diff --git a/.dockerignore b/.dockerignore index c653757958..b376dc3782 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,6 +7,7 @@ !hack !docs !test +!e2e-test !ui !tools !images diff --git a/.github/.licenserc.yaml b/.github/.licenserc.yaml new file mode 100644 index 0000000000..9bfe749103 --- /dev/null +++ b/.github/.licenserc.yaml @@ -0,0 +1,84 @@ +header: + license: + spdx-id: Apache-2.0 + copyright-owner: Chaos Mesh Authors. + paths-ignore: + - '.gitignore' + - '.gitkeep' + - '.dockerignore' + - '.editorconfig' + - '.lift.toml' + - '.muse.toml' + - '.devcontainer' + - .prettierrc + - '**/*.md' + - '**/*.json' + - '**/*.log' + - 'vendor/**' + - '**/go.mod' + - '**/go.sum' + - '**/go.work' + - '**/go.work.sum' + - '**/*.crt' + - '**/*.key' + - '**/*.ext' + - '**/*.csr' + - '.github/**' + - 'Makefile' + - '*.mk' + - 'PROJECT' + - 'LICENSE' + # build cache in dev-env + - '.cache' + # reported as unsupported by skywalking-eyes as of October 4th 2021 + - 'helm/chaos-mesh/.helmignore' + - 'helm/chaos-mesh/templates/*.tpl' + - 'pkg/chaosdaemon/pb/chaosdaemon.proto' + - 'pkg/chaoskernel/pb/bpfki.proto' + - 'test/integration_test/utils/check_contains' + # skip auto-generated files + - 'manifests/**' + - 'helm/chaos-mesh/crds/*' + - 'config/**' + - '**/*_gen.go' + - '**/*_generated*' + - '**/schema.resolvers.go' + - '**/generated.go' + - 'pkg/dashboard/swaggerdocs/swagger.yaml' + - 'pkg/dashboard/swaggerdocs/docs.go' + - 'pkg/ctrlserver/graph/model/models_gen.go' + - 'pkg/ctrlserver/graph/generated/generated.go' + - 'pkg/ctrlserver/graph/schema.resolvers.go' + - 'pkg/chaosdaemon/pb/chaosdaemon.pb.go' + - 'pkg/chaoskernel/pb/bpfki.pb.go' + - 'pkg/time/fakeclock/.embed.o' + # k8s copyright + - 'hack/boilerplate/boilerplate.py' + # Dockerfiles + - '**/Dockerfile' + # UI + - 'ui/pnpm-workspace.yaml' + - 'ui/pnpm-lock.yaml' + - 'ui/.husky/**' + - 'ui/.prettierignore' + - 'ui/.prettierrc' + - 'ui/app/public/index.html' + - 'ui/app/src/api/zz_generated.frontend.chaos-mesh.ts' + - 'ui/app/src/formik/**' + - 'ui/app/src/openapi/**' + - 'ui/app/src/setupProxy.js' + - 'ui/**/*.svg' + - '**/node_modules/**' + - '**/__mocks__/**' + - '**/__snapshots__/**' + - 'ui/app/build/**/*' + - 'ui/packages/mui-extends/esm/**/*' + - 'ui/packages/mui-extends/.storybook/**' + - 'ui/packages/mui-extends/stories/**' + - 'ui/packages/mui-extends/test/storyshots.test.js' + # codecov configuration file + - 'codecov.yml' + # OWNERS + - 'OWNERS' + - 'OWNERS_ALIASES' + - '.well-known/funding-manifest-urls' diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md deleted file mode 100644 index ef48e27b22..0000000000 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -name: "\U0001F41B Bug Report" -about: Something isn't working as expected - ---- - -## Bug Report - -**What version of Kubernetes are you using?** - - -**What version of Chaos Mesh are you using?** - - -**What did you do?** - - -**What did you expect to see?** - -**What did you see instead?** - -**Output of chaosctl** - - diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 0000000000..3ade358370 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,39 @@ +name: Bug Report +description: Something does not work as expected, and I could provide a minimal reproducible example. +title: "[Bug]: " +labels: + - type/bug +assignees: + - g1eny0ung + - STRRL +body: + - type: input + id: chaos-mesh-version + attributes: + label: Chaos Mesh Version + description: What version of Chaos Mesh are you using? + placeholder: v2.x.x or master + validations: + required: true + - type: input + id: k8s-version + attributes: + label: Kubernetes Version + description: What version of Kubernetes are you using? + placeholder: v1.x.x + validations: + required: true + - type: textarea + id: bug + attributes: + label: Describe the bug + description: A clear and concise description of what the bug is. + validations: + required: true + - type: textarea + id: reproduce + attributes: + label: To Reproduce + description: Steps to reproduce the behavior. + placeholder: | + You can also include screenshots or any other relevant information here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..d5c024d209 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: +- name: 🤔 Ask a question + url: https://github.com/chaos-mesh/chaos-mesh/discussions/new?category=q-a + about: Chaos Mesh does not work as expected? Or not sure about how to use Chaos Mesh? Ask a question here! diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md deleted file mode 100644 index cb6e994f6d..0000000000 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: "\U0001F680 Feature Request" -about: I have a suggestion - ---- - -## Feature Request - -**Is your feature request related to a problem? Please describe:** - - -**Describe the feature you'd like:** - - -**Describe alternatives you've considered:** - - -**Teachability, Documentation, Adoption, Migration Strategy:** - diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml new file mode 100644 index 0000000000..2e5b7a8e68 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -0,0 +1,36 @@ +name: Feature Request +description: Suggest an idea for this project +title: '[Feature]: ' +labels: + - feature/new +assignees: + - g1eny0ung + - STRRL +body: + - type: markdown + attributes: + value: | + > [!TIP] + > Thanks for suggesting a feature! Please fill out the sections below to help us understand your request better. + > + > If you have a question or need help, please open a discussion instead. + - type: textarea + id: feature + attributes: + label: Feature request + description: Please describe the feature you'd like to see added to the project. + placeholder: I'd like to see [...] + validations: + required: true + - type: textarea + id: solution + attributes: + label: Proposed solution + description: Please describe a possible solution to the feature request. + placeholder: I think we could [...] + - type: textarea + id: context + attributes: + label: Additional context + description: Add any other context or screenshots about the feature request here. + placeholder: I have an idea [...] diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index 614b7ab7aa..0000000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: "\U0001F914 Question" -about: Usage question that isn't answered in docs or discussion - ---- - -## Question - -Before asking a question, make sure you have: - -- Reviewed relevant Kubernetes information: Google your error messages and look at K8s docs. -- Searched open and closed [GitHub issues](https://github.com/chaos-mesh/chaos-mesh/issues?utf8=%E2%9C%93&q=is%3Aissue) -- Read the documentation: - - [Chaos Mesh Readme](https://github.com/chaos-mesh/chaos-mesh) - - [Chaos Mesh Doc](https://chaos-mesh.org/docs) - -**Output of chaosctl** - - diff --git a/.github/checklink_config.json b/.github/checklink_config.json new file mode 100644 index 0000000000..96ddeef917 --- /dev/null +++ b/.github/checklink_config.json @@ -0,0 +1,8 @@ +{ + "ignorePatterns": [ + { + "pattern": "^http://localhost" + } + ], + "aliveStatusCodes": [200, 403, 500, 502, 503] +} diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000000..4b50730071 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,142 @@ +CI/CD: + - changed-files: + - any-glob-to-any-file: + - ".github/workflows/**" + +rebuild-build-env-image: + - changed-files: + - any-glob-to-any-file: + - "images/build-env/Dockerfile" +rebuild-dev-env-image: + - changed-files: + - any-glob-to-any-file: + - "images/dev-env/Dockerfile" + +components/tests: + - changed-files: + - any-glob-to-all-files: + - "test/**" + - "*_test.go" + - "*.test.(js|ts|tsx)" +component/daemon: + - changed-files: + - any-glob-to-any-file: + - "cmd/chaosdaemon/**" + - "pkg/chaosdaemon/**" + - "chaos-daemon-*.yaml" +component/helm: + - changed-files: + - any-glob-to-any-file: + - "helm/**" +component/operator: + - changed-files: + - any-glob-to-any-file: + - "cmd/chaos-controller-manager/**" + - "controllers/**" + - "controller-manager-*.yaml" +component/scripts: + - changed-files: + - any-glob-to-any-file: + - "hack/**" + - "install.sh" +component/ui: + - changed-files: + - any-glob-to-any-file: + - "ui/**" +component/workflow: + - changed-files: + - any-glob-to-any-file: + - "pkg/workflow/**" +component/chaosctl: + - changed-files: + - any-glob-to-any-file: + - "cmd/chaosctl/**" + - "pkg/chaosctl/**" +component/e2e: + - changed-files: + - any-glob-to-any-file: + - "e2e-test/**" +component/dashboard: + - changed-files: + - any-glob-to-any-file: + - "cmd/chaos-dashboard/**" + - "pkg/dashboard/**" + - "chaos-dashboard-*.yaml" + +chaos/gcp: + - changed-files: + - any-glob-to-any-file: + - "gcpchaos_*.go" + - "controllers/chaosimpl/gcpchaos/**" +chaos/dns: + - changed-files: + - any-glob-to-any-file: + - "dnschaos_*.go" + - "controllers/chaosimpl/dnschaos/**" +chaos/kernel: + - changed-files: + - any-glob-to-any-file: + - "kernelchaos_*.go" + - "controllers/chaosimpl/kernelchaos/**" +chaos/jvm: + - changed-files: + - any-glob-to-any-file: + - "jvmchaos_*.go" + - "controllers/chaosimpl/jvmchaos/**" +chaos/network: + - changed-files: + - any-glob-to-any-file: + - "networkchaos_*.go" + - "controllers/chaosimpl/networkchaos/**" + - "podnetworkchaos_*.go" + - "controllers/podnetworkchaos/**" +chaos/io: + - changed-files: + - any-glob-to-any-file: + - "iochaos_*.go" + - "controllers/chaosimpl/iochaos/**" + - "podiochaos_*.go" + - "controllers/podiochaos/**" +chaos/stress: + - changed-files: + - any-glob-to-any-file: + - "stresschaos_*.go" + - "controllers/chaosimpl/stresschaos/**" +chaos/time: + - changed-files: + - any-glob-to-any-file: + - "timechaos_*.go" + - "controllers/chaosimpl/timechaos/**" + - "pkg/time/**" +chaos/pod: + - changed-files: + - any-glob-to-any-file: + - "podchaos_*.go" + - "controllers/chaosimpl/podchaos/**" +chaos/aws: + - changed-files: + - any-glob-to-any-file: + - "awschaos_*.go" + - "controllers/chaosimpl/awschaos/**" +chaos/http: + - changed-files: + - any-glob-to-any-file: + - "httpchaos_*.go" + - "controllers/chaosimpl/httpchaos/**" + - "podhttpchaos_*.go" + - "controllers/podhttpchaos/**" +chaos/physical-machine: + - changed-files: + - any-glob-to-any-file: + - "physicalmachinechaos_*.go" + - "controllers/chaosimpl/physicalmachinechaos/**" +chaos/azure: + - changed-files: + - any-glob-to-any-file: + - "azurechaos_*.go" + - "controllers/chaosimpl/azurechaos/**" +chaos/block: + - changed-files: + - any-glob-to-any-file: + - "blockchaos_*.go" + - "controllers/chaosimpl/blockchaos/**" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ea29f9cd7f..f399152604 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,35 +1,64 @@ -### What problem does this PR solve? - +> [!IMPORTANT] +> Thank you for contributing to Chaos Mesh! Please fill out the template below to help us review your PR. +> +> If you are new to Chaos Mesh, please read the [contributing guide](https://github.com/chaos-mesh/chaos-mesh/blob/master/CONTRIBUTING.md) first. +> +> Please follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) when writing the PR title and commit messages. -### What is changed and how does it work? +## What problem does this PR solve? -### Checklist - +> [!TIP] +> Please replace this with a brief description of the problem this PR solves. +> You can also close #issue_number if this PR solves the issue. -Tests - +## What's changed and how it works? + +> [!TIP] +> Please replace this with a brief description of the changes and how it works. +> You can also refer to a proposal or design doc if it exists. + +## Related changes + +- [ ] This change also requires further updates to the [website](https://github.com/chaos-mesh/website) (e.g. docs) +- [ ] This change also requires further updates to the `UI interface` + +## Cherry-pick to release branches (optional) + +> This PR should be cherry-picked to the following release branches: + +- [ ] release-2.7 +- [ ] release-2.6 + +## Checklist + +### CHANGELOG + +> Must include at least one of them. + +- [ ] I have updated the `CHANGELOG.md` +- [ ] I have labeled this PR with "no-need-update-changelog" + +### Tests + +> Must include at least one of them. - [ ] Unit test - [ ] E2E test -- [ ] Manual test (add detailed scripts or steps below) -- [ ] No code - -Side effects +- [ ] Manual test -- [ ] Breaking backward compatibility +### Side effects -Related changes +- [ ] **Breaking backward compatibility** -- [ ] Need to update the documentation +## DCO -### Does this PR introduce a user-facing change? - +> [!TIP] +> Depends on actual situations, for example, if the failed commit isn't the most recent +> one, you can use `git rebase -i HEAD~n` to re-signoff the commit. -```release-note -NONE +```shell +git commit --amend --signoff +git push --force ``` diff --git a/.github/workflows/checklink.yaml b/.github/workflows/checklink.yaml index 0b4a8bdac2..13431c0e1e 100644 --- a/.github/workflows/checklink.yaml +++ b/.github/workflows/checklink.yaml @@ -1,16 +1,22 @@ name: Check Markdown links on: - push: + pull_request: branches: - master + paths: + - "**.md" + - ".github/checklink_config.json" + +permissions: read-all jobs: markdown-link-check: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@master - - uses: gaurav-nelson/github-action-markdown-link-check@v1 - with: - use-quiet-mode: 'yes' - config-file: '.github/workflows/checklink_config.json' + - uses: actions/checkout@v4 + - uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-quiet-mode: "yes" + check-modified-files-only: 'yes' + config-file: ".github/checklink_config.json" diff --git a/.github/workflows/checklink_config.json b/.github/workflows/checklink_config.json deleted file mode 100644 index 84cc222419..0000000000 --- a/.github/workflows/checklink_config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "ignorePatterns": [ - { - "pattern": ["^/img/"] - }, - { - "pattern": ["^http://localhost"] - }, - { - "pattern": ["^https://github.com"] - } - ] -} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d004957893..85e7622459 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,3 +1,15 @@ +# This workflow defines the go and ui related jobs. +# +# First, we use [dorny/paths-filter@v3](https://github.com/dorny/paths-filter) to +# detect changes in go and ui related files, and then run the corresponding sub-jobs +# based on the changes. +# +# Please note that due to the GitHub required checks, the `go` and `ui` jobs +# also need to run to report the status. So here we need to define an additional +# "skip" file to ensure that the status is reported. For details, please refer to: +# +# - `ci_skip.yml` +# - https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks name: ci on: @@ -6,63 +18,129 @@ on: - master - release-* -jobs: +permissions: read-all - pull: - runs-on: ubuntu-latest +jobs: + # JOB to run change detection + changes: + runs-on: ubuntu-20.04 + # Set job outputs to values from filter step + outputs: + go: ${{ steps.filter.outputs.go }} + ui: ${{ steps.filter.outputs.ui }} + steps: + # For pull requests it's not necessary to checkout the code + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + go: + - Makefile + - go.* + - '**.go' + - 'helm/**' + ui: + - 'ui/pnpm-lock.yaml' + - '**.js' + - '**.ts?(x)' + go: + needs: changes + if: ${{ needs.changes.outputs.go == 'true' }} strategy: fail-fast: false matrix: + arch: [amd64, arm64] job: - verify - build - test + runs-on: ${{ fromJson('{"amd64":"ubuntu-20.04", "arm64":["self-hosted", "Linux", "ARM64"]}')[matrix.arch] }} steps: - - name: Set up Go 1.15 - uses: actions/setup-go@v1 - with: - go-version: 1.15.11 - id: go + - uses: actions/checkout@v4 - - name: Check out code into the Go module directory - uses: actions/checkout@v2 - with: - ref: ${{ github.event.pull_request.head.sha }} - path: go/src/github.com/${{ github.repository }} + - name: Build Chaos Mesh Build Env + env: + IMAGE_BUILD_ENV_BUILD: ${{ contains(github.event.pull_request.labels.*.name, 'rebuild-build-env-image') }} + run: | + if [ "${IMAGE_BUILD_ENV_BUILD}" = "true" ] ; then + export IMAGE_BUILD_ENV_BUILD=1; + else + export IMAGE_BUILD_ENV_BUILD=0; + fi - - name: Setup Helm - uses: azure/setup-helm@v1 - with: - version: v3.3.0 + make image-build-env - - name: ${{ matrix.job }} + - name: Build Chaos Mesh Dev Env + env: + IMAGE_DEV_ENV_BUILD: ${{ contains(github.event.pull_request.labels.*.name, 'rebuild-dev-env-image') }} run: | - # workaround for https://github.com/actions/setup-go/issues/14 - export GOPATH=${GITHUB_WORKSPACE}/go - export PATH=$PATH:$GOPATH/bin - make ensure-kubebuilder || echo 0 - make ensure-kustomize || echo 0 - - # preload go modules before goimports - go mod download -x + if [ "${IMAGE_DEV_ENV_BUILD}" = "true" ] ; then + export IMAGE_DEV_ENV_BUILD=1; + else + export IMAGE_DEV_ENV_BUILD=0; + fi - make groupimports || echo 0 - #use sh function + make image-dev-env + - name: ${{ matrix.job }} + env: + job: ${{ matrix.job }} + run: | if [[ "$job" == "verify" ]]; then make check - echo "Please make check before creating a PR" - git diff --quiet -- . || (git diff | cat && false) - make check-install-script + echo "Please run [make check] before creating a PR" + git diff --quiet elif [[ "$job" == "build" ]]; then make image elif [[ "$job" == "test" ]]; then - ROOT=$(pwd) - KUBEBUILDER_ASSETS=${ROOT}/output/bin/kubebuilder/bin make test - BUILD_NUMBER=${BUILD_NUMBER} CODECOV_TOKEN="${CODECOV_TOKEN}" CI=1 make coverage + make test else make $job fi - working-directory: ${{ github.workspace }}/go/src/github.com/${{ github.repository }} - env: - job: ${{ matrix.job }} + + - name: Upload Code Coverage + uses: codecov/codecov-action@v3 + if: matrix.job == 'test' + with: + files: ./cover.out + ui: + needs: changes + if: ${{ needs.changes.outputs.ui == 'true' }} + defaults: + run: + working-directory: ./ui + strategy: + matrix: + job: + - build + - test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v2 + with: + version: 9 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + cache-dependency-path: "ui/pnpm-lock.yaml" + + - run: pnpm install --frozen-lockfile + + - name: Cache app/build + if: ${{ matrix.job == 'build' }} + uses: actions/cache@v2 + with: + path: ./ui/app/build + key: ${{ runner.os }}-pnpm-${{ hashFiles('ui/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- + + - name: Build app + if: ${{ matrix.job == 'build' }} + run: pnpm build + + - name: Run tests + if: ${{ matrix.job == 'test' }} + run: pnpm test diff --git a/.github/workflows/ci_skip.yml b/.github/workflows/ci_skip.yml new file mode 100644 index 0000000000..44e76b326a --- /dev/null +++ b/.github/workflows/ci_skip.yml @@ -0,0 +1,56 @@ +# Please refer to the file comments in `ci.yml` for more information. +name: ci + +on: + pull_request: + branches: + - master + - release-* + +permissions: read-all + +jobs: + skip-changes: + runs-on: ubuntu-20.04 + outputs: + go: ${{ steps.filter.outputs.go }} + ui: ${{ steps.filter.outputs.ui }} + steps: + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + go: + - Makefile + - go.* + - '**.go' + - 'helm/**' + ui: + - 'ui/pnpm-lock.yaml' + - '**.js' + - '**.ts?(x)' + go: + needs: skip-changes + if: ${{ needs.skip-changes.outputs.go != 'true' }} + strategy: + matrix: + arch: [amd64, arm64] + job: + - verify + - build + - test + runs-on: ubuntu-20.04 + steps: + - run: echo "Not required to run go jobs." + ui: + needs: skip-changes + if: ${{ needs.skip-changes.outputs.ui != 'true' }} + strategy: + matrix: + job: + - verify + - build + - test + runs-on: ubuntu-20.04 + steps: + - run: echo "Not required to run ui jobs." diff --git a/.github/workflows/codecov_unittest.yaml b/.github/workflows/codecov_unittest.yaml new file mode 100644 index 0000000000..7d74e67141 --- /dev/null +++ b/.github/workflows/codecov_unittest.yaml @@ -0,0 +1,28 @@ +name: Unit Test And Code Coverage + +on: + push: + paths: + - Makefile + - go.* + - "**.go" + +permissions: read-all + +jobs: + unitTestAndCodeCoverage: + runs-on: ubuntu-latest + name: Unit Test And Code Coverage + steps: + - uses: actions/checkout@v4 + + - name: Unit Test + run: make test + + - name: Upload Code Coverage + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./cover.out + verbose: true + fail_ci_if_error: true diff --git a/.github/workflows/e2e_test.yml b/.github/workflows/e2e_test.yml new file mode 100644 index 0000000000..cec241583d --- /dev/null +++ b/.github/workflows/e2e_test.yml @@ -0,0 +1,247 @@ +# This workflow defines the e2e test related jobs. +name: E2E Test + +on: + workflow_dispatch: {} + pull_request: + branches: + - master + - release-* + +permissions: read-all + +jobs: + changed-files: + runs-on: ubuntu-20.04 + outputs: + only_changed: ${{ steps.filter.outputs.only_changed }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 2 + - name: Get changed files + uses: tj-actions/changed-files@v41 + id: filter + with: + # Not available for frontend code for now. + files: | + .gitignore + **.md + .github/ISSUE_TEMPLATE/* + .github/pull_request_template.md + ui/** + .github/workflows/checklink.yaml + .github/checklink_config.json + .github/workflows/ci.yml + .github/workflows/ci_skip.yml + .github/workflows/codecov_unittest.yaml + .github/workflows/integration_test.yml + .github/workflows/license_checker.yml + .github/workflows/must_update_changelog.yml + .github/workflows/release_helm_chart.yml + .github/workflows/upload_env_image.yml + .github/workflows/upload_image.yml + .github/workflows/upload_image_pr.yml + .github/workflows/upload_latest_files.yml + .github/workflows/upload_release_files.yml + - name: Show outputs + run: echo "${{ toJSON(steps.filter.outputs) }}" + + build-image: + needs: changed-files + if: needs.changed-files.outputs.only_changed == 'false' + runs-on: ubuntu-20.04 + steps: + - name: checkout codes + uses: actions/checkout@v4 + - name: Build Chaos Mesh Build Env + if: ${{ github.event.pull_request }} + env: + IMAGE_BUILD_ENV_BUILD: ${{ contains(github.event.pull_request.labels.*.name, 'rebuild-build-env-image') }} + run: | + if [ "${IMAGE_BUILD_ENV_BUILD}" = "true" ] ; then + export IMAGE_BUILD_ENV_BUILD=1; + else + export IMAGE_BUILD_ENV_BUILD=0; + fi + make image-build-env + - name: Build Chaos Mesh Dev Env + if: ${{ github.event.pull_request }} + env: + IMAGE_DEV_ENV_BUILD: ${{ contains(github.event.pull_request.labels.*.name, 'rebuild-dev-env-image') }} + run: | + if [ "${IMAGE_DEV_ENV_BUILD}" = "true" ] ; then + export IMAGE_DEV_ENV_BUILD=1; + else + export IMAGE_DEV_ENV_BUILD=0; + fi + make image-dev-env + # once the https://github.com/actions/cache/pull/498 gets merged, + # we can switch to the official cache action + - name: Restore build cache + id: cache + uses: martijnhols/actions-cache/restore@main + with: + path: cache + # don't worry about the branch, the github cache + # is only accessible in the same branch (or a pull_request + # whose target is the branch) + key: e2e-image-build-cache-${{ runner.os }} + + - name: Build e2e images + env: + DOCKER_CACHE: 1 + DOCKER_CACHE_DIR: ${{ github.workspace }}/cache + GO_BUILD_CACHE: ${{ github.workspace }}/cache + DOCKER_CLI_EXPERIMENTAL: enabled + run: | + docker buildx create --use --name chaos-mesh-builder + make -j4 image e2e-image + + - name: save docker images + run: | + mkdir -p ./output/saved-images + docker image save ghcr.io/chaos-mesh/chaos-dashboard:latest > ./output/saved-images/chaos-dashboard.tgz + docker image save ghcr.io/chaos-mesh/chaos-daemon:latest > ./output/saved-images/chaos-daemon.tgz + docker image save ghcr.io/chaos-mesh/chaos-mesh:latest > ./output/saved-images/chaos-mesh.tgz + docker image save ghcr.io/chaos-mesh/e2e-helper:latest > ./output/saved-images/e2e-helper.tgz + + - name: upload saved images + uses: actions/upload-artifact@v4 + with: + name: saved-images + path: ./output/saved-images + retention-days: 7 + + build-e2e-binary: + needs: changed-files + if: needs.changed-files.outputs.only_changed == 'false' + runs-on: ubuntu-20.04 + steps: + - name: checkout codes + uses: actions/checkout@v4 + - name: Restore build cache + id: cache + uses: martijnhols/actions-cache/restore@main + with: + path: cache + key: e2e-binary-build-cache-${{ runner.os }} + - name: build e2e binary + env: + DOCKER_CACHE: 1 + DOCKER_CACHE_DIR: ${{ github.workspace }}/cache + GO_BUILD_CACHE: ${{ github.workspace }}/cache + run: | + make e2e-build + - name: upload e2e binary + uses: actions/upload-artifact@v4 + with: + name: e2e-binary + path: ./e2e-test/image/e2e/bin + retention-days: 7 + + e2e-test-matrix: + needs: + - build-image + - build-e2e-binary + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + kubernetes-version: + - v1.26.13 + - v1.27.10 + - v1.28.6 + focus: + - "[Graceful-Shutdown] [IOChaos]" + - "[Graceful-Shutdown] [HTTPChaos]" + - "[Basic] [PodChaos]" + - "[Basic] [TimeChaos]" + - "[Basic] [IOChaos]" + - "[Basic] [HTTPChaos]" + - "[Basic] [Sidecar Config]" + - "[Basic] [NetworkChaos]" + - "[Basic] [DNSChaos]" + - "[Basic] [StressChaos]" + steps: + - name: checkout codes + uses: actions/checkout@v4 + - name: download saved images + uses: actions/download-artifact@v4 + with: + name: saved-images + path: ./output/saved-images + - name: download e2e binary + uses: actions/download-artifact@v4 + with: + name: e2e-binary + path: ./output/e2e-binary + - name: move e2e binary + run: | + mkdir -p ./e2e-test/image/e2e/bin + mv ./output/e2e-binary/ginkgo ./e2e-test/image/e2e/bin/ginkgo + mv ./output/e2e-binary/e2e.test ./e2e-test/image/e2e/bin/e2e.test + chmod +x ./e2e-test/image/e2e/bin/ginkgo + chmod +x ./e2e-test/image/e2e/bin/e2e.test + + - name: Setup minikube + uses: medyagh/setup-minikube@latest + with: + minikube-version: 1.32.0 + kubernetes-version: ${{ matrix.kubernetes-version }} + + - name: load image into minikube + run: | + minikube image load ./output/saved-images/chaos-dashboard.tgz + minikube image load ./output/saved-images/chaos-daemon.tgz + minikube image load ./output/saved-images/chaos-mesh.tgz + minikube image load ./output/saved-images/e2e-helper.tgz + + - name: Restrict access to kubeconfig # https://github.com/helm/helm/issues/9115 + run: chmod 600 ~/.kube/config + + - name: Setup Helm + uses: azure/setup-helm@v3 + + - name: Install Chaos Mesh + # Set DOCKER_API_VERSION to 1.41 to bypass https://github.com/chaos-mesh/chaos-mesh/pull/4154#issuecomment-1704442551. + run: | + helm install --wait --create-namespace chaos-mesh helm/chaos-mesh --namespace=chaos-mesh --set images.tag=latest --set chaosDaemon.env.DOCKER_API_VERSION=1.41 + - name: e2e tests + env: + FOCUS: ${{ matrix.focus }} + run: | + # because ginkgo -focus accepts the regex expression, we should use escape to represent the squared brackets and dash + export ESCAPED_FOCUS=$(echo $FOCUS | sed -e 's/\[/\\\[/g' | sed -e 's/\]/\\\]/g' | sed -e 's/\-/\\\-/g') + KUBECONFIG=~/.kube/config ./e2e-test/image/e2e/bin/ginkgo -focus="${ESCAPED_FOCUS}" ./e2e-test/image/e2e/bin/e2e.test -- --e2e-image ghcr.io/chaos-mesh/e2e-helper:latest + - name: post run - extract profile info from kubernetes + if: always() + env: + PROFILE_DIRECTORY: ./output/chaos-mesh-profile + run: | + kubectl cluster-info dump --all-namespaces --output-directory $PROFILE_DIRECTORY/manifests -o yaml + kubectl get endpoints -A -o yaml > $PROFILE_DIRECTORY/manifests/endpoints.yaml + kubectl get secrets -A -o yaml > $PROFILE_DIRECTORY/manifests/secrets.yaml + kubectl get configmaps -A -o yaml > $PROFILE_DIRECTORY/manifests/configmaps.yaml + - name: post run - upload Chaos Mesh profile info + if: always() + uses: actions/upload-artifact@v4 + with: + name: profiling-${{ matrix.focus }}-k8s-${{ matrix.kubernetes-version }} + path: ./output/chaos-mesh-profile + retention-days: 7 + - name: post run - upload junit test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-junit-reports-${{ matrix.focus }}-k8s-${{ matrix.kubernetes-version }} + path: "**/*.xml" + retention-days: 7 + + pass: + needs: + - e2e-test-matrix + name: E2E Test Passed + runs-on: ubuntu-20.04 + steps: + - run: echo "🎉 E2E Test Passed!" diff --git a/.github/workflows/e2e_test_upload_cache.yml b/.github/workflows/e2e_test_upload_cache.yml new file mode 100644 index 0000000000..9a32eac74c --- /dev/null +++ b/.github/workflows/e2e_test_upload_cache.yml @@ -0,0 +1,68 @@ +name: E2E Test Upload Cache + +on: + workflow_dispatch: {} + push: + branches: + - master + - release-* + paths-ignore: + - .gitignore + - "**.md" + # Not available for frontend code for now. + - "ui/**" + - .github/workflows/checklink.yaml + - .github/checklink_config.json + - .github/workflows/ci.yml + - .github/workflows/ci_skip.yml + - .github/workflows/codecov_unittest.yaml + - .github/workflows/integration_test.yml + - .github/workflows/license_checker.yml + - .github/workflows/must_update_changelog.yml + - .github/workflows/release_helm_chart.yml + - .github/workflows/upload_env_image.yml + - .github/workflows/upload_image.yml + - .github/workflows/upload_image_pr.yml + - .github/workflows/upload_latest_files.yml + - .github/workflows/upload_release_files.yml + +permissions: read-all + +jobs: + build-image: + runs-on: ubuntu-20.04 + steps: + - name: checkout codes + uses: actions/checkout@v4 + - name: build e2e images + env: + DOCKER_CACHE: 1 + DOCKER_CACHE_DIR: ${{github.workspace}}/cache + GO_BUILD_CACHE: ${{github.workspace}}/cache + DOCKER_CLI_EXPERIMENTAL: enabled + run: | + docker buildx create --use --name chaos-mesh-builder + make -j4 image e2e-image + - name: upload build cache + uses: martijnhols/actions-cache/save@main + with: + path: cache + key: e2e-image-build-cache-${{ runner.os }} + + build-e2e-binary: + runs-on: ubuntu-20.04 + steps: + - name: checkout codes + uses: actions/checkout@v4 + - name: build e2e binary + env: + DOCKER_CACHE: 1 + DOCKER_CACHE_DIR: ${{github.workspace}}/cache + GO_BUILD_CACHE: ${{github.workspace}}/cache + run: | + make e2e-build + - name: upload build cache + uses: martijnhols/actions-cache/save@main + with: + path: cache + key: e2e-binary-build-cache-${{ runner.os }} diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index b7c014fe79..6620b4a2f2 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -1,42 +1,131 @@ name: Integration Test + on: - push: - branches: - - master pull_request: branches: - master + paths-ignore: + - .gitignore + - "**.md" + - .github/ISSUE_TEMPLATE/* + - .github/pull_request_template.md + # Not available for frontend code for now. + - "ui/**" + - .github/workflows/checklink.yaml + - .github/checklink_config.json + - .github/workflows/ci.yml + - .github/workflows/ci_skip.yml + - .github/workflows/codecov_unittest.yaml + - .github/workflows/e2e_test.yml + - .github/workflows/e2e_test_upload_cache.yml + - .github/workflows/license_checker.yml + - .github/workflows/must_update_changelog.yml + - .github/workflows/release_helm_chart.yml + - .github/workflows/upload_env_image.yml + - .github/workflows/upload_image.yml + - .github/workflows/upload_image_pr.yml + - .github/workflows/upload_latest_files.yml + - .github/workflows/upload_release_files.yml + +permissions: read-all jobs: run: name: Integration Test - runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + arch: [amd64, arm64] + runs-on: ${{ fromJson('{"amd64":"ubuntu-20.04", "arm64":["self-hosted", "Linux", "ARM64"]}')[matrix.arch] }} steps: - - uses: actions/checkout@master + - uses: actions/checkout@v4 with: # Must use at least depth 2! fetch-depth: 2 - name: Create kind cluster - uses: helm/kind-action@v1.0.0-rc.1 + # released version of kind-action doesn't support arm64 + uses: helm/kind-action@4c7909140acfc81a05fc96fed8fea6673ba8ce80 + with: + kubectl_version: v1.23.1 + + - name: Restrict access to kubeconfig # https://github.com/helm/helm/issues/9115 + run: chmod 600 ~/.kube/config + + - name: Setup Helm + uses: azure/setup-helm@v3 + + - name: Magic Kind DNS Fix + if: ${{ matrix.arch == 'arm64' }} + run: | + docker exec chart-testing-control-plane /bin/bash -c "sed -e 's/nameserver \(.*\)/nameserver 8.8.8.8/g' /etc/resolv.conf > /etc/resolv.conf.sed" + docker exec chart-testing-control-plane /bin/bash -c "cp /etc/resolv.conf.sed /etc/resolv.conf" + + kubectl rollout restart deployment -n kube-system coredns + + - uses: actions/setup-python@v2 + if: ${{ matrix.arch != 'arm64' }} # We can assume the self-hosted arm64 has a functional python + + - uses: actions/setup-go@v4 + with: + check-latest: true + go-version-file: "go.mod" + - name: Build Chaos Mesh Build Env + if: ${{ github.event.pull_request }} + env: + IMAGE_BUILD_ENV_BUILD: ${{ contains(github.event.pull_request.labels.*.name, 'rebuild-build-env-image') }} + run: | + if [ "${IMAGE_BUILD_ENV_BUILD}" = "true" ] ; then + export IMAGE_BUILD_ENV_BUILD=1; + else + export IMAGE_BUILD_ENV_BUILD=0; + fi + + make image-build-env + + - name: Build Chaos Mesh Dev Env + if: ${{ github.event.pull_request }} + env: + IMAGE_DEV_ENV_BUILD: ${{ contains(github.event.pull_request.labels.*.name, 'rebuild-dev-env-image') }} + run: | + if [ "${IMAGE_DEV_ENV_BUILD}" = "true" ] ; then + export IMAGE_DEV_ENV_BUILD=1; + else + export IMAGE_DEV_ENV_BUILD=0; + fi + + make image-dev-env - name: Install Chaos Mesh run: | export CLUSTER="chart-testing" hack/local-up-chaos-mesh.sh - kubectl set env deployment/chaos-dashboard SECURITY_MODE=true -n chaos-testing - kubectl set env deployment/chaos-controller-manager SECURITY_MODE=true -n chaos-testing + kubectl set env deployment/chaos-dashboard SECURITY_MODE=true -n chaos-mesh + kubectl set env deployment/chaos-controller-manager SECURITY_MODE=true -n chaos-mesh sleep 5 - kubectl port-forward -n chaos-testing svc/chaos-dashboard 2333:2333 & - - name: Make chaosctl + kubectl port-forward -n chaos-mesh svc/chaos-dashboard 2333:2333 & + - name: Build chaosctl run: | make chaosctl - name: Install localstack && aws client run: | helm repo add localstack-repo http://helm.localstack.cloud - helm upgrade --install localstack localstack-repo/localstack --version 0.1.2 + helm upgrade --install localstack localstack-repo/localstack --version 0.6.14 pip install awscli + kubectl wait --timeout=60s --for=condition=ready --all pod - name: Run integration test run: | bash test/integration_test/run.sh + + - name: post run - dump kubernetes cluster info + if: always() + run: | + kubectl cluster-info dump --all-namespaces --output-directory cluster-info-dump + - name: post run - upload kubernetes cluster info dump + if: always() + uses: actions/upload-artifact@v4 + with: + name: integration-test-kubernetes-cluster-info-dump-${{ matrix.arch }} + path: cluster-info-dump + retention-days: 7 diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000000..52474c6a6c --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,12 @@ +name: "Pull Request Labeler" +on: + - pull_request_target + +jobs: + labeler: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v5 diff --git a/.github/workflows/license_checker.yml b/.github/workflows/license_checker.yml new file mode 100644 index 0000000000..00c40f3c86 --- /dev/null +++ b/.github/workflows/license_checker.yml @@ -0,0 +1,21 @@ +name: License checker + +on: + pull_request: + branches: + - master + +permissions: read-all + +jobs: + check-license: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + - name: Check License Header + uses: apache/skywalking-eyes@v0.4.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + log: info + config: .github/.licenserc.yaml diff --git a/.github/workflows/merge_conflict_finder.yaml b/.github/workflows/merge_conflict_finder.yaml new file mode 100644 index 0000000000..3415c729ec --- /dev/null +++ b/.github/workflows/merge_conflict_finder.yaml @@ -0,0 +1,24 @@ +name: Merge Conflict Finder + +on: + push: + branches: + - master + - release-* + pull_request: + branches: + - master + - release-* + +permissions: read-all + +jobs: + merge_conflict_job: + runs-on: ubuntu-latest + name: Find merge conflicts + steps: + # Checkout the source code so there are some files to look at. + - uses: actions/checkout@v4 + # Run the actual merge conflict finder + - name: Merge Conflict finder + uses: olivernybroe/action-conflict-finder@v4.0 diff --git a/.github/workflows/must_update_changelog.yml b/.github/workflows/must_update_changelog.yml new file mode 100644 index 0000000000..57fc58e7dd --- /dev/null +++ b/.github/workflows/must_update_changelog.yml @@ -0,0 +1,49 @@ +# This workflow would make sure that there are some changes on CHANGELOG.md or +# the label "no-need-update-changelog" is tagged on the PR. + +name: "Must Update CHANGELOG" + +on: + pull_request: + types: + - opened + - synchronize + - reopened + - labeled + - unlabeled + branches: + - master + - release-* + +permissions: read-all + +jobs: + must-update-changelog: + name: "Must Update CHANGELOG" + runs-on: "ubuntu-20.04" + env: + LABEL_EXISTS: ${{ contains(github.event.pull_request.labels.*.name, 'no-need-update-changelog') }} + steps: + - name: "Skip if label exists" + if: env.LABEL_EXISTS == 'true' + run: | + echo "no-need-update-changelog exists, skipping this check" + - name: "Collect changes" + id: "collect-changes" + if: env.LABEL_EXISTS != 'true' + uses: dorny/paths-filter@v3 + with: + filters: | + changelog: + - CHANGELOG.md + - name: "Make sure CHANGELOG.md is updated" + if: env.LABEL_EXISTS != 'true' + env: + CHANGELOG_UPDATED: ${{ steps.collect-changes.outputs.changelog }} + run: | + if [ "${CHANGELOG_UPDATED}" = "true" ] ; then + echo "CHANGELOG.md is updated" + else + echo "CHANGELOG.md is not updated" + exit 1 + fi diff --git a/.github/workflows/release_helm_chart.yml b/.github/workflows/release_helm_chart.yml index ab71947485..191b149686 100644 --- a/.github/workflows/release_helm_chart.yml +++ b/.github/workflows/release_helm_chart.yml @@ -2,20 +2,29 @@ name: Release helm chart files on: push: - tags: 'chart-*' + tags: + - "chart-*" + +permissions: read-all jobs: release-chart: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + - name: Extract version + id: extract_version + run: | + VERSION=${GITHUB_REF_NAME##chart-} + echo "version=$VERSION" >> $GITHUB_OUTPUT - name: Publish Helm chart uses: stefanprodan/helm-gh-pages@master with: - token: ${{ secrets.CR_TOKEN }} + token: ${{ secrets.RELEASE_HELM_CHART_TOKEN }} charts_dir: helm charts_url: https://charts.chaos-mesh.org owner: chaos-mesh repository: charts branch: gh-pages - + app_version: ${{ steps.extract_version.outputs.version }} + chart_version: ${{ steps.extract_version.outputs.version }} diff --git a/.github/workflows/script_test.yml b/.github/workflows/script_test.yml deleted file mode 100644 index e6ac63fe3a..0000000000 --- a/.github/workflows/script_test.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Script Test -on: - push: - branches: - - master - pull_request: - branches: - - master - -jobs: - run: - name: Script Test - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - with: - # Must use at least depth 2! - fetch-depth: 2 - - - name: Creating kind cluster - uses: helm/kind-action@v1.0.0-rc.1 - - - name: Install Chaos Mesh - run: | - bash install.sh --local kind --crd ./manifests/crd.yaml - - - name: Run integration test - run: | - bash test/integration_test/run.sh network diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml deleted file mode 100644 index bbbd84eea0..0000000000 --- a/.github/workflows/stale.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Mark stale issues and pull requests - -on: - schedule: - - cron: "0 0 * * *" - -jobs: - stale: - - runs-on: ubuntu-latest - - steps: - - uses: actions/stale@v3 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-issue-message: 'This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 21 days' - stale-pr-message: 'This pr is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 21 days' - days-before-stale: 90 - days-before-close: 21 - stale-issue-label: 'lifecycle/stale' - stale-pr-label: 'lifecycle/stale' - exempt-issue-labels: 'lifecycle/frozen,type/enhancement,type/suggestion,type/bug' - exempt-pr-labels: 'lifecycle/frozen,type/enhancement,type/bug-fix' diff --git a/.github/workflows/upload_env_image.yml b/.github/workflows/upload_env_image.yml new file mode 100644 index 0000000000..efbb706b41 --- /dev/null +++ b/.github/workflows/upload_env_image.yml @@ -0,0 +1,116 @@ +name: Upload Env Images + +on: + workflow_dispatch: {} + push: + paths: + - "images/build-env/Dockerfile" + - "images/dev-env/Dockerfile" + branches: + - master + - release-* + +permissions: read-all + +jobs: + build-specific-architecture: + permissions: + # https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions#authenticating-to-package-registries-on-github + packages: write + runs-on: ubuntu-20.04 + strategy: + matrix: + arch: [amd64, arm64] + image: [dev, build] + outputs: + image_tag: ${{ steps.image_tag.outputs.image_tag }} + steps: + - uses: actions/checkout@v4 + + - name: Extract Image Tag + shell: bash + run: | + # we assume that both image tags of build-env and dev-env are same during this workflow + IMAGE_TAG=$(./hack/env-image-tag.sh build-env) + + echo "::set-output name=image_tag::$(echo $IMAGE_TAG)" + id: image_tag + + - name: Log in to GitHub Docker Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build Chaos Mesh Env + env: + IMAGE_TAG: ${{ steps.image_tag.outputs.image_tag }} + ARCH: ${{ matrix.arch }} + IMAGE: ${{ matrix.image }} + GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} + run: | + export IMAGE_${IMAGE^^}_ENV_BUILD=1 + export IMAGE_${IMAGE^^}_ENV_TAG=$IMAGE_TAG-$ARCH + + docker run --rm --privileged multiarch/qemu-user-static --reset -p yes + + # ${VAR,,} convert VAR to lower case + make -B \ + TARGET_PLATFORM=$ARCH \ + IMAGE_TAG=$IMAGE_TAG-$ARCH \ + image-$IMAGE-env + + - name: Upload Chaos Mesh Env + env: + IMAGE_TAG: ${{ steps.image_tag.outputs.image_tag }} + ARCH: ${{ matrix.arch }} + IMAGE: ${{ matrix.image }} + GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} + run: | + # ${VAR,,} convert VAR to lower case + docker push ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE-env:$IMAGE_TAG-$ARCH + + upload-manifest: + permissions: + # https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions#authenticating-to-package-registries-on-github + packages: write + runs-on: ubuntu-20.04 + strategy: + matrix: + image: [dev, build] + needs: build-specific-architecture + steps: + - name: Build Chaos Mesh manifest + env: + IMAGE: ${{ matrix.image }} + IMAGE_TAG: ${{ needs.build-specific-architecture.outputs.image_tag }} + GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} + run: | + # ${VAR,,} convert VAR to lower case + docker manifest create ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE-env:$IMAGE_TAG \ + ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE-env:$IMAGE_TAG-amd64 \ + ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE-env:$IMAGE_TAG-arm64 + + docker manifest annotate ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE-env:$IMAGE_TAG \ + ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE-env:$IMAGE_TAG-amd64 \ + --os linux --arch amd64 + docker manifest annotate ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE-env:$IMAGE_TAG \ + ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE-env:$IMAGE_TAG-arm64 \ + --os linux --arch arm64 + + - name: Log in to GitHub Docker Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload Chaos Mesh Env + env: + IMAGE: ${{ matrix.image }} + IMAGE_TAG: ${{ needs.build-specific-architecture.outputs.image_tag }} + GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} + run: | + # ${VAR,,} convert VAR to lower case + docker manifest push ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE-env:$IMAGE_TAG diff --git a/.github/workflows/upload_image.yml b/.github/workflows/upload_image.yml new file mode 100644 index 0000000000..75a8d9824f --- /dev/null +++ b/.github/workflows/upload_image.yml @@ -0,0 +1,194 @@ +name: Upload Image + +on: + workflow_dispatch: {} + schedule: + - cron: "0 0 * * 0" + release: + types: [published] + +permissions: read-all + +jobs: + build-specific-architecture: + if: ${{ github.repository == 'chaos-mesh/chaos-mesh' }} + permissions: + # https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions#authenticating-to-package-registries-on-github + packages: write + strategy: + matrix: + arch: [amd64, arm64] + image: + [chaos-daemon, chaos-mesh, chaos-dashboard, chaos-kernel, chaos-dlv] + outputs: + image_tag: ${{ steps.image_tag.outputs.image_tag }} + runs-on: ${{ fromJson('{"amd64":"ubuntu-20.04", "arm64":["self-hosted", "Linux", "ARM64"]}')[matrix.arch] }} + steps: + - uses: actions/checkout@v4 + with: + # It requires all the tags and branches to generate the correct GitVersion with `hack/version.sh`. + fetch-depth: 0 + + - name: Extract Image Tag + id: image_tag + shell: bash + run: | + IMAGE_TAG=${GITHUB_REF##*/} + if [ "${IMAGE_TAG}" = "master" ] ; then + IMAGE_TAG=latest; + fi + + echo "::set-output name=image_tag::$(echo $IMAGE_TAG)" + + - name: Login to GitHub Container registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build Chaos Mesh + env: + IMAGE_TAG: ${{ steps.image_tag.outputs.image_tag }} + ARCH: ${{ matrix.arch }} + IMAGE: ${{ matrix.image }} + GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} + run: | + if [ "${IMAGE}" = "chaos-dashboard" ]; then + UI=1 + else + UI=0 + fi + # ${VAR,,} convert VAR to lower case + make -B \ + TARGET_PLATFORM=$ARCH \ + IMAGE_TAG=$IMAGE_TAG-$ARCH \ + IMAGE_DEV_ENV_BUILD=1 \ + IMAGE_BUILD_ENV_BUILD=1 \ + UI=$UI \ + image-$IMAGE + + - name: Upload Chaos Mesh + env: + IMAGE_TAG: ${{ steps.image_tag.outputs.image_tag }} + ARCH: ${{ matrix.arch }} + IMAGE: ${{ matrix.image }} + GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} + run: | + # ${VAR,,} convert VAR to lower case + docker push ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE:$IMAGE_TAG-$ARCH + + upload-manifest: + needs: build-specific-architecture + runs-on: ubuntu-20.04 + permissions: + # https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions#authenticating-to-package-registries-on-github + packages: write + strategy: + matrix: + image: + [chaos-daemon, chaos-mesh, chaos-dashboard, chaos-kernel, chaos-dlv] + env: + IMAGE_TAG: ${{ needs.build-specific-architecture.outputs.image_tag }} + GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} + steps: + - name: Create the manifest list + env: + IMAGE: ${{ matrix.image }} + run: | + # ${VAR,,} convert VAR to lower case + docker manifest create ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE:$IMAGE_TAG \ + ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE:$IMAGE_TAG-amd64 \ + ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE:$IMAGE_TAG-arm64 + + docker manifest annotate ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE:$IMAGE_TAG \ + ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE:$IMAGE_TAG-amd64 \ + --os linux --arch amd64 + docker manifest annotate ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE:$IMAGE_TAG \ + ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE:$IMAGE_TAG-arm64 \ + --os linux --arch arm64 + + - name: Login to GitHub Container registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Push the manifest list + env: + IMAGE: ${{ matrix.image }} + run: | + # ${VAR,,} convert VAR to lower case + docker manifest push ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/$IMAGE:$IMAGE_TAG + + sign: + needs: + - build-specific-architecture + - upload-manifest + if: needs.build-specific-architecture.outputs.image_tag != 'latest' + runs-on: ubuntu-20.04 + permissions: + contents: write # Need to upload files to the related release. + # https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions#authenticating-to-package-registries-on-github + packages: write + env: + IMAGE_TAG: ${{ needs.build-specific-architecture.outputs.image_tag }} + steps: + - name: Install cosign + uses: sigstore/cosign-installer@main + with: + cosign-release: "v1.13.1" + - name: Login to GitHub Container registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Sign Chaos Mesh Container images + env: + COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }} + COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }} + run: | + cosign sign --key env://COSIGN_PRIVATE_KEY ghcr.io/chaos-mesh/chaos-mesh:$IMAGE_TAG --output-signature ghcr.io-chaos-mesh-chaos-mesh-$IMAGE_TAG.sig + cosign sign --key env://COSIGN_PRIVATE_KEY ghcr.io/chaos-mesh/chaos-daemon:$IMAGE_TAG --output-signature ghcr.io-chaos-mesh-chaos-daemon-$IMAGE_TAG.sig + cosign sign --key env://COSIGN_PRIVATE_KEY ghcr.io/chaos-mesh/chaos-dashboard:$IMAGE_TAG --output-signature ghcr.io-chaos-mesh-chaos-dashboard-$IMAGE_TAG.sig + cosign sign --key env://COSIGN_PRIVATE_KEY ghcr.io/chaos-mesh/chaos-kernel:$IMAGE_TAG --output-signature ghcr.io-chaos-mesh-chaos-kernel-$IMAGE_TAG.sig + cosign public-key --key env://COSIGN_PRIVATE_KEY > cosign.pub + - name: Upload cosign.pub and sigs + uses: softprops/action-gh-release@v1 + with: + files: | + cosign.pub + ghcr.io-chaos-mesh-chaos-mesh-${{ needs.build-specific-architecture.outputs.image_tag }}.sig + ghcr.io-chaos-mesh-chaos-daemon-${{ needs.build-specific-architecture.outputs.image_tag }}.sig + ghcr.io-chaos-mesh-chaos-dashboard-${{ needs.build-specific-architecture.outputs.image_tag }}.sig + ghcr.io-chaos-mesh-chaos-kernel-${{ needs.build-specific-architecture.outputs.image_tag }}.sig + + sbom: + needs: build-specific-architecture + if: needs.build-specific-architecture.outputs.image_tag != 'latest' + runs-on: ubuntu-20.04 + permissions: + contents: write # Need to upload files to the related release. + env: + IMAGE_TAG: ${{ needs.build-specific-architecture.outputs.image_tag }} + steps: + - uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + check-latest: true + go-version-file: "go.mod" + + - name: Install bom + run: go install sigs.k8s.io/bom/cmd/bom@latest + + - name: Generate SBOM + run: bom generate -n https://chaos-mesh.org/chaos-mesh.spdx -o chaos-mesh-$IMAGE_TAG-sbom.spdx . + + - name: Upload SBOM + uses: softprops/action-gh-release@v1 + with: + files: chaos-mesh-${{ needs.build-specific-architecture.outputs.image_tag }}-sbom.spdx diff --git a/.github/workflows/upload_image_pr.yml b/.github/workflows/upload_image_pr.yml new file mode 100644 index 0000000000..692bbc3da2 --- /dev/null +++ b/.github/workflows/upload_image_pr.yml @@ -0,0 +1,94 @@ +name: Upload Image for PR + +on: + issue_comment: + types: [created] + +permissions: read-all + +jobs: + build-for-pr: + runs-on: ubuntu-20.04 + if: ${{ github.event.issue.pull_request && startsWith( github.event.comment.body, '/build-image') }} + steps: + - uses: actions/checkout@v4 + + - name: Install jq + run: | + sudo apt-get install jq -y + + - name: Cache docker image and go + uses: actions/cache@v2 + with: + path: | + cache + key: chaos-mesh-build-${{ github.event.issue.number }} + + - name: Enable docker builder + run: | + DOCKER_CLI_EXPERIMENTAL=enabled docker buildx create --use --name chaos-mesh-builder + + - name: Build Chaos Mesh Build Env + env: + IMAGE_BUILD_ENV_BUILD: ${{ contains(github.event.pull_request.labels.*.name, 'rebuild-build-env-image') }} + run: | + if [ "${IMAGE_BUILD_ENV_BUILD}" = "true" ] ; then + export IMAGE_BUILD_ENV_BUILD=1; + else + export IMAGE_BUILD_ENV_BUILD=0; + fi + + make \ + DOCKER_CACHE=1 \ + DOCKER_CACHE_DIR=$GITHUB_WORKSPACE/cache \ + GO_BUILD_CACHE=$GITHUB_WORKSPACE/cache \ + image-build-env + + - name: Build Chaos Mesh Dev Env + env: + IMAGE_DEV_ENV_BUILD: ${{ contains(github.event.pull_request.labels.*.name, 'rebuild-dev-env-image') }} + run: | + if [ "${IMAGE_DEV_ENV_BUILD}" = "true" ] ; then + export IMAGE_DEV_ENV_BUILD=1; + else + export IMAGE_DEV_ENV_BUILD=0; + fi + + make \ + DOCKER_CACHE=1 \ + DOCKER_CACHE_DIR=$GITHUB_WORKSPACE/cache \ + GO_BUILD_CACHE=$GITHUB_WORKSPACE/cache \ + image-dev-env + + - name: Build Chaos Mesh + run: | + make \ + IMAGE_TAG=latest \ + UI=1 \ + DOCKER_CACHE=1 \ + DOCKER_CACHE_DIR=$GITHUB_WORKSPACE/cache \ + GO_BUILD_CACHE=$GITHUB_WORKSPACE/cache \ + image + + for IMAGE in "chaos-mesh" "chaos-daemon" "chaos-dashboard" + do + docker image save ghcr.io/chaos-mesh/$IMAGE > $IMAGE.tar + done + + - name: Upload Chaos Mesh Image to Artifacts + uses: actions/upload-artifact@v4 + with: + name: chaos-mesh-images + path: | + *.tar + + - name: Create comment + uses: peter-evans/create-or-update-comment@v1 + with: + issue-number: ${{ github.event.issue.number }} + body: | + You can download and import the image with following commands: + + ```bash + ./hack/download-image.sh -r ${{ github.repository }} -i ${{ github.run_id }} + ``` diff --git a/.github/workflows/upload_latest_files.yml b/.github/workflows/upload_latest_files.yml index 0da4d83e39..1d8822b3ee 100644 --- a/.github/workflows/upload_latest_files.yml +++ b/.github/workflows/upload_latest_files.yml @@ -1,4 +1,5 @@ name: Upload latest install related files to CDN + on: push: branches: @@ -9,30 +10,35 @@ on: - examples/web-show/deploy.sh - pkg/chaosctl/** - cmd/chaosctl/** + - tools/schedule-migration/** + +permissions: read-all + jobs: run: + if: github.repository_owner == 'chaos-mesh' name: Upload - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - - name: Set up Go 1.15 - uses: actions/setup-go@v2 - with: - go-version: 1.15.11 - id: go - - - uses: actions/checkout@master + - uses: actions/checkout@v4 with: # Must use at least depth 2! fetch-depth: 2 - uses: actions/setup-python@v2 + - uses: actions/setup-go@v4 + with: + check-latest: true + go-version-file: "go.mod" - name: Configure awscli run: | pip3 install awscli printf "%s\n" ${{ secrets.AWS_ACCESS_KEY }} ${{ secrets.AWS_SECRET_KEY }} ${{ secrets.AWS_REGION }} "json" | aws configure - - name: Build chaosctl - run: make chaosctl + - name: Build binary + run: | + make chaosctl + make schedule-migration - name: Upload files run: | @@ -44,3 +50,4 @@ jobs: aws s3 cp manifests/crd.yaml ${{ secrets.AWS_BUCKET_NAME }}/${GIT_TAG}/crd.yaml aws s3 cp examples/web-show/deploy.sh ${{ secrets.AWS_BUCKET_NAME }}/${GIT_TAG}/web-show/deploy.sh aws s3 cp bin/chaosctl ${{ secrets.AWS_BUCKET_NAME }}/${GIT_TAG}/chaosctl + aws s3 cp bin/schedule-migration ${{ secrets.AWS_BUCKET_NAME }}/${GIT_TAG}/schedule-migration diff --git a/.github/workflows/upload_release_files.yml b/.github/workflows/upload_release_files.yml index ff3976b82a..2e51142956 100644 --- a/.github/workflows/upload_release_files.yml +++ b/.github/workflows/upload_release_files.yml @@ -1,32 +1,61 @@ name: Upload tagged install related files to CDN + on: push: tags: - v* + +permissions: read-all + jobs: run: name: Upload - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - - name: Set up Go 1.15 - uses: actions/setup-go@v2 - with: - go-version: 1.15.11 - id: go + - name: "Must Triggered by Tag v" + run: | + # GITHUB_REF_TYPE MUST equals to "tag" + if [ "${GITHUB_REF_TYPE}" != "tag" ]; then + echo "This workflow must be triggered by tag" + echo "GITHUB_REF_TYPE: ${GITHUB_REF_TYPE}" + echo "GITHUB_REF: ${GITHUB_REF}" + exit 1 + fi + + # The tag MUST start with "v" + GIT_TAG=${GITHUB_REF##*/} + if [[ "${GIT_TAG}" == "v"* ]]; then + exit 0 + fi - - uses: actions/checkout@master + echo "The tag must start with 'v'" + echo "GITHUB_REF: ${GITHUB_REF}" + exit 1 + - uses: actions/checkout@v4 with: # Must use at least depth 2! fetch-depth: 2 - uses: actions/setup-python@v2 + - uses: actions/setup-go@v4 + with: + check-latest: true + go-version-file: "go.mod" - name: Configure awscli run: | pip3 install awscli printf "%s\n" ${{ secrets.AWS_ACCESS_KEY }} ${{ secrets.AWS_SECRET_KEY }} ${{ secrets.AWS_REGION }} "json" | aws configure - - name: Build chaosctl - run: make chaosctl + - name: Build binary + run: | + make chaosctl + make schedule-migration.tar.gz + + - name: Update install.sh with Certain Version + run: | + GIT_TAG=${GITHUB_REF##*/} + VERSION=${GIT_TAG##chart-} + sed install.sh -i -e "s/^VERSION=.*/VERSION=${VERSION}/" - name: Upload files run: | @@ -35,3 +64,4 @@ jobs: aws s3 cp manifests/crd.yaml ${{ secrets.AWS_BUCKET_NAME }}/${GIT_TAG}/crd.yaml aws s3 cp examples/web-show/deploy.sh ${{ secrets.AWS_BUCKET_NAME }}/${GIT_TAG}/web-show/deploy.sh aws s3 cp bin/chaosctl ${{ secrets.AWS_BUCKET_NAME }}/${GIT_TAG}/chaosctl + aws s3 cp schedule-migration.tar.gz ${{ secrets.AWS_BUCKET_NAME }}/${GIT_TAG}/schedule-migration.tar.gz diff --git a/.gitignore b/.gitignore index 0a46c8dce5..08a89e23b6 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,6 @@ tags *.fail.go vendor .DS_Store -core. core.sqlite # Output of the go coverage tool, specifically when used with LiteIDE @@ -22,23 +21,29 @@ core.sqlite # retool. We could check this in like a vendor # But it is just tools that can be installed with make setup /_tools/ +.devcontainer -/images/chaos-dashboard/build node_modules +go.work +go.work.sum + output/ _artifacts/ -test/image/e2e/chaos-mesh -test/image/e2e/manifests/ - -/pkg/uiserver/embedded_assets_handler.go +e2e-test/image/e2e/chaos-mesh +e2e-test/image/e2e/manifests/ -/docs/swagger.* -/docs/docs.go +/pkg/dashboard/uiserver/embedded_assets_handler.go /images/*/bin/* !/images/*/bin/.gitkeep .dockerbuilt -Dockerfile +/Dockerfile +.cache + +*.o + +__pycache__ +*.pyc diff --git a/.lift.toml b/.lift.toml new file mode 100644 index 0000000000..f63b9dc26e --- /dev/null +++ b/.lift.toml @@ -0,0 +1,10 @@ +# lift config reference: https://help.sonatype.com/lift/configuration-reference + +# A deny list of analyis tools to not be applied to the repository. +# disableTools = [] + +# Any issue in the ignore list is never reported to the user +# Semgrep -> opt.semgrep.import-text-template -> 'text/template' does not escape HTML content. If you need to escape HTML content, use 'html/template' instead. +# Semgrep -> opt.semgrep.pprof-debug-exposure -> The profiling 'pprof' endpoint is automatically exposed on /debug/pprof. ... +# Semgrep -> opt.semgrep.go.lang.security.audit.net.pprof.pprof-debug-exposure -> The profiling 'pprof' endpoint is automatically exposed on /debug/pprof. ... +ignoreRules = ["opt.semgrep.import-text-template", "opt.semgrep.pprof-debug-exposure", "opt.semgrep.go.lang.security.audit.net.pprof.pprof-debug-exposure"] diff --git a/.muse.toml b/.muse.toml new file mode 100644 index 0000000000..173fb04ebc --- /dev/null +++ b/.muse.toml @@ -0,0 +1,6 @@ +# configurations for muse-dev +# reference: https://docs.muse.dev/docs/repository-configuration/ + +ignoreFiles = """ +e2e-test/** +""" diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000000..d2504b43d5 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "proseWrap": "never" +} diff --git a/.well-known/funding-manifest-urls b/.well-known/funding-manifest-urls new file mode 100644 index 0000000000..fdd3a10b5f --- /dev/null +++ b/.well-known/funding-manifest-urls @@ -0,0 +1,2 @@ +https://strrl.dev/funding.json +https://g1en.site/funding.json diff --git a/ADOPTERS.md b/ADOPTERS.md index 8fd7ceb65c..2897a9d837 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -1,20 +1,34 @@ -# Chaos Mesh® Adopters +# Chaos Mesh Adopters -This is a list of known adopters of Chaos Mesh. Some have already gone into production, and others are at various stages of testing. +Chaos Mesh now has over 40 adopters, here we have listed some of them. Some have already gone into production, and others are at various stages of testing. -- [Apache APISIX](https://github.com/apache/apisix) -- [Celo](https://celo.org/) -- [Dailymotion](https://www.dailymotion.com/) -- [DataStax Fallout](https://github.com/datastax/fallout) -- [NetEase Fuxi Lab](https://fuxi.163.com/en/about.html) -- [JuiceFS](https://juicefs.com/?hl=en) -- [KingNet](https://www.kingnet.com/) -- [Meituan Dianping](https://about.meituan.com/en) -- [PingCAP](https://en.pingcap.com/) -- [Apache Pulsar](https://pulsar.apache.org/) -- [Qihoo 360](https://360.cn/) -- [Qiniu Cloud](https://qiniu.com/en) -- [Tencent](https://www.tencent.com/en-us) -- [Vald](https://vald.vdaas.org/) -- [WeBank](https://www.webank.com/) -- [Xpeng](https://en.xiaopeng.com/) +If you are an adopter and are willing to share your Chaos Mesh story, feel free to raise a PR against this file! + +## End users + +| Organization  |Use case  |  Details | +| ------------------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------- | +| [Authzed](http://authzed.com/)  |Uses `TimeChaos` to fake vDSO time calls to test SpiceDB.   |[How SpiceDB uses Chaos Mesh to verify protection](https://youtu.be/3rjWxgdtBTw)  | +| [PITS Globale Datenrettungsdienste](https://pitsdatenrettung.de/)  | Utilizes IOChaos combined with workflows for fault simulations and other needs.   | To be added. | +| [ByteDance](https://bytedance.com/en/)  |ByteDance's self-developed chaos engineering platform is mainly used by the company's own technology system. As there are cloud-native deployment services involved, ByteDance integrates Chaos Mesh as the underlying fault injection engine, which is a key supplement to ByteDance’s chaos engineering platform.  | To be added. | +| [DataStax](https://www.datastax.com/)  |DataStax utilized Chaos Mesh to create a tool for running local or large scale remote based distributed correctness, verification and performance tests: [Fallout](https://github.com/datastax/fallout), which they use to test AstraDB, a multi-cloud DBaaS built on Apache Cassandra.  | [Leveraging Chaos Mesh in AstraDB Testing](https://youtu.be/Kw7gMurHJnQ) | +| [DigitalChina](http://www.digitalchina.com/en/)  |To better serve their strategy to transform to cloud infrastructure, DigitalChina uses Chaos Mesh to test the application's ability to maintain business functions and to discover errors and vulnerabilities that may occur under extreme conditions.  |[Develop a Daily Reporting System for Chaos Mesh](https://mp.weixin.qq.com/s/dm6GayOE-4A6Bdz-ucS6Dw) | +| [KingNet](https://www.kingnet.com/)  |KingNet uses Chaos Mesh for testing the availability of multiple data centers and microservice links. Chaos Mesh also helps them with mocking service unavailability or abnormal network conditions.  |To be added. | +| [GreptimeDB](https://www.greptime.com/)  |GreptimeDB uses Chaos Mesh to enhance the correctness and availability of their distributed cluster. Chaos engineering finds lots of corner cases from the database implement to their dependencies. | [Chaos Engineering - Who's to Blame for the Bug Mess?](https://greptime.com/blogs/2023-11-06-chaos-engineering) | +| [NetEase Fuxi Lab](https://fuxi.163.com/fuxi-introduction)  |Uses Chaos Mesh to improve the stability of their internal hybrid cloud. In addition, their users with cloud platforms also access Chaos Mesh to test the stability of user services.  |[How a Top Game Company Uses Chaos Engineering to Improve Testing](https://chaos-mesh.org/blog/how-a-top-game-company-uses-chaos-engineering-to-improve-testing) | +| [Percona](https://www.percona.com/)  |Percona uses Chaos Mesh to test their Percona Kubernetes Operators, which is used to deploy their own Database-as-Service.  |[Chaos Mesh to Create Chaos in Kubernetes](https://www.percona.com/blog/2020/11/05/chaosmesh-to-create-chaos-in-kubernetes/) | +| [PingCAP](https://en.pingcap.com/)  |Built [TiPocket](https://github.com/pingcap/tipocket) ontop of Chaos Mesh, an automated testing framework to build a full Chaos Engineering testing loop for TiDB, a distributed database.  |[Building an Automated Testing Framework Based on Chaos Mesh and Argo](https://chaos-mesh.org/blog/building_automated_testing_framework/) | +| [Prudential](https://www.prudential.com.sg/) |Chaos Mech is an essential part of the Pru SRE toolset that implements managed outages scenarios for comprehensive testing of distributed microservice product platforms, especially Java-powered runtimes.  |To be added. | +| [Qiniu Cloud](https://qiniu.com/en)  |To ensure the reliability of cloud storage products, they use Chaos Mesh to perform chaos tests on metadata and the underlying storage system under conditions such as: single point of failure of services, network abnormality, abnormal resource consumption (CPU, memory, I/O), etc.  |To be added. | +| [RabbitMQ](https://www.rabbitmq.com/)  |RabbitMQ applies NetworkChaos to learn how RabbitMQ handles network latency.  |[Testing RabbitMQ Resiliency with Chaos Mesh](https://github.com/rabbitmq/tgir/tree/S01E09/s01/e09) | +| [Tencent](https://www.tencent.com/en-us)  |After Tencent Interactive Entertainment migrated their online operations to the Tencent Cloud Kubernetes engine, they wished to provide users with a more stable and reliable experience, which is why they introduced Chaos Mesh. Tencent mainly use Chaos Mesh to simulate the following types of failures: fault isolation, service degradation, verification of services.  |[Securing Online Gaming: Combine Chaos Engineering with DevOps Practices](https://chaos-mesh.org/blog/Securing-Online-Gaming-Combine-Chaos-Engineering-with-DevOps-Practices/) | +| [Xpeng](https://en.xiaopeng.com/)  |Xpeng Motors use Chaos Mesh in the following scenarios: rolling updates of microservices and lossless verification of traffic; microservices, multi-registries, multi-party synchronization, and traffic lossless verification; MQTT cluster two-way subscription verification; exactly-once consumer business verification for message queues;simulation of weak 4G network for in-vehicle systems, saving drive test costs; AIOPS anomaly detection dataset generation.  |To be added. | +| [Maycur](https://www.maycur.com/) |Maycur built Chaos Mesh on K8S for JVM fault drill, mainly for JVM delay, method exception, method return value modification, and other scenarios. |To be added. | + +## Vendors + +| Organization  |  Use case  |  Details | +| ------------------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------- | +| [Civo](https://github.com/civo/kubernetes-marketplace) |Chaos Mesh can be directly deployed from the Civo's Kubernetes marketplace. |[Automating chaos engineering with Chaos Mesh](https://www.civo.com/learn/automating-chaos-engineering-with-chaos-mesh-on-civo) | +| [KubeSphere](https://github.com/kubesphere/kubesphere) |Chaos Mesh can be directly deployed from the KubeSphere App Store starting from KubeSphere v2.3 onwards. |To be added. | +| [Microsoft](https://www.microsoft.com/)  |Microsoft's Azure Chaos Studio integrated Chaos Mesh, so that users can inject faults into AKS clusters.   |[Create a chaos experiment that uses a Chaos Mesh fault to kill AKS pods](https://docs.microsoft.com/en-us/azure/chaos-studio/chaos-studio-tutorial-aks) | diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..8cdc900e35 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,824 @@ +# Chaos Mesh Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +For more information and how-to, see [RFC: Keep A Changelog](https://github.com/chaos-mesh/rfcs/blob/main/text/2022-01-17-keep-a-changelog.md). + +## [Unreleased] + +### Added + +- Nothing + +### Changed + +- Upgrade pnpm lockfile version to 9.0 [#4522](https://github.com/chaos-mesh/chaos-mesh/pull/4522) + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Issue with getting a single archive in the Dashboard UI [#4521](https://github.com/chaos-mesh/chaos-mesh/pull/4521) + +### Security + +- Nothing + +## [2.7.0] - 2024-09-20 + +### Added + +- Allow if condition for creating chaos-controller-manager ServiceAccount and allow setting securityContext for chaos-daemon pods [#4390](https://github.com/chaos-mesh/chaos-mesh/pull/4390) +- Allow annotations on chaos-controller-manager and chaos-daemon ServiceAccount [#4106](https://github.com/chaos-mesh/chaos-mesh/pull/4106) +- Support for deploying chaos-dashboard under the subpath [#4093](https://github.com/chaos-mesh/chaos-mesh/pull/4093) +- Support more rate units for networkchaos [#4129](https://github.com/chaos-mesh/chaos-mesh/pull/4129) +- Support for deploying chaos-dashboard with sidecar containers in helm chart [#4164](https://github.com/chaos-mesh/chaos-mesh/pull/4164) +- Add `values.schema.json` [#4205](https://github.com/chaos-mesh/chaos-mesh/pull/4205) +- Add [`GreptimeDB`](https://greptime.com) to ADOPTERS.md [#4245](https://github.com/chaos-mesh/chaos-mesh/pull/4245) +- Support configurable chaos-dns-server pod affinities [#4260](https://github.com/chaos-mesh/chaos-mesh/pull/4260) +- Add experiment `name`, `namespace` and `kind` to "apply chaos" and "recover chaos" log messages [4278](https://github.com/chaos-mesh/chaos-mesh/pull/4278) +- Support for watching remote status of chaos experiments to local [#4188](https://github.com/chaos-mesh/chaos-mesh/pull/4188) +- Add netem/rate support for NetworkChaos [#4017](https://github.com/chaos-mesh/chaos-mesh/pull/4017) +- Support for setting `loadBalancerSourceRanges` in chaos-dashboard service in helm chart [#4172](https://github.com/chaos-mesh/chaos-mesh/pull/4172) +- Helm: allow templating of dashboard rootUrl [#4370](https://github.com/chaos-mesh/chaos-mesh/pull/4370) +- Support for reading database connection string from secret [#4363](https://github.com/chaos-mesh/chaos-mesh/pull/4363) +- Allow if condition for creating chaos-controller-manager ServiceAccount and allow setting securityContext for chaos-daemon pods [#4390](https://github.com/chaos-mesh/chaos-mesh/pull/4390) +- Integrate helm-values-schema-json to generate schema for values.yaml [#4435](https://github.com/chaos-mesh/chaos-mesh/pull/4435) +- Add an option to toggle metric scraping of Chaos Daemon [#4488](https://github.com/chaos-mesh/chaos-mesh/pull/4488) + +### Changed + +- Change `awschaos/*/impl.go` to use `aws_session_token` with static credentials provider so that users can perform awschaos using [temporary AWS credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html) [#4066](https://github.com/chaos-mesh/chaos-mesh/pull/4066) +- Enable consistency for ghcr.io registry [#4091](https://github.com/chaos-mesh/chaos-mesh/pull/4091) [#4134](https://github.com/chaos-mesh/chaos-mesh/pull/4134) +- Prevent mousewheel scroll from changing numeric input values. [#4133](https://github.com/chaos-mesh/chaos-mesh/pull/4133) +- Set the database column type to text for 'Workflow/Experiment/Schedule' [#4151](https://github.com/chaos-mesh/chaos-mesh/pull/4151) +- Bump go to v1.20 [#4157](https://github.com/chaos-mesh/chaos-mesh/pull/4157) +- Upgrade docker/login-action to v2 [#4167](https://github.com/chaos-mesh/chaos-mesh/pull/4167) +- Update k8s dependencies to 1.28.0 [#4154](https://github.com/chaos-mesh/chaos-mesh/pull/4154) +- Update lru dependency [#4189](https://github.com/chaos-mesh/chaos-mesh/pull/4189) +- Update swag dependency [#4191](https://github.com/chaos-mesh/chaos-mesh/pull/4191) +- Update ginkgo to 2.12.0 [#4190](https://github.com/chaos-mesh/chaos-mesh/pull/4190) +- Update k8s controller-runtime dependency [#4198](https://github.com/chaos-mesh/chaos-mesh/pull/4198) +- Automatically remove the token from the dashboard when it expires [#4193](https://github.com/chaos-mesh/chaos-mesh/pull/4193) +- Optimize `allInjected` and `allRecovered` states when targets are not selected [#4199](https://github.com/chaos-mesh/chaos-mesh/pull/4199) +- Upgrade byteman-helper to v4.0.22 [#4299](https://github.com/chaos-mesh/chaos-mesh/pull/4299) +- GCP auth is changed to object with additional key `existingSecret` in helm chart values [#4303](https://github.com/chaos-mesh/chaos-mesh/pull/4303) +- Add context to the http request to download the chart [#4304](https://github.com/chaos-mesh/chaos-mesh/pull/4304) + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Set `replicas: 1` automatically when HA is not enabled [#4079](https://github.com/chaos-mesh/chaos-mesh/pull/4079) +- Remove redundant where statements [#4084](https://github.com/chaos-mesh/chaos-mesh/pull/4084) +- Fix dashboard panic when exec delete action by finish_time [#4100](https://github.com/chaos-mesh/chaos-mesh/pull/4100) +- Fix remote cluster cannot upgrade helm release [#4075](https://github.com/chaos-mesh/chaos-mesh/pull/4075) +- Fix goroutine leak [#4229](https://github.com/chaos-mesh/chaos-mesh/pull/4229) +- Remove the duplicate `make test` [#4234](https://github.com/chaos-mesh/chaos-mesh/pull/4234) +- Fix daemon-server `SetDNSServer` endpoint to validate provided server address [#4246](https://github.com/chaos-mesh/chaos-mesh/pull/4246) +- Enable prometheus directive within CoreDNS [#4321](https://github.com/chaos-mesh/chaos-mesh/pull/4321) +- Fix TTL configuration from environment variables [#4338](https://github.com/chaos-mesh/chaos-mesh/pull/4338) +- Fix dashboard panic while replacing query namespace with targetNamespace in namespace scoped mode [#4409](https://github.com/chaos-mesh/chaos-mesh/issues/4409) +- Fix incorrect mmap args for IOChaos [#3680](https://github.com/chaos-mesh/chaos-mesh/issues/3680) +- Fix excessive records by adding the `MaxEvents` field [#4402](https://github.com/chaos-mesh/chaos-mesh/pull/4402) +- Fix chaos controller can't find daemonIP over 1000 nodes using endpoints [#4421](https://github.com/chaos-mesh/chaos-mesh/pull/4421) +- Minor fixes in certificates to make them ArgoCD friendly [#4482](https://github.com/chaos-mesh/chaos-mesh/pull/4482) + +### Security + +- Remove `-k` from `curl` command lines in chaos-daemon Dockerfile [#4241](https://github.com/chaos-mesh/chaos-mesh/pull/4241) +- Upgrade the base image of dev/build-env [#4388](https://github.com/chaos-mesh/chaos-mesh/pull/4388) + +## [2.6.0] - 2023-05-30 + +### Added + +- Install offline Helm Chart for a multi-cluster [#3897](https://github.com/chaos-mesh/chaos-mesh/pull/3897) + +### Changed + +- Change CoreDNS listen port from 53 to 5353 [#4022](https://github.com/chaos-mesh/chaos-mesh/pull/4022) +- Bump go to v1.19.3 [#3770](https://github.com/chaos-mesh/chaos-mesh/pull/3770) +- Change ubuntu version from latest to 20.04 [#3817](https://github.com/chaos-mesh/chaos-mesh/pull/3817) +- Switch views between k8s and hosts nodes [#3830](https://github.com/chaos-mesh/chaos-mesh/pull/3830) +- New CI for finding merge conflicts [#3850](https://github.com/chaos-mesh/chaos-mesh/pull/3850) +- Upgrade byteman-helper to v4.0.20 [#3863](https://github.com/chaos-mesh/chaos-mesh/pull/3863) +- Helm: change default webhook port to 10250 [#3877](https://github.com/chaos-mesh/chaos-mesh/pull/3877) +- Upgrade base image for chaos-mesh to alpine:3.17 [#3893](https://github.com/chaos-mesh/chaos-mesh/pull/3893) +- Slow down releasing the latest version [#3900](https://github.com/chaos-mesh/chaos-mesh/pull/3900) +- Update k8s.io dependencies to v0.26.1 [#3902](https://github.com/chaos-mesh/chaos-mesh/pull/3902) +- Update sigs.k8s.io/controller-runtime to v0.14.1 and sigs.k8s.io/controller-tools to v0.11.1 [#3902](https://github.com/chaos-mesh/chaos-mesh/pull/3902) +- Change the package manager from `yarn` to `pnpm`. [#3965](https://github.com/chaos-mesh/chaos-mesh/pull/3965) +- Upgrade DNS CoreDNS image url to ghcr.io [#3488](https://github.com/chaos-mesh/chaos-mesh/pull/3488) +- Upgrade OS image for chaos-daemon container image [#3905](https://github.com/chaos-mesh/chaos-mesh/pull/3905) +- Replace openapi-generator with Orval and React Query [#3748](https://github.com/chaos-mesh/chaos-mesh/pull/3748) +- Cleanup makefile and provide `make help` [#3888](https://github.com/chaos-mesh/chaos-mesh/pull/3888) +- Remove `IN_DOCKER` environment variable in `Makefile` [#3992](https://github.com/chaos-mesh/chaos-mesh/pull/3992) +- Refine TTL config of Chaos dashboard [#4008](https://github.com/chaos-mesh/chaos-mesh/pull/4008) +- `pause` would return non zero exit code when the subcommand failed [#4018](https://github.com/chaos-mesh/chaos-mesh/pull/4018) +- use helm values to set chaos-daemon capabilities [#4030](https://github.com/chaos-mesh/chaos-mesh/pull/4030) +- Build binaries locally with `local/` prefix targets in `Makefile` [#4004](https://github.com/chaos-mesh/chaos-mesh/pull/4004) +- Use kubectl cluster-info dump to enhance e2e profiling [#3759](https://github.com/chaos-mesh/chaos-mesh/pull/3759) +- Upgrade fx event logger [#4036](https://github.com/chaos-mesh/chaos-mesh/pull/4036) +- Refine logging in `pkg/selector/physicalmachine` [#4037](https://github.com/chaos-mesh/chaos-mesh/pull/4037) +- Setup OWNERS and OWNERS_ALIASES [#4039](https://github.com/chaos-mesh/chaos-mesh/pull/4039) + +### Deprecated + +- Nothing + +### Removed + +- Remove no needed file crd-v1beta1.yaml [#3807](https://github.com/chaos-mesh/chaos-mesh/pull/3807) +- Remove useless kubebuilder comment in webhook [#3816](https://github.com/chaos-mesh/chaos-mesh/pull/3816) +- Remove the unused inject-v1-pod webhook. [#3885](https://github.com/chaos-mesh/chaos-mesh/pull/3885) + +### Fixed + +- Fix version comparison in install.sh [#3901](https://github.com/chaos-mesh/chaos-mesh/pull/3901) +- Fix stuck dashboard updates when using ReadWriteOnce PVCs [#3876](https://github.com/chaos-mesh/chaos-mesh/issues/3876) +- Fix MySQL NO_ZERO_IN_DATE by using `*time.Time` to represent finish time [#4056](https://github.com/chaos-mesh/chaos-mesh/pull/4056) + +### Security + +- Bump go to v1.19.7 to fix CVE-2022-41723 [#3978](https://github.com/chaos-mesh/chaos-mesh/pull/3978) [#3981](https://github.com/chaos-mesh/chaos-mesh/pull/3981) +- Bump github.com/opencontainers/runc from 1.1.4 to 1.1.5 [#3987](https://github.com/chaos-mesh/chaos-mesh/pull/3987) + +## [2.5.0] - 2022-11-22 + +### Added + +- Add `controller.securityContext` and `dashboard.securityContext` to Helm chart [#3603](https://github.com/chaos-mesh/chaos-mesh/pull/3603) +- Add `RemoteCluster` resource type [#3342](https://github.com/chaos-mesh/chaos-mesh/pull/3342) +- Add `clusterregistry` package to help developers to develop multi-cluster reconciler [#3342](https://github.com/chaos-mesh/chaos-mesh/pull/3342) +- Add features about integration with helm to install Chaos Mesh in remote cluster [#3384](https://github.com/chaos-mesh/chaos-mesh/pull/3384) +- Add new CI "Manually Sign Container Images" to sign existing container images [#3708](https://github.com/chaos-mesh/chaos-mesh/pull/3708) +- Install and uninstall chaos mesh in remote cluster through `RemoteCluster` resource [#3414](https://github.com/chaos-mesh/chaos-mesh/pull/3414) +- MultiCluster: support inject / recover on remote cluster [#3453](https://github.com/chaos-mesh/chaos-mesh/pull/3453) +- Add TLS support for HTTPChaos [#3549](https://github.com/chaos-mesh/chaos-mesh/pull/3549) + +### Changed + +- Use the next generation `New Workflow` UI by default [#3718](https://github.com/chaos-mesh/chaos-mesh/pull/3718) +- StressChaos: Support cgroup v2 for docker and crio [#3698](https://github.com/chaos-mesh/chaos-mesh/pull/3698) + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Remove the explicit use of pingcap/log [#3674](https://github.com/chaos-mesh/chaos-mesh/pull/3674) +- Fix typo in controller error message [#3704](https://github.com/chaos-mesh/chaos-mesh/pull/3704) +- Fix panic when logging, log kvs as pair [#3716](https://github.com/chaos-mesh/chaos-mesh/pull/3716) +- Fix timechaos not injected into the child process [#3725](https://github.com/chaos-mesh/chaos-mesh/pull/3725) +- Ignore `ScheduleSkipRemoveHistory` events to fix the memory of controller-manager keep increasing [#3761](https://github.com/chaos-mesh/chaos-mesh/issues/3761) +- Update `is mandatory` to true in a swagger comment [#3743](https://github.com/chaos-mesh/chaos-mesh/pull/3743) +- Enable mode when creating PhysicalMachineChaos with addresses in UI [#3797](https://github.com/chaos-mesh/chaos-mesh/pull/3797) + +### Security + +- Sign images and generate sbom when uploading images in CI [#3766](https://github.com/chaos-mesh/chaos-mesh/pull/3766) + +## [2.4.2] - 2022-11-07 + +### Added + +- Nothing + +### Changed + +- Nothing + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Fix timechaos not injected into the child process [#3730](https://github.com/chaos-mesh/chaos-mesh/pull/3730) +- Update `is mandatory` to true in a swagger comment [#3743](https://github.com/chaos-mesh/chaos-mesh/pull/3743) + +### Security + +- Nothing + +## [2.4.1] - 2022-09-27 + +### Added + +- Nothing + +### Changed + +- Nothing + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Fix: mark 2.4.1 not as pre-release version[#3679](https://github.com/chaos-mesh/chaos-mesh/pull/3679) + +### Security + +- Nothing + +## [2.4.0] - 2022-09-23 + +### Added + +- Add support for `PhysicalMachine` in UI [#3624](https://github.com/chaos-mesh/chaos-mesh/pull/3624) + +### Changed + +- Replace io/ioutil package with os package. [#3539](https://github.com/chaos-mesh/chaos-mesh/pull/3539) +- Refine logging in pkg/dashboard/apiserver/event, moved package level variable log into struct Service as a field. [#3528](https://github.com/chaos-mesh/chaos-mesh/pull/3528) +- Refine logging in pkg/dashboard/apiserver/auth/gcp, moved package level variable log into struct Service as a field [#3527](https://github.com/chaos-mesh/chaos-mesh/pull/3527) +- Change e2e config settings to append "pause image" args. [#3567](https://github.com/chaos-mesh/chaos-mesh/pull/3567) +- Update display of disabled scope in UI [#3621](https://github.com/chaos-mesh/chaos-mesh/pull/3621) +- Make the Scope render conditionally [#3622](https://github.com/chaos-mesh/chaos-mesh/pull/3622) +- Refine logging, remove the usage of klog in chaosctl [#3628](https://github.com/chaos-mesh/chaos-mesh/pull/3628) +- Dashboard: Fix rbac.yaml for token generation verbs/resources [#3370](https://github.com/chaos-mesh/chaos-mesh/pull/3370) +- Refine logging, remove the usage of klog in event recorder [#3629](https://github.com/chaos-mesh/chaos-mesh/pull/3629) +- Use int64 to restore latency for BlockChaos [#3638](https://github.com/chaos-mesh/chaos-mesh/pull/3638) +- Remove CRD v1beta1 support [#3630](https://github.com/chaos-mesh/chaos-mesh/pull/3630) + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Fix NetworkChaos fail with @ifXX in the device [#3605](https://github.com/chaos-mesh/chaos-mesh/pull/3605) +- Fix BlockChaos can't show Chinese name. [#3536](https://github.com/chaos-mesh/chaos-mesh/pull/3536) +- Add `omitempty` JSON tag to optional fields of the CRD objects. [#3531](https://github.com/chaos-mesh/chaos-mesh/pull/3531) +- Fix "sidecar config" e2e test cases run failed in some scenario.[#3564](https://github.com/chaos-mesh/chaos-mesh/pull/3564) +- Fix Integration test with bumping kubectl version. [#3589](https://github.com/chaos-mesh/chaos-mesh/pull/3589) + +### Security + +- Nothing + +## [2.3.3] - 2022-11-07 + +### Added + +- Nothing + +### Changed + +- Nothing + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Remove `limit` action of `BlockChaos` in the dashboard [#3655](https://github.com/chaos-mesh/chaos-mesh/pull/3655) +- Sync PhysicalMachineChaos to API client and forms [#3660](https://github.com/chaos-mesh/chaos-mesh/pull/3660) +- Fix timechaos not injected into the child process [#3729](https://github.com/chaos-mesh/chaos-mesh/pull/3729) +- Update `is mandatory` to true in a swagger comment [#3743](https://github.com/chaos-mesh/chaos-mesh/pull/3743) + +### Security + +- Nothing + +## [2.3.2] - 2022-09-20 + +### Added + +- Nothing + +### Changed + +- Use int64 to restore latency for BlockChaos [#3638](https://github.com/chaos-mesh/chaos-mesh/pull/3638) + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Fix: update helm chart annotation artifacthub.io/prerelease to false [#3626](https://github.com/chaos-mesh/chaos-mesh/pull/3626) + +### Security + +- Nothing + +## [2.3.1] - 2022-09-02 + +### Added + +- Nothing + +### Changed + +- Nothing + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Protect chaos available namespace and filter namespaces if needed [#3473](https://github.com/chaos-mesh/chaos-mesh/pull/3473) +- Respect flag `enableProfiling` and do not register profiler endpoints when it's false [#3474](https://github.com/chaos-mesh/chaos-mesh/pull/3474) +- Fix the blank screen after creating chaos experiment with "By YAML" [#3489](https://github.com/chaos-mesh/chaos-mesh/pull/3489) +- Update hint text about the manual token generating process for Kubernetes 1.24+ [#3505](https://github.com/chaos-mesh/chaos-mesh/pull/3505) +- Fix IOChaos `containerNames` field in UI [#3533](https://github.com/chaos-mesh/chaos-mesh/pull/3533) +- Fix BlockChaos can't show Chinese name. [#3536](https://github.com/chaos-mesh/chaos-mesh/pull/3536) +- Fix recover bug when setting force recover to true [#3578](https://github.com/chaos-mesh/chaos-mesh/pull/3578) +- Fix generate token failed on chaos dashboard [#3595](https://github.com/chaos-mesh/chaos-mesh/pull/3595) + +### Security + +- Nothing + +## [2.3.0] - 2022-07-29 + +### Added + +- Add more status for record [#3170](https://github.com/chaos-mesh/chaos-mesh/pull/3170) +- Add `chaosDaemon.updateStrategy` to Helm chart to allow configuring `DaemonSetUpdateStrategy` for chaos-daemon [#3108](https://github.com/chaos-mesh/chaos-mesh/pull/3108) +- Add AArch64 support for TimeChaos [#3088](https://github.com/chaos-mesh/chaos-mesh/pull/3088) +- Add integration test and link test on arm [#3177](https://github.com/chaos-mesh/chaos-mesh/pull/3177) +- Add `spec.privateKey.rotationPolicy` to Certificates, to comply with requirements in cert-manager 1.8 [#3325](https://github.com/chaos-mesh/chaos-mesh/pull/3325) +- Add `clusterregistry` package to help developers to develop multi-cluster reconciler [#3342](https://github.com/chaos-mesh/chaos-mesh/pull/3342) +- Support `Suspend` in next generation `New Workflow`'s UI [#3254](https://github.com/chaos-mesh/chaos-mesh/pull/3254) +- Add helm annotations for Artifact Hub [#3355](https://github.com/chaos-mesh/chaos-mesh/pull/3355) +- Add implementation of blockchaos in chaos-daemon [#2907](https://github.com/chaos-mesh/chaos-mesh/pull/2907) +- Bump chaos-tproxy to v0.5.1 [#3412](https://github.com/chaos-mesh/chaos-mesh/pull/3412) +- Allow importing external workflows and copying flow nodes in next generation `New Workflow` [#3368](https://github.com/chaos-mesh/chaos-mesh/pull/3368) +- Add `QPS` and `Burst` for Chaos Dashboard Configuration [#3476](https://github.com/chaos-mesh/chaos-mesh/pull/3476) +- Add guide and example for monitoring Chaos Mesh [#3030](https://github.com/chaos-mesh/chaos-mesh/pull/3030) +- Support `KernelChaos` in `AutoForm` [#3449](https://github.com/chaos-mesh/chaos-mesh/pull/3449) +- Sync latest Chaosd and PhysicalMachineChaos [#3477](https://github.com/chaos-mesh/chaos-mesh/pull/3477) +- Add accept-tcp-flag to network delay in PysicalMachineChaos [#3588](https://github.com/chaos-mesh/chaos-mesh/pull/3588) + +### Changed + +- Helm charts: update validate-auth to chaos-mesh-validation-auth [#3193](https://github.com/chaos-mesh/chaos-mesh/pull/3193) +- Helm charts: support latest api version of dashboard ingress [#3066](https://github.com/chaos-mesh/chaos-mesh/pull/3066) +- Update shell script to support shellchecks [#3230](https://github.com/chaos-mesh/chaos-mesh/pull/3230) +- CI: build dev-env and build-env for e2e tests if required [#3264](https://github.com/chaos-mesh/chaos-mesh/pull/3264) +- CI: version unrelated manifests [#3293](https://github.com/chaos-mesh/chaos-mesh/pull/3293) +- Bump chaos-tproxy to v0.4.6 [#3272](https://github.com/chaos-mesh/chaos-mesh/pull/3272) +- Helm charts: using 0.0.0 as version and appVersion [#3311](https://github.com/chaos-mesh/chaos-mesh/pull/3311) +- Add a comment to the flag size of memory stress in the dashboard [#3359](https://github.com/chaos-mesh/chaos-mesh/pull/3359) +- Refine logging in pkg/dashboard/store, removed global the log [#3143](https://github.com/chaos-mesh/chaos-mesh/pull/3143) +- Renamed namespace from chaos-testing to chaos-mesh [#3353](https://github.com/chaos-mesh/chaos-mesh/pull/3353) +- Use ContainerSelector in kernel chaos [#3395](https://github.com/chaos-mesh/chaos-mesh/pull/3395) +- Make possible to have more than one dns chaos server [#3381](https://github.com/chaos-mesh/chaos-mesh/pull/3381) +- Helm charts: Relax allowedHostPaths in chaos-daemon PSP [#3350](https://github.com/chaos-mesh/chaos-mesh/pull/3350) +- Run build image ci on self-hosted machine [#3429](https://github.com/chaos-mesh/chaos-mesh/pull/3429) +- Simplified logic and add test case about finalizers. [#3422](https://github.com/chaos-mesh/chaos-mesh/pull/3422) +- Update API requests with OpenAPI generated client [#2926](https://github.com/chaos-mesh/chaos-mesh/pull/2926) +- Implement some missing methods in ctrl server [#3462](https://github.com/chaos-mesh/chaos-mesh/pull/3462) +- Use `net.Interfaces()` to implement `getAllInterfaces()` [#3484](https://github.com/chaos-mesh/chaos-mesh/pull/3484) + +### Deprecated + +- Nothing + +### Removed + +- Removed extra import of common pkg in chaosctl/cmd/logs.go +- Removed unused local function from statuscheck/manager.go [#3228](https://github.com/chaos-mesh/chaos-mesh/pull/3228) +- Removed ui build and test for arm64 [#3305](https://github.com/chaos-mesh/chaos-mesh/pull/3305) +- Remove sed need (SC2001) [#3248](https://github.com/chaos-mesh/chaos-mesh/pull/3248) +- Removed not used clientset in cmd/chaos-controller-manager/main.go [#3334](https://github.com/chaos-mesh/chaos-mesh/pull/3334) +- Removed not used globalCacheReader in cmd/chaos-controller-manager/provider/controller.go [#3343](https://github.com/chaos-mesh/chaos-mesh/pull/3343) +- Removed unsupported action comments of blockchaos [#3435](https://github.com/chaos-mesh/chaos-mesh/pull/3435) + +### Fixed + +- Update description of memory stressors [#3225](https://github.com/chaos-mesh/chaos-mesh/pull/3225) +- Isolate `target` field and `Scope` when creating `NetworkChaos` in UI [#3223](https://github.com/chaos-mesh/chaos-mesh/issues/3221) +- Add arm64 architecture to ci_skip to pass required test [#3305](https://github.com/chaos-mesh/chaos-mesh/pull/3305) +- Adapt install.sh for kubectl/kubernetes cluster greater than 1.24 [#3177](https://github.com/chaos-mesh/chaos-mesh/pull/3177) +- SC2166: Use || or && rather than -o or -a [#3235](https://github.com/chaos-mesh/chaos-mesh/pull/3235) +- SC2206: Use quote to prevent word splitting/globbing [#3234](https://github.com/chaos-mesh/chaos-mesh/pull/3234) +- Fix make check does not respect the env-images.yaml [#3210] () +- SC2004: Remove unnecessary $ on arithmetic variables [#3247](https://github.com/chaos-mesh/chaos-mesh/pull/3247) +- PhysicalMachineChaos: update stress options type [#3347](https://github.com/chaos-mesh/chaos-mesh/pull/3347) +- PhysicalMachineChaos: remove validate for IP and host for delay, loss, duplicate, corruption [#3483](https://github.com/chaos-mesh/chaos-mesh/pull/3483) +- StressChaos: run `pause` before `choom` [#3405](https://github.com/chaos-mesh/chaos-mesh/pull/3405) +- JVMChaos: update the error message that can be ignored [#3415](https://github.com/chaos-mesh/chaos-mesh/pull/3415) +- Fix Workflow Validating Webhook Panic [#3413](https://github.com/chaos-mesh/chaos-mesh/pull/3413) +- Overwrite $IMAGE_BUILD_ENV_TAG with $IMAGE_TAG-$ARCH in `upload_env_image.yml` github action [#3444](https://github.com/chaos-mesh/chaos-mesh/pull/3444) +- Add a judgement of `enterNS` in `getAllInterfaces()` [#3459](https://github.com/chaos-mesh/chaos-mesh/pull/3459) +- Fix JVMChaos loading missing jar file for injection [#3491](https://github.com/chaos-mesh/chaos-mesh/pull/3491) + +### Security + +- Nothing + +## [2.2.3] - 2022-08-04 + +### Added + +- Add `QPS` and `Burst` for Chaos Dashboard Configuration [#3476](https://github.com/chaos-mesh/chaos-mesh/pull/3476) + +### Changed + +- Implement some missing methods in ctrl server [#3470](https://github.com/chaos-mesh/chaos-mesh/pull/3470) + +### Deprecated + +- Nothing + +### Changed + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Protect chaos available namespace and filter namespaces if needed [#3473](https://github.com/chaos-mesh/chaos-mesh/pull/3473) +- Respect flag `enableProfiling` and do not register profiler endpoints when it's false [#3474](https://github.com/chaos-mesh/chaos-mesh/pull/3474) +- Fix the blank screen after creating chaos experiment with "By YAML" [#3489](https://github.com/chaos-mesh/chaos-mesh/pull/3489) +- Update hint text about the manual token generating process for Kubernetes 1.24+ [#3505](https://github.com/chaos-mesh/chaos-mesh/pull/3505) + +### Security + +- Nothing + +## [2.2.2] - 2022-07-07 + +### Changed + +- Bump chaos-tproxy to v0.5.1 [#3426](https://github.com/chaos-mesh/chaos-mesh/pull/3426) +- Run build image ci on self-hosted machine [#3429](https://github.com/chaos-mesh/chaos-mesh/pull/3429) + +## [2.2.1] - 2022-06-29 + +### Added + +- JVMChaos: support inject fault into MySQL client [#3189](https://github.com/chaos-mesh/chaos-mesh/pull/3189) + +### Changed + +- Nothing + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- PhysicalMachineChaos: update stress options type [#3354](https://github.com/chaos-mesh/chaos-mesh/pull/3354) +- StressChaos: run `pause` before `choom` [#3405](https://github.com/chaos-mesh/chaos-mesh/pull/3405) + +### Security + +- Nothing + +## [2.2.0] - 2022-04-29 + +### Added + +- Add metrics for archived objects in chaos-dashboard [#2568](https://github.com/chaos-mesh/chaos-mesh/pull/2568) +- Add metrics for iptables, ipset and tc metrics in chaos-daemon [#2540](https://github.com/chaos-mesh/chaos-mesh/pull/2540) +- Add metrics for emitted event counter in chaos-controller-manager [#2435](https://github.com/chaos-mesh/chaos-mesh/pull/2435) +- Add metrics for grpc client [#2458](https://github.com/chaos-mesh/chaos-mesh/pull/2458) +- Add metrics for grpc and HTTP request duration histogram [#2543](https://github.com/chaos-mesh/chaos-mesh/pull/2543) +- Add metrics for bpm controlled processes [#2497](https://github.com/chaos-mesh/chaos-mesh/pull/2497) +- Provide additional printer columns for `action` and `duration` [#2526](https://github.com/chaos-mesh/chaos-mesh/pull/2526) +- Add PhysicalMachine CRD [#2587](https://github.com/chaos-mesh/chaos-mesh/pull/2587) +- New command `physical-machine` to `chaosctl` [#2624](https://github.com/chaos-mesh/chaos-mesh/pull/2624) +- Add status "Deleting" for chaos experiments on Chaos Dashboard [#2708](https://github.com/chaos-mesh/chaos-mesh/pull/2708) +- Add time skew for gettimeofday [#2742](https://github.com/chaos-mesh/chaos-mesh/pull/2742) +- Add support of the Unified cgroup mode (tested with containerd runtime only) for linux stress experiments [#2928](https://github.com/chaos-mesh/chaos-mesh/pull/2928) +- Add `StatusCheck` CRD [#2954](https://github.com/chaos-mesh/chaos-mesh/pull/2954) +- Add support for declaring ports in external targets in NetworkChaos experiments [#2932](https://github.com/chaos-mesh/chaos-mesh/pull/2932) +- Add forced recovery of httpchaos, iochaos, stresschaos, and networkchaos for chaosctl [#2992](https://github.com/chaos-mesh/chaos-mesh/pull/2992) +- Add namespace and pod name in failed event for podxxxchaos crd [#3178](https://github.com/chaos-mesh/chaos-mesh/pull/3178) +- Add next generation `New Workflow` in UI [#3185](https://github.com/chaos-mesh/chaos-mesh/pull/3185) +- JVMChaos: support inject fault into MySQL client [#3189](https://github.com/chaos-mesh/chaos-mesh/pull/3189) + +### Changed + +- Use pipeline controller to serialize common controllers [#2465](https://github.com/chaos-mesh/chaos-mesh/pull/2465) +- Enable mTLS between chaos-controller-manager and chaosd [#2580](https://github.com/chaos-mesh/chaos-mesh/pull/2580) +- Rename Physics to Host in Chaos Dashboard [#2645](https://github.com/chaos-mesh/chaos-mesh/pull/2645) +- Retry oneshot chaos if it's not selected [#2618](https://github.com/chaos-mesh/chaos-mesh/pull/2618) +- Bump gopsutil to v3 [#2681](https://github.com/chaos-mesh/chaos-mesh/pull/2681) +- Add prefix for identifier of toda and tproxy in bpm [#2673](https://github.com/chaos-mesh/chaos-mesh/pull/2673) +- Bump toda to v0.2.2 [#2747](https://github.com/chaos-mesh/chaos-mesh/pull/2747) +- Bump go to 1.17 [#2754](https://github.com/chaos-mesh/chaos-mesh/pull/2754) +- Use github.com/pkg/errors to replace fmt.Errorf and "errors" [#2779](https://github.com/chaos-mesh/chaos-mesh/pull/2779) +- Kill chaos-tproxy while failing to apply config [#2672](https://github.com/chaos-mesh/chaos-mesh/pull/2672) +- JVMChaos: ignore AgentLoadException when install agent [#2701](https://github.com/chaos-mesh/chaos-mesh/pull/2701) +- Bump container-runtime to v0.11.0 [#2778](https://github.com/chaos-mesh/chaos-mesh/pull/2778) +- Bump kubernetes dependencies to v1.23.1 [#2778](https://github.com/chaos-mesh/chaos-mesh/pull/2778) +- Removed docker registry mirror [#2797](https://github.com/chaos-mesh/chaos-mesh/pull/2797) +- Use OpenAPI definitions to generate API Client and Form data in UI [2770](https://github.com/chaos-mesh/chaos-mesh/pull/2770) +- Refine logging in pkg/selector/pod [#3002](https://github.com/chaos-mesh/chaos-mesh/pull/3002) +- Add `envFollowKubernetesPattern` to handle k8s-like format env in helm templates [2955](https://github.com/chaos-mesh/chaos-mesh/pull/2955) +- Bump chaos-tproxy to v0.4.5 [#2555](https://github.com/chaos-mesh/chaos-mesh/pull/2555) +- Re-implement chaosctl based on ctrlserver [#2950](https://github.com/chaos-mesh/chaos-mesh/pull/2950) +- Fix wrong zero value of httpchaos replace-body-action[#2990](https://github.com/chaos-mesh/chaos-mesh/pull/2990) +- Bump gqlgen to v0.17.2 [#3038](https://github.com/chaos-mesh/chaos-mesh/pull/3038) +- Bump go to v1.18 [#3055](https://github.com/chaos-mesh/chaos-mesh/pull/3055) +- Bump toda to v0.2.3 [#3131](https://github.com/chaos-mesh/chaos-mesh/pull/3131) +- refactor: rename reconcileContext to reconcileInfo [#3154](https://github.com/chaos-mesh/chaos-mesh/pull/3154) +- Migrate e2e tests from self-hosted Jenkins to Github Action [#2986](https://github.com/chaos-mesh/chaos-mesh/pull/2986) +- Bump minimist from 1.2.5 to 1.2.6 in /ui [#3058](https://github.com/chaos-mesh/chaos-mesh/pull/3058) +- Specify image tag of `build-env` and `dev-env` for each branch [#3071](https://github.com/chaos-mesh/chaos-mesh/pull/3071) +- Specify image tag in e2e tests [#3147](https://github.com/chaos-mesh/chaos-mesh/pull/3147) +- Must update CHANGELOG [#3148](https://github.com/chaos-mesh/chaos-mesh/pull/3148) +- Use chaosDaemon.mtls.enabled instead of dashboard.securityMode for chaos-daemon mtls [#3168](https://github.com/chaos-mesh/chaos-mesh/pull/3168) +- Helm charts: component chaos-dashboard use certain service account and roles [#3145](https://github.com/chaos-mesh/chaos-mesh/pull/3145) +- Refactor helm charts template, split out webhook configuration and secrets [#3159](https://github.com/chaos-mesh/chaos-mesh/pull/3159) +- Helm charts: apply webhook.FailurePolicy to all the webhooks with default value `Fail` [#3184](https://github.com/chaos-mesh/chaos-mesh/pull/3184) +- Bump memStress from v0.2.1 to v0.3 [#3186](https://github.com/chaos-mesh/chaos-mesh/pull/3186) +- Helm charts: configure ca bundle for webhook explicitly [#3190](https://github.com/chaos-mesh/chaos-mesh/pull/3190) +- Refine logging in pkg/selector/generic/namespace [#3214](https://github.com/chaos-mesh/chaos-mesh/pull/3214) + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Unable to load from saved objects [#2585](https://github.com/chaos-mesh/chaos-mesh/pull/2585) +- Fix helm install error [#2591](https://github.com/chaos-mesh/chaos-mesh/pull/2591) +- Fix helm conditions in ingress [#2604](https://github.com/chaos-mesh/chaos-mesh/pull/2604) +- Fix typo in NewExperiment [#2535](https://github.com/chaos-mesh/chaos-mesh/pull/2535) +- Fix chaos-kernel build, mark bcc version [#2693](https://github.com/chaos-mesh/chaos-mesh/pull/2693) +- Fix wrong field name of PhysicalMachineChaos on Chaos Dashboard [#2724](https://github.com/chaos-mesh/chaos-mesh/pull/2724) +- Fix field descriptions of GCPChaos [#2791](https://github.com/chaos-mesh/chaos-mesh/pull/2791) +- Fix `real_gettimeofday` on arm64 [#2849](https://github.com/chaos-mesh/chaos-mesh/pull/2849) +- Fix Github Action `upload-image` [#2935](https://github.com/chaos-mesh/chaos-mesh/pull/2935) +- Fix JVMChaos to handle the situation that the container which holds the JVM rules has been deleted [#2981](https://github.com/chaos-mesh/chaos-mesh/pull/2981) +- Fix typo in comments for Chaos API [#3109](https://github.com/chaos-mesh/chaos-mesh/pull/3109) + +### Security + +- Nothing + +## [v2.1.8] - 2022-08-30 + +### Added + +- Nothing + +### Changed + +- Nothing + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Fix recover bug when setting force recover to true [#3578](https://github.com/chaos-mesh/chaos-mesh/pull/3578) +- Uniformly use Enter to add item in LabelField [#3580](https://github.com/chaos-mesh/chaos-mesh/pull/3580) + +## [2.1.7] - 2022-07-29 + +### Added + +- Add `QPS` and `Burst` for Chaos Dashboard Configuration [#3476](https://github.com/chaos-mesh/chaos-mesh/pull/3476) + +### Changed + +- Nothing + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Nothing + +## [2.1.6] - 2022-07-22 + +### Added + +- Add e2e build image cache [#3097](https://github.com/chaos-mesh/chaos-mesh/pull/3151) +- PhysicalMachineChaos: add recover command in process [#3468](https://github.com/chaos-mesh/chaos-mesh/pull/3468) + +### Changed + +- Must update CHANGELOG [#3181](https://github.com/chaos-mesh/chaos-mesh/pull/3181) + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Fix: find the correct pid by CommName [#3336](https://github.com/chaos-mesh/chaos-mesh/pull/3336) + +### Security + +- Nothing + +## [2.1.5] - 2022-04-18 + +### Added + +- Nothing + +### Changed + +- Migrate e2e tests from self-hosted Jenkins to Github Action [#2986](https://github.com/chaos-mesh/chaos-mesh/pull/2986) +- Bump minimist from 1.2.5 to 1.2.6 in /ui [#3058](https://github.com/chaos-mesh/chaos-mesh/pull/3058) +- Specify image tag of `build-env` and `dev-env` for each branch [#3071](https://github.com/chaos-mesh/chaos-mesh/pull/3071) +- Bump toda to v0.2.3 [#3131](https://github.com/chaos-mesh/chaos-mesh/pull/3131) +- Specify image tag in e2e tests [#3147](https://github.com/chaos-mesh/chaos-mesh/pull/3147) + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Fix `real_gettimeofday` on arm64 [#2849](https://github.com/chaos-mesh/chaos-mesh/pull/2849) +- Fix Github Action `upload-image` [#2935](https://github.com/chaos-mesh/chaos-mesh/pull/2935) +- Fix JVMChaos to handle the situation that the container which holds the JVM rules has been deleted [#2981](https://github.com/chaos-mesh/chaos-mesh/pull/2981) +- Fix typo in comments for Chaos API [#3109](https://github.com/chaos-mesh/chaos-mesh/pull/3109) + +### Security + +- Nothing + +## [2.1.4] - 2022-03-21 + +### Added + +- Add time skew for gettimeofday [#2742](https://github.com/chaos-mesh/chaos-mesh/pull/2742) + +### Changed + +- Removed docker registry mirror [#2797](https://github.com/chaos-mesh/chaos-mesh/pull/2797) + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Fix default value for concurrencyPolicy [#2622](https://github.com/chaos-mesh/chaos-mesh/pull/2622) +- Enable the webhooks for `Schedule` and `Workflow` [#2622](https://github.com/chaos-mesh/chaos-mesh/pull/2622) +- Fix PhysicalMachineChaos to make it able to create network bandwidth experiment. [#2850](https://github.com/chaos-mesh/chaos-mesh/pull/2850) +- Fix workflow emit new events after accomplished [#2911](https://github.com/chaos-mesh/chaos-mesh/pull/2911) +- Fix human unreadable logging timestamp [#2808](https://github.com/chaos-mesh/chaos-mesh/pull/2808) [#2902](https://github.com/chaos-mesh/chaos-mesh/pull/2902) [#2973](https://github.com/chaos-mesh/chaos-mesh/pull/2973) +- Fix default value of percent field in iochaos [#3018](https://github.com/chaos-mesh/chaos-mesh/pull/3018) +- Fix the unexpected CPU stress for StressChaos with cpu resource limit [#3102](https://github.com/chaos-mesh/chaos-mesh/pull/3102) +- Fix the bug that create JVMChaos failed in workflow [#3156](https://github.com/chaos-mesh/chaos-mesh/pull/3156) + +### Security + +- Nothing + +## [2.1.3] - 2022-01-27 + +### Added + +- Add status "Deleting" for chaos experiments on Chaos Dashboard [#2708](https://github.com/chaos-mesh/chaos-mesh/pull/2708) + +### Changed + +- Add prefix for identifier of toda and tproxy in bpm [#2673](https://github.com/chaos-mesh/chaos-mesh/pull/2673) +- Bump toda to v0.2.2 [#2747](https://github.com/chaos-mesh/chaos-mesh/pull/2747) +- Bump go to 1.17 [#2754](https://github.com/chaos-mesh/chaos-mesh/pull/2754) +- JVMChaos ignore AgentLoadException when install agent [#2701](https://github.com/chaos-mesh/chaos-mesh/pull/2701) +- Bump container-runtime to v0.11.0 [#2807](https://github.com/chaos-mesh/chaos-mesh/pull/2807) +- Bump kubernetes dependencies to v1.23.1 [#2807](https://github.com/chaos-mesh/chaos-mesh/pull/2807) +- Kill chaos-tproxy while failing to apply config [#2672](https://github.com/chaos-mesh/chaos-mesh/pull/2672) + +### Fixed + +- Fix wrong field name of PhysicalMachineChaos on Chaos Dashboard [#2724](https://github.com/chaos-mesh/chaos-mesh/pull/2724) +- Fix field descriptions of GCPChaos [#2791](https://github.com/chaos-mesh/chaos-mesh/pull/2791) +- Fix chaos experiment "not found" on Chaos Dashboard [#2698](https://github.com/chaos-mesh/chaos-mesh/pull/2698) + +## [2.1.2] - 2021-12-29 + +### Changed + +- Provide additional print columns for chaos experiments [#2526](https://github.com/chaos-mesh/chaos-mesh/pull/2526) +- Refactor pkg/time [#2570](https://github.com/chaos-mesh/chaos-mesh/pull/2570) +- Rename “physic” to “host” on Chaos Dashboard [#2645](https://github.com/chaos-mesh/chaos-mesh/pull/2645) +- Restructure UI codebase [#2590](https://github.com/chaos-mesh/chaos-mesh/pull/2590) +- Upgrade UI dependencies [#2685](https://github.com/chaos-mesh/chaos-mesh/pull/2685) +- Set default selector mode from “one” to “all” [#2680](https://github.com/chaos-mesh/chaos-mesh/pull/2792) +- Workflow now ordered by creation time [#2680](https://github.com/chaos-mesh/chaos-mesh/pull/2680) +- Set up codecov for testing coverage reports [#2679](https://github.com/chaos-mesh/chaos-mesh/pull/2679) +- Speed up e2e tests [#2617](https://github.com/chaos-mesh/chaos-mesh/pull/2617) [#2702](https://github.com/chaos-mesh/chaos-mesh/pull/2702) + +### Fixed + +- Fixed: error when using Schedule and PodChaos for injecting PodChaos as a cron job [#2618](https://github.com/chaos-mesh/chaos-mesh/pull/2618) +- Fixed: chaos-kernel build failure [#2693](https://github.com/chaos-mesh/chaos-mesh/pull/2693) + +## [2.0.7] - 2022-01-27 + +### Added + +- Add status "Deleting" for chaos experiments on Chaos Dashboard [#2708](https://github.com/chaos-mesh/chaos-mesh/pull/2708) + +### Changed + +- Add prefix for identifier of toda and tproxy in bpm [#2673](https://github.com/chaos-mesh/chaos-mesh/pull/2673) +- Kill chaos-tproxy while failing to apply config [#2672](https://github.com/chaos-mesh/chaos-mesh/pull/2672) + +### Fixed + +- Fix chaos experiment "not found" on Chaos Dashboard [#2698](https://github.com/chaos-mesh/chaos-mesh/pull/2698) +- Fix field descriptions of GCPChaos [#2791](https://github.com/chaos-mesh/chaos-mesh/pull/2791) + +## [2.0.6] - 2021-12-29 + +### Changed + +- Provide additional print columns for chaos experiments [#2526](https://github.com/chaos-mesh/chaos-mesh/pull/2526) +- Remove redundant codes [#2704](https://github.com/chaos-mesh/chaos-mesh/pull/2704) +- Speed up e2e tests #2617 [#2718](https://github.com/chaos-mesh/chaos-mesh/pull/2718) + +### Fixed + +- Fixed: error when using Schedule and PodChaos for injecting PodChaos as a cron job [#2618](https://github.com/chaos-mesh/chaos-mesh/pull/2618) +- Fixed: fail to recover when Chaos CR was deleted before appending finalizers [#2624](https://github.com/chaos-mesh/chaos-mesh/pull/2624) +- Fixed: chaos-kernel build failure [#2693](https://github.com/chaos-mesh/chaos-mesh/pull/2693) +- Fixed: Chaos Dashboard panic when creating StressChaos [#2655](https://github.com/chaos-mesh/chaos-mesh/pull/2655) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 389be33305..929070fa4c 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,3 @@ # Chaos Mesh Community Code of Conduct -Chaos Mesh follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). \ No newline at end of file +Chaos Mesh follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 20ffd6bdd2..1126318256 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,40 +6,43 @@ Thanks for your interest in improving the project! This document provides a step Before starting work on something major, please reach out to us via GitHub, Slack, email, etc. We will make sure no one else is already working on it and ask you to open a GitHub issue. Also, we will provide necessary guidance should you need it. -Specifically, if you want to develop a specific chaos type, you may also find [Development Guide](https://chaos-mesh.org/docs/development_guides/development_overview) useful. +Specifically, if you want to develop a specific chaos type, you may also find [Development Guide](https://chaos-mesh.org/docs/developer-guide-overview) useful. ## Submitting a PR If you have a specific idea of a fix or update, follow these steps below to submit a PR: -- [Step 1: Make the change](#step-1-make-the-change) -- [Step 2: Run unit tests](#step-2-run-unit-tests) -- [Step 3: Start Chaos Mesh locally and do manual tests](#step-3-start-chaos-mesh-locally-and-do-manual-tests) -- [Step 4: Commit and push your changes](#step-4-commit-and-push-your-changes) -- [Step 5: Create a pull request](#step-5-create-a-pull-request) -- [Step 6: Get a code review](#step-6-get-a-code-review) +- [Contributing to Chaos Mesh](#contributing-to-chaos-mesh) + - [Communications](#communications) + - [Submitting a PR](#submitting-a-pr) + - [Step 1: Make the change](#step-1-make-the-change) + - [Step 2: Run unit tests](#step-2-run-unit-tests) + - [Step 3: Start Chaos Mesh locally and do manual tests](#step-3-start-chaos-mesh-locally-and-do-manual-tests) + - [Step 4: Commit and push your changes](#step-4-commit-and-push-your-changes) + - [Step 5: Create a pull request](#step-5-create-a-pull-request) + - [Step 6: Get a code review](#step-6-get-a-code-review) ### Step 1: Make the change 1. Fork the Chaos Mesh repo, and then clone it: ```bash - $ export user={your github. profile name} - $ git clone git@github.com:${user}/chaos-mesh.git + export user={your github. profile name} + git clone git@github.com:${user}/chaos-mesh.git ``` 2. Set your cloned local to track the upstream repository: ```bash - $ cd chaos-mesh - $ git remote add upstream https://github.com/chaos-mesh/chaos-mesh + cd chaos-mesh + git remote add upstream https://github.com/chaos-mesh/chaos-mesh ``` 3. Disable pushing to upstream master: ```bash - $ git remote set-url --push upstream no_push - $ git remote -v + git remote set-url --push upstream no_push + git remote -v ``` The output should look like: @@ -54,10 +57,10 @@ If you have a specific idea of a fix or update, follow these steps below to subm 4. Get your local master up-to-date and create your working branch: ```bash - $ git fetch upstream - $ git checkout master - $ git rebase upstream/master - $ git checkout -b myfeature + git fetch upstream + git checkout master + git rebase upstream/master + git checkout -b myfeature ``` 5. Make the change on the code. @@ -67,14 +70,14 @@ If you have a specific idea of a fix or update, follow these steps below to subm If you want to update the `crd.yaml` according the the CRD structs, run the following commands: ```bash - $ make generate - $ make manifests/crd.yaml + make generate + make manifests/crd.yaml ``` 6. Check the code change by running the following command: ```bash - $ make check + make check ``` This will show errors if your code change does not pass the check. (eg: fmt, lint). Please fix them before submitting the PR. @@ -84,8 +87,7 @@ If you have a specific idea of a fix or update, follow these steps below to subm Before running your code in a real Kubernetes cluster, make sure it passes all unit tests: ```bash -$ make ensure-kubebuilder # install some test dependencies -$ make test +make test ``` ### Step 3: Start Chaos Mesh locally and do manual tests @@ -97,16 +99,16 @@ $ make test - Install the above dependencies in `~/local/bin` using [`install.sh`](https://github.com/chaos-mesh/chaos-mesh/blob/master/install.sh): ```bash - $ ./install.sh --local kind --dependency-only + ./install.sh --local kind --dependency-only ``` 2. Make sure the installation in step 1 is successful: ```bash - $ source ~/.bash_profile - $ kind --version + source ~/.bash_profile + kind --version ... - $ kubectl version + kubectl version ... ``` @@ -115,8 +117,7 @@ $ make test Following command will rebuild project code and reinstall chaos mesh. ```bash - # - $ ./hack/local-up-chaos-mesh.sh + ./hack/local-up-chaos-mesh.sh ``` Now you can test your code update on the deployed cluster. @@ -128,21 +129,21 @@ Congratulations! Now you have finished all tests and are ready to commit your co 1. Run the following commands to keep your branch in sync: ```bash - $ git fetch upstream - $ git rebase upstream/master + git fetch upstream + git rebase upstream/master ``` 2. Commit your changes: ```bash - $ git add -A - $ git commit --signoff + git add -A + git commit --signoff ``` 3. Push your changes to the remote branch: ```bash - $ git push -f origin myfeature + git push -f origin myfeature ``` ### Step 5: Create a pull request diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 7468978e32..00778c606b 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -2,55 +2,59 @@ Chaos Mesh is a meritocratic, consensus-based community project. Anyone with an interest in the project can join the community, contribute to the project design and participate in the decision making process. This document describes how that participation takes place and how to set about earning merit within the project community. -# Roles and responsibilities +## Roles and responsibilities -## Users +### Contributor -Users are community members who have a need for the project. They are the most important members of the community, without them, the project would have no purpose. Anyone can be a user, there are no special requirements. +Contributors are community members who contribute in concrete ways to the project. Anyone can contribute to the project and become a contributor, regardless of their skillset. There is no expectation of commitment to the project, no specific skill requirements, and no selection process. There are many ways to contribute to the project, which may be one or more of the following (but not limited to): -The project asks its users to participate in the project and community as much as possible. User contributions enable the project team to ensure that they are satisfying the needs of those users. Common user contributions include (but not limited to): +- Reporting or fixing bugs. +- Identifying requirements, strengths, and weaknesses. +- Improving the Chaos Mesh website. +- Writing documentation. +- Joining discussions on [Twitter](https://twitter.com/chaos_mesh), our community Slack channel [(#project-chaos-mesh)](https://slack.cncf.io/), or at [community meetings](https://docs.google.com/document/d/1H8IfmhIJiJ1ltg-XLjqR_P_RaMHUGrl1CzvHnKM_9Sc/edit). +- Evangelizing about the project (e.g. a link on a website or word-of-mouth awareness raising). -- Evangelising about the project (e.g. a link on a website or word-of-mouth awareness raising). -- Supporting others. -- Informing developers of strengths and weaknesses from a new user’s perspective. -- Providing moral support (a ‘thank you’ goes a long way). -- Providing financial support (the software is open source, but its developers need to eat). +For first-time contributors, it’s recommended to start by going through [Contributing to Chaos Mesh](https://github.com/chaos-mesh/chaos-mesh/blob/master/CONTRIBUTING.md), and joining our community Slack channel. -Users who continue to engage with the project may either be recognized as Chaos Mesh Evangelists or find themselves becoming contributors, as described in the following section. +As one continues to contribute to the project and engage with the community, he/she may at some point become eligible for a Chaos Mesh Member. -## Contributor +### Member -Contributors are community members who contribute in concrete ways to the project. Anyone can contribute to the project and become a contributor, regardless of their skills. There is no expectation of commitment to the project, no specific skill requirements and no selection process. There are many ways to contribute to the project, which may be one or more of the following (but not limited to): +Chaos Mesh [Members](https://github.com/orgs/chaos-mesh/people) are continuously active contributors in the community. There are multiple ways to stay "active" and engaged with us - contributing to codes, raising issues, writing tutorials and case studies, and even answering questions. -- Reporting or fixing bugs. -- Identifying requirements. -- Improving the Chaos Mesh website. -- Assisting with project infrastructure. -- Writing documentation. -- Adding features. -- Answering questions on social platforms such as Twitter, community Slack channel. +To become a Chaos Mesh member, you are expected to: -For details, see [Contributing to Chaos Mesh](https://github.com/chaos-mesh/chaos-mesh/blob/master/CONTRIBUTING.md). For first time contributors, the community Slack channel is the most appropriate place to ask for help. +- Have made multiple contributions, which may be one or more of the following (but not limited to): + - Authored PRs on GitHub. + - Filed, or commented on issues on GitHub. + - Join community discussions (e.g. community meetings, Slack). +- Sponsored by at least 1 Chaos Mesh [maintainer or committer](https://github.com/chaos-mesh/chaos-mesh/blob/master/MAINTAINERS.md). + +Contributors that meet the above requirements will then be invited to the GitHub organization "Chaos Mesh" by a sponsor, and there would be an announcement published in the slack channel [(#project-chaos-mesh)](https://slack.cncf.io/). + +Members are expected to respond to issues and PRs assigned to them, and be the owners of the code or docs they have contributed. Members that have not contributed to the project or community in any way in over 6 months will lose their membership. As one gains experience and familiarity with the project and as their commitment to the community increases, they may find themselves being nominated for committership at some stage. -## Committer +### Committer -Committers are active community members who have shown that they are committed to the continuous development of the project through ongoing engagement with the community. Committership allows contributors to more easily carry on with their project-related activities by giving them direct access to the project’s resources. +Committers are active community members who have shown that they are committed to the continuous development of the project through ongoing engagement with the community. Committership allows contributors to more easily carry on with their project-related activities by giving them direct access to the project’s resources. -Typically, a potential committer will need to show that they have sufficient understanding of the project, its objectives and its strategy. To become a committer, you are expected to: +Typically, a potential committer needs to show that they have a sufficient understanding of the project, its objectives, and its strategy. To become a committer, you are expected to: +- Be a Chaos Mesh member. - Express interest to the existing maintainers that you are interested in becoming a committer. -- Have contributed 6 substantial PRs or above. -- Have above average understanding of the project, its goals and directions. +- Have contributed 6 or more substantial PRs. +- Have an above-average understanding of the project codebase, its goals, and directions. -Contributors that meet the above requirements will be nominated by an existing maintainer to become a committer. The existing maintainers will confer and decide whether to grant committer status or not. +Members that meet the above requirements will be nominated by an existing maintainer to become a committer. It is recommended to describe the reasons for the nomination and the contribution of the nominee in the PR. The existing maintainers will confer and decide whether to grant committer status or not. Committers are expected to review issues and PRs. Their LGTM counts towards the required LGTM count to merge a PR. While committership indicates a valued member of the community who has demonstrated a healthy respect for the project’s aims and objectives, their work continues to be reviewed by the community before acceptance in an official release. A committer who shows an above-average level of contribution to the project, particularly with respect to its strategic direction and long-term health, may be nominated to become a maintainer. This role is described below. -## Maintainer +### Maintainer Maintainers are first and foremost committers that have shown they are committed to the long term success of a project. They are the planners and designers of the Chaos Mesh project. Maintainership is about building trust with the current maintainers of the project and being a person that they can depend on to make decisions in the best interest of the project in a consistent manner. @@ -61,11 +65,11 @@ Committers wanting to become maintainers are expected to: - Demonstrate a deep and comprehensive understanding of Chaos Mesh's architecture, technical goals, and directions. - Actively engage with major Chaos Mesh feature proposals and implementations. -A new maintainer must be nominated by an existing maintainer. The nominating maintainer will create a PR to update the [Maintainers List](https://github.com/chaos-mesh/chaos-mesh/blob/master/MAINTAINERS.md). Upon consensus of incumbent maintainers, the PR will be approved and the new maintainer becomes active. +A new maintainer must be nominated by an existing maintainer. The nominating maintainer will create a PR to update the [Maintainers List](https://github.com/chaos-mesh/chaos-mesh/blob/master/MAINTAINERS.md). It is recommended to describe the reasons for the nomination and the contribution of the nominee in the PR. Upon consensus of incumbent maintainers, the PR will be approved and the new maintainer becomes active. -If a maintainer is no longer interested or cannot perform the maintainer duties listed above, they should volunteer to be moved to emeritus status. In extreme cases this can also occur by a vote of the maintainers per the voting process, as mentioned below. +If a maintainer is no longer interested or cannot perform the maintainer duties listed above, they should volunteer to be moved to [emeritus status](https://github.com/chaos-mesh/chaos-mesh/blob/master/MAINTAINERS.md#emeritus-maintainers). In extreme cases this can also occur by a vote of the maintainers per the voting process, as mentioned below. -# Approving PRs +### Approving PRs PRs may be merged only after receiving at least two approvals (LGTMs) from committers or maintainers. However, maintainers can sidestep this rule under justifiable circumstances. For example: @@ -73,16 +77,26 @@ PRs may be merged only after receiving at least two approvals (LGTMs) from commi - Minor typos or fixes for broken tests. - The change was approved through other means than the standard process. -# Decision Making Process +### Decision Making Process -Ideally, all project decisions are resolved by consensus via a PR or GitHub issue. Any of the day-to-day project maintenance can be done by a [lazy consensus model(https://communitymgt.fandom.com/wiki/Lazy_consensus). +Ideally, all project decisions are resolved by consensus via a PR or GitHub issue. Any of the day-to-day project maintenance can be done by a [lazy consensus model](https://communitymgt.fandom.com/wiki/Lazy_consensus). -Community or project level decisions such as RFC submission, creating a new project, maintainer promotion, and major updates on GOVERNANCE must be brought to broader awareness of the community via community meetings, GitHub discussions, and slack channels. A supermajority (2/3) approval from Maintainers is required for such approvals. +Community or project level decisions such as RFC submission, creating a new project, maintainer promotion, and major updates on GOVERNANCE must be brought to broader awareness of the community via community meetings, GitHub discussions, and slack channels. A supermajority (2/3) approval from Maintainers is required for such approvals. In general, we prefer that technical issues and maintainer membership are amicably worked out between the persons involved. If a dispute cannot be decided independently, the maintainers can be called in to resolve the issue by voting. For voting, a specific statement of what is being voted on should be added to the relevant github issue or PR, and a link to that issue or PR added to the maintainers meeting agenda document. Maintainers should indicate their yes/no vote on that issue or PR, and after a suitable period of time, the votes will be tallied and the outcome noted. Decision making must comply with the [CNCF Code of Conduct](https://github.com/chaos-mesh/chaos-mesh/blob/master/CODE_OF_CONDUCT.md). -## Proposal process +### Proposal process + +We use a Request for Comments (RFC) process for any substantial changes to Chaos Mesh. This process involves an upfront design that will provide increased visibility to the community. If you're considering a PR that will bring in a new feature that may affect how Chaos Mesh is implemented, or may be a breaking change, then you should start with a RFC. The process is documented in the [RFC repository](https://github.com/chaos-mesh/rfcs) and has [a template](https://github.com/chaos-mesh/rfcs/blob/main/template.md) for you to get started. + +### Nomination process + +The following table describes how the nomination is approved. -We use a Request for Comments (RFC) process for any substantial changes to Chaos Mesh. This process involves an upfront design that will provide increased visibility to the community. If you're considering a PR that will bring in a new feature that may affect how Chaos Mesh is implemented, or may be a breaking change, then you should start with a RFC. The process is documented in the [RFC repository](https://github.com/chaos-mesh/rfcs)) and has [a template](https://github.com/chaos-mesh/rfcs/blob/main/template.md) for you to get started. \ No newline at end of file +| Nomination | Description | Approval | Binding Roles | Minimum Length (days) | +| :----------------- | :---------------------------------------------------------------------------------------- | :------------ | :----------------- | :-------------------- | +| New Member | When a new member is proposed, should be only nominated by a committer. | [Lazy Consensus](https://communitymgt.fandom.com/wiki/Lazy_consensus) | Active committers or maintainers | 3 | +| New Committer | When a new committer is proposed, should be only nominated by a maintainer. | [Lazy Consensus](https://communitymgt.fandom.com/wiki/Lazy_consensus) | Active maintainers | 7 | +| New Maintainer | When a new maintainer is proposed, should be only nominated by a maintainer. | Supermajority (2/3) Approval | Active maintainers | 7 | diff --git a/LICENSE b/LICENSE index b67d909100..05414bac8c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Apache License + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ diff --git a/MAINTAINERS.md b/MAINTAINERS.md index df6c4b0494..647391f2e3 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -1,33 +1,51 @@ -# Project Maintainers - This file lists the maintainers and committers of the Chaos Mesh project. In short, maintainers are people who are in charge of the maintenance of the Chaos Mesh project. Committers are active community members who have shown that they are committed to the continuous development of the project through ongoing engagement with the community. For detailed description of the roles, see [Chaos Mesh Governance](https://github.com/chaos-mesh/chaos-mesh/blob/master/GOVERNANCE.md). -The Maintainers of Chaos Mesh, along with their emails, are listed below: +## Maintainers +The Maintainers of Chaos Mesh, along with their emails, are listed below: -Name | Email | Org -----|---|--- -Siddon Tang ([siddontang](https://github.com/siddontang)) | [tl@pingcap.com](mailto:tl@pingcap.com) | [PingCAP](https://www.pingcap.com/) -Qiang Zhou ([zhouqiang-cl](https://github.com/zhouqiang-cl)) | [zhouqiang@pingcap.com](mailto:zhouqiang@pingcap.com) | [PingCAP](https://www.pingcap.com/) -Cwen Yin ([cwen0](https://github.com/cwen0)) | [cwen@pingcap.com](mailto:cwen@pingcap.com) | [PingCAP](https://www.pingcap.com/) -Keao Yang ([YangKeao](https://github.com/YangKeao)) | [yangkeao@pingcap.com](mailto:yangkeao@pingcap.com) | [PingCAP](https://www.pingcap.com/) -Song Gao ([Yisaer](https://github.com/Yisaer)) | [gaosong@pingcap.com](mailto:gaosong@pingcap.com) | [PingCAP](https://www.pingcap.com/) -Calvin Weng ([dcalvin](https://github.com/dcalvin)) | [wenghao@pingcap.com](mailto:wenghao@pingcap.com) | [PingCAP](https://www.pingcap.com/) -Ben Ye ([yeya24](https://github.com/yeya24)) | [yb532204897@gmail.com](mailto:yb532204897@gmail.com) | Individual -Hengliang Tan ([Gallardot](https://github.com/Gallardot)) | [tttick@gmail.com](mailto:tttick@gmail.com) | [Xpeng Motors](https://www.xiaopeng.com/) +| Name  |  Email  |  Org | +| ---------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------ | +| Cwen Yin ([cwen0](https://github.com/cwen0))  |  [cwen@pingcap.com](mailto:cwen@pingcap.com)  |  [PingCAP](https://www.pingcap.com/) | +| Keao Yang ([YangKeao](https://github.com/YangKeao))  |  [yangkeao@pingcap.com](mailto:yangkeao@pingcap.com)  |  [PingCAP](https://www.pingcap.com/) | +| Calvin Weng ([dcalvin](https://github.com/dcalvin))  |  [wenghao@pingcap.com](mailto:wenghao@pingcap.com)  |  [PingCAP](https://www.pingcap.com/) | +| Zhiqiang Zhou ([STRRL](https://github.com/STRRL)) | [im@strrl.dev](mailto:im@strrl.dev) | Freelancer | +| Glen Yang ([g1eny0ung](https://github.com/g1eny0ung)) | [g1enyy0ung@gmail.com](mailto:g1enyy0ung@gmail.com) | [EMQ](https://www.emqx.com/) | +## Committers The Committers of Chaos Mesh, along with their emails, are listed below: -| Name | Email | Org | -|------------------------------|--------------------------|---------| -| Glen Yang ([G1eny0ung](https://github.com/g1eny0ung)) | [yangyue@pingcap.com](mailto:yangyue@pingcap.com) | [PingCAP](https://www.pingcap.com/) | -| Yihao Fu ([fewdan](https://github.com/fewdan)) | [fuyihao@pingcap.com](mailto:fuyihao@pingcap.com) | [PingCAP](https://www.pingcap.com/) | -| Jiaxing Wu ([Colstuwjx](https://github.com/Colstuwjx)) | [wjx_colstu@hotmail.com](mailto:wjx_colstu@hotmail.com) | [Kingnet](https://www.kingnet.com/) | -| Shuyang Wu ([Yiyiyimu](https://github.com/Yiyiyimu)) | [wosoyoung@gmail.com](mailto:wosoyoung@gmail.com) | [APISIX](https://apisix.apache.org/) | -| Shenan Zhang ([Andrewmatilde](https://github.com/Andrewmatilde)) | [zhangshenan@pingcap.com](mailto:zhangshenan@pingcap.com) | [PingCAP](https://www.pingcap.com/) | -| Xiang Wang ([WangXiangUSTC](https://github.com/WangXiangUSTC)) | [wangxiang@pingcap.com](mailto:wangxiang@pingcap.com) | [PingCAP](https://www.pingcap.com/) | -| Wenbo Zhang ([ethercflow](https://github.com/ethercflow)) | [zhangwenbo@pingcap.com](mailto:zhangwenbo@pingcap.com) | [PingCAP](https://www.pingcap.com/) | -| Zhiqiang Zhou ([STRRL](https://github.com/STRRL)) | [zhouzhiqiang@pingcap.com](mailto:zhouzhiqiang@pingcap.com) | [PingCAP](https://www.pingcap.com/) +| Name | Email | Org | +| ---------------------------------------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------- | +| Shenan Zhang ([Andrewmatilde](https://github.com/Andrewmatilde)) | [zhangshenan@pingcap.com](mailto:zhangshenan@pingcap.com) | [PingCAP](https://www.pingcap.com/) | +| Xiang Wang ([WangXiangUSTC](https://github.com/WangXiangUSTC)) | [wangxiang@pingcap.com](mailto:wangxiang@pingcap.com) | [PingCAP](https://www.pingcap.com/) | +| Xianglin Gao ([xlgao-zju](https://github.com/xlgao-zju)) | [xlgao@zju.edu.cn](mailto:xlgao@zju.edu.cn) | [Tencent](https://tencent.com/) | + +## Emeritus Maintainers + +The Emeritus Maintainers of Chaos Mesh, along with their emails, are listed below: + +| Name  |  Email  |  Org | +| ------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------ | +| Siddon Tang ([siddontang](https://github.com/siddontang)) |  [tl@pingcap.com](mailto:tl@pingcap.com)  |  [PingCAP](https://www.pingcap.com/) | +| Qiang Zhou ([zhouqiang-cl](https://github.com/zhouqiang-cl))  |  [zhouqiang@pingcap.com](mailto:zhouqiang@pingcap.com)  |  [PingCAP](https://www.pingcap.com/) | +| Song Gao ([Yisaer](https://github.com/Yisaer))  |  [gaosong@pingcap.com](mailto:gaosong@pingcap.com)  |  [PingCAP](https://www.pingcap.com/) | +| Ben Ye ([yeya24](https://github.com/yeya24))  |  [yb532204897@gmail.com](mailto:yb532204897@gmail.com)  |  [AWS](https://aws.amazon.com/) | +| Hengliang Tan ([Gallardot](https://github.com/Gallardot))  |  [gallardot@apache.org](mailto:gallardot@apache.org)  |  [Xpeng Motors](https://www.xiaopeng.com/) | + +## Emeritus Committers + +The Emeritus Committers of Chaos Mesh, along with their emails, are listed below: + +| Name | Email | Org | +| ---------------------------------------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------- | +| Yihao Fu ([fewdan](https://github.com/fewdan)) | [fuyihao@pingcap.com](mailto:fuyihao@pingcap.com) | [PingCAP](https://www.pingcap.com/) | +| Jiaxing Wu ([Colstuwjx](https://github.com/Colstuwjx)) | [wjx_colstu@hotmail.com](mailto:wjx_colstu@hotmail.com) | [Kingnet](https://www.kingnet.com/) | +| Shuyang Wu ([Yiyiyimu](https://github.com/Yiyiyimu)) | [wosoyoung@gmail.com](mailto:wosoyoung@gmail.com) | [APISIX](https://apisix.apache.org/) | +| Wenbo Zhang ([ethercflow](https://github.com/ethercflow)) | [zhangwenbo@pingcap.com](mailto:zhangwenbo@pingcap.com) | [PingCAP](https://www.pingcap.com/) | +| Shivansh Saini ([shivanshs9](https://github.com/shivanshs9)) | [shivansh.saini.cse17@iitbhu.ac.in](mailto:shivansh.saini.cse17@iitbhu.ac.in) | [Headout](https://github.com/headout) | +| Siyu Chen ([iguoyr](https://github.com/iguoyr)) | [chensiyu@pingcap.com](mailto:chensiyu@pingcap.com) | [PingCAP](https://www.pingcap.com/) | +| Chenxi Li ([Hexilee](https://github.com/Hexilee)) | [lichenxi@pingcap.com](mailto:lichenxi@pingcap.com) | [PingCAP](https://pingcap.com/) | diff --git a/Makefile b/Makefile index 7e511b6e80..d293158654 100644 --- a/Makefile +++ b/Makefile @@ -1,411 +1,326 @@ -# Set DEBUGGER=1 to build debug symbols -LDFLAGS = $(if $(IMG_LDFLAGS),$(IMG_LDFLAGS),$(if $(DEBUGGER),,-s -w) $(shell ./hack/version.sh)) -DOCKER_REGISTRY ?= "localhost:5000" +# If you update this file, please follow +# https://suva.sh/posts/well-documented-makefiles + +## -------------------------------------- +## General +## -------------------------------------- -# SET DOCKER_REGISTRY to change the docker registry -DOCKER_REGISTRY_PREFIX := $(if $(DOCKER_REGISTRY),$(DOCKER_REGISTRY)/,) -DOCKER_BUILD_ARGS := --build-arg HTTP_PROXY=${HTTP_PROXY} --build-arg HTTPS_PROXY=${HTTPS_PROXY} --build-arg UI=${UI} --build-arg SWAGGER=${SWAGGER} --build-arg LDFLAGS="${LDFLAGS}" --build-arg CRATES_MIRROR="${CRATES_MIRROR}" +.DEFAULT_GOAL:=help -GOVER_MAJOR := $(shell go version | sed -E -e "s/.*go([0-9]+)[.]([0-9]+).*/\1/") -GOVER_MINOR := $(shell go version | sed -E -e "s/.*go([0-9]+)[.]([0-9]+).*/\2/") -GO111 := $(shell [ $(GOVER_MAJOR) -gt 1 ] || [ $(GOVER_MAJOR) -eq 1 ] && [ $(GOVER_MINOR) -ge 11 ]; echo $$?) +# Set DEBUGGER=1 to build debug symbols +export LDFLAGS := $(if $(LDFLAGS),$(LDFLAGS),$(if $(DEBUGGER),,-s -w) $(shell ./hack/version.sh)) -IMAGE_TAG := $(if $(IMAGE_TAG),$(IMAGE_TAG),latest) +export IMAGE_TAG ?= latest +export IMAGE_BUILD ?= 1 ROOT=$(shell pwd) -OUTPUT_BIN=$(ROOT)/output/bin -KUSTOMIZE_BIN=$(OUTPUT_BIN)/kustomize -KUBEBUILDER_BIN=$(OUTPUT_BIN)/kubebuilder -KUBECTL_BIN=$(OUTPUT_BIN)/kubectl -HELM_BIN=$(OUTPUT_BIN)/helm - -ifeq ($(GO111), 1) -$(error Please upgrade your Go compiler to 1.11 or higher version) -endif -# Enable GO111MODULE=on explicitly, disable it with GO111MODULE=off when necessary. -export GO111MODULE := on -GOOS := $(if $(GOOS),$(GOOS),"") -GOARCH := $(if $(GOARCH),$(GOARCH),"") -GOENV := GO15VENDOREXPERIMENT="1" CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) -CGOENV := GO15VENDOREXPERIMENT="1" CGO_ENABLED=1 GOOS=$(GOOS) GOARCH=$(GOARCH) +export IMAGE_BUILD_ENV_BUILD ?= 0 +export IMAGE_DEV_ENV_BUILD ?= 0 + +export GOPROXY := $(if $(GOPROXY),$(GOPROXY),https://proxy.golang.org,direct) +GOENV := CGO_ENABLED=0 +CGOENV := CGO_ENABLED=1 GO := $(GOENV) go CGO := $(CGOENV) go -GOTEST := TEST_USE_EXISTING_CLUSTER=false NO_PROXY="${NO_PROXY},testhost" go test -SHELL := bash - -PACKAGE_LIST := echo $$(go list ./... | grep -vE "chaos-mesh/test|pkg/ptrace|zz_generated|vendor") github.com/chaos-mesh/chaos-mesh/api/v1alpha1 +GOTEST := USE_EXISTING_CLUSTER=false NO_PROXY="$(NO_PROXY),testhost" go test +SHELL := bash -# Produce CRDs that work back to Kubernetes 1.11 (no version conversion) -CRD_OPTIONS ?= "crd:trivialVersions=true,preserveUnknownFields=false" +PACKAGE_LIST := echo $$(go list -buildvcs=false ./... | grep -vE "chaos-mesh/test|pkg/ptrace|zz_generated|vendor") $$(cd api && go list -buildvcs=false ./... && cd ../) -# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) -ifeq (,$(shell go env GOBIN)) -GOBIN=$(shell go env GOPATH)/bin -else -GOBIN=$(shell go env GOBIN) -endif - -FAILPOINT_ENABLE := $$(find $$PWD/ -type d | grep -vE "(\.git|bin)" | xargs $(GOBIN)/failpoint-ctl enable) -FAILPOINT_DISABLE := $$(find $$PWD/ -type d | grep -vE "(\.git|bin)" | xargs $(GOBIN)/failpoint-ctl disable) - -GO_BUILD_CACHE ?= $(HOME)/.cache/chaos-mesh +export GO_BUILD_CACHE ?= $(ROOT)/.cache/chaos-mesh BUILD_TAGS ?= -ifeq ($(SWAGGER),1) - BUILD_TAGS += swagger_server -endif - ifeq ($(UI),1) BUILD_TAGS += ui_server endif -CLEAN_TARGETS := +# See https://github.com/chaos-mesh/chaos-mesh/pull/4004 for more details. +ifeq (,$(findstring local/,$(MAKECMDGOALS))) -all: manifests/crd.yaml image -go_build_cache_directory: - mkdir -p $(GO_BUILD_CACHE)/chaos-mesh-gobuild - mkdir -p $(GO_BUILD_CACHE)/chaos-mesh-gopath - -check: fmt vet boilerplate lint generate manifests/crd.yaml tidy - -# Run tests -test: failpoint-enable generate generate-mock manifests test-utils - rm -rf cover.* cover - $(GOTEST) $$($(PACKAGE_LIST)) -coverprofile cover.out.tmp - cat cover.out.tmp | grep -v "_generated.deepcopy.go" > cover.out - @$(FAILPOINT_DISABLE) - -test-utils: timer multithread_tracee +# Each branch should have its own image tag for build-env and dev-env +# Use := with ifeq instead of = for performance issues (simply expanded) +ifeq ($(IMAGE_BUILD_ENV_TAG),) +export IMAGE_BUILD_ENV_TAG := $(shell ./hack/env-image-tag.sh build-env) +endif +ifeq ($(IMAGE_DEV_ENV_TAG),) +export IMAGE_DEV_ENV_TAG := $(shell ./hack/env-image-tag.sh dev-env) +endif -timer: - $(GO) build -ldflags '$(LDFLAGS)' -o bin/test/timer ./test/cmd/timer/*.go +endif -multithread_tracee: test/cmd/multithread_tracee/main.c - cc test/cmd/multithread_tracee/main.c -lpthread -O2 -o ./bin/test/multithread_tracee +BASIC_IMAGE_ENV=IMAGE_DEV_ENV_TAG=$(IMAGE_DEV_ENV_TAG) \ + IMAGE_BUILD_ENV_TAG=$(IMAGE_BUILD_ENV_TAG) \ + IMAGE_TAG=$(IMAGE_TAG) TARGET_PLATFORM=$(TARGET_PLATFORM) \ + GO_BUILD_CACHE=$(GO_BUILD_CACHE) -mockgen: - GO111MODULE=on go get github.com/golang/mock/mockgen@v1.5.0 +RUN_IN_DEV_SHELL=$(shell $(BASIC_IMAGE_ENV)\ + $(ROOT)/build/get_env_shell.py dev-env) +RUN_IN_BUILD_SHELL=$(shell $(BASIC_IMAGE_ENV)\ + $(ROOT)/build/get_env_shell.py build-env) -generate-mock: mockgen - go generate ./pkg/workflow - make fmt vet lint +# See https://github.com/chaos-mesh/chaos-mesh/pull/4004 for more details. +ifeq (,$(findstring local/,$(MAKECMDGOALS))) -coverage: -ifeq ("$(CI)", "1") - @bash <(curl -s https://codecov.io/bash) -f cover.out -t $(CODECOV_TOKEN) -else - mkdir -p cover - gocov convert cover.out > cover.json - gocov-xml < cover.json > cover.xml - gocov-html < cover.json > cover/index.html -endif +# Include generated makefiles. +# These sub makefiles depend on RUN_IN_DEV_SHELL and RUN_IN_BUILD_SHELL, so it should be included after them. +include binary.generated.mk container-image.generated.mk -swagger_spec: -ifeq (${SWAGGER},1) - hack/generate_swagger_spec.sh endif -yarn_dependencies: -ifeq (${UI},1) - cd ui &&\ - yarn install --frozen-lockfile -endif +include local-binary.generated.mk -ui: yarn_dependencies -ifeq (${UI},1) - cd ui &&\ - yarn build - hack/embed_ui_assets.sh -endif +export CLEAN_TARGETS := -watchmaker: - $(CGO) build -ldflags '$(LDFLAGS)' -o bin/watchmaker ./cmd/watchmaker/... +# The help will print out all targets with their descriptions organized bellow their categories. The categories are represented by `##@` and the target descriptions by `##`. +# The awk commands is responsible to read the entire set of makefiles included in this invocation, looking for lines of the file as xyz: ## something, and then pretty-format the target and help. Then, if there's a line with ##@ something, that gets pretty-printed as a category. +# More info over the usage of ANSI control characters for terminal formatting: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters +# More info over awk command: http://linuxcommand.org/lc3_adv_awk.php +# +# Notice that we have a little modification on the awk command to support slash in the recipe name: +# origin: /^[a-zA-Z_0-9-]+:.*?##/ +# modified /^[a-zA-Z_0-9\/\.-]+:.*?##/ +.PHONY: help +help: ## Display this help + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9\/\.-]+:.*?##/ { printf " \033[36m%-21s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) -# Build chaosctl -chaosctl: - $(GO) build -ldflags '$(LDFLAGS)' -o bin/chaosctl ./cmd/chaosctl/*.go +##@ Code generation -# Run against the configured Kubernetes cluster in ~/.kube/config -run: generate fmt vet manifests - $(GO) run ./cmd/controller-manager/main.go +config: SHELL:=$(RUN_IN_DEV_SHELL) +config: images/dev-env/.dockerbuilt ## Generate CRD manifests with controller-gen + cd ./api ;\ + controller-gen crd:ignoreUnexportedFields=true,crdVersions=v1 rbac:roleName=manager-role paths="./..." output:crd:artifacts:config=../config/crd/bases ;\ + rm ../helm/chaos-mesh/crds/* && cp ../config/crd/bases/* ../helm/chaos-mesh/crds -NAMESPACE ?= chaos-testing -# Install CRDs into a cluster -install: manifests - $(KUBECTL_BIN) apply -f manifests/crd.yaml - $(HELM_BIN) upgrade --install chaos-mesh helm/chaos-mesh --namespace=${NAMESPACE} --set registry=${DOCKER_REGISTRY} --set dnsServer.create=true --set dashboard.create=true; +chaos-build: SHELL:=$(RUN_IN_DEV_SHELL) +chaos-build: bin/chaos-builder images/dev-env/.dockerbuilt ## Generate codes for CustomResource Kinds under api/v1alpha1 + bin/chaos-builder -# Generate manifests e.g. CRD, RBAC etc. -config: $(GOBIN)/controller-gen - cd ./api/v1alpha1 ;\ - $< $(CRD_OPTIONS) rbac:roleName=manager-role paths="./..." output:crd:artifacts:config=../../config/crd/bases ;\ - $< $(CRD_OPTIONS) rbac:roleName=manager-role paths="./..." output:crd:artifacts:config=../../helm/chaos-mesh/crds ; +generate: manifests/crd.yaml generate-ctrl swagger_spec generate-deepcopy chaos-build ## Generate codes for codebase, including CRD manifests, chaosctl GraphQL code generation, chaos mesh controller code generation, deepcopy, swager spec. -# Run go fmt against code -fmt: groupimports - $(CGO) fmt ./... +generate-ctrl: SHELL:=$(RUN_IN_DEV_SHELL) +generate-ctrl: images/dev-env/.dockerbuilt generate-deepcopy ## Generate GraphQL schema for chaosctl + $(GO) generate ./pkg/ctrl/server -gosec-scan: $(GOBIN)/gosec - $(GOENV) $< ./api/... ./controllers/... ./pkg/... || echo "*** sec-scan failed: known-issues ***" +.PHONY: generate-makefile +generate-makefile: ## Generate makefile (binary.generated.mk, container-image.generated.mk) + @$(GO) run ./cmd/generate-makefile -groupimports: $(GOBIN)/goimports - $< -w -l -local github.com/chaos-mesh/chaos-mesh . +generate-deepcopy: SHELL:=$(RUN_IN_DEV_SHELL) +generate-deepcopy: images/dev-env/.dockerbuilt chaos-build ## Generate deepcopy files for CRD Kind with controller-gen + cd ./api ;\ + controller-gen object:headerFile=../hack/boilerplate/boilerplate.generatego.txt paths="./..." ; -failpoint-enable: $(GOBIN)/failpoint-ctl -# Converting gofail failpoints... - @$(FAILPOINT_ENABLE) +install.sh: SHELL:=$(RUN_IN_DEV_SHELL) +install.sh: images/dev-env/.dockerbuilt ## Generate install.sh + ./hack/update_install_script.sh -failpoint-disable: $(GOBIN)/failpoint-ctl -# Restoring gofail failpoints... - @$(FAILPOINT_DISABLE) +manifests/crd.yaml: SHELL:=$(RUN_IN_DEV_SHELL) +manifests/crd.yaml: config images/dev-env/.dockerbuilt ## Generate the combined CRD manifests + kustomize build config/default > manifests/crd.yaml -# Run go vet against code -vet: - $(CGOENV) go vet ./... +proto: SHELL:=$(RUN_IN_DEV_SHELL) +proto: images/dev-env/.dockerbuilt ## Generate .go files from .proto files + for dir in pkg/chaosdaemon pkg/chaoskernel ; do\ + protoc -I $$dir/pb $$dir/pb/*.proto -I /usr/local/include --go_out=plugins=grpc:$$dir/pb --go_out=./$$dir/pb ;\ + done -tidy: clean - @echo "go mod tidy" - GO111MODULE=on go mod tidy - git diff -U --exit-code go.mod go.sum +swagger_spec: SHELL:=$(RUN_IN_DEV_SHELL) +swagger_spec: images/dev-env/.dockerbuilt ## Generate OpenAPI/Swagger spec for frontend + swag init -g cmd/chaos-dashboard/main.go --output pkg/dashboard/swaggerdocs --pd --parseInternal -install.sh: - ./hack/update_install_script.sh +##@ Linters, formatters and others -check-install-script: install.sh - git diff -U --exit-code install.sh +check: generate manifests/crd.yaml vet boilerplate lint fmt tidy install.sh helm-values-schema ## Run prerequisite checks for PR -clean: - rm -rf docs/docs.go $(CLEAN_TARGETS) +SKYWALKING_EYES_HEADER = /go/bin/license-eye header -c ./.github/.licenserc.yaml +boilerplate: SHELL:=$(RUN_IN_DEV_SHELL) +boilerplate: images/dev-env/.dockerbuilt + $(SKYWALKING_EYES_HEADER) check -boilerplate: - ./hack/verify-boilerplate.sh +boilerplate-fix: SHELL:=$(RUN_IN_DEV_SHELL) +boilerplate-fix: images/dev-env/.dockerbuilt ## Fix boilerplate + $(SKYWALKING_EYES_HEADER) fix -image: image-chaos-daemon image-chaos-mesh image-chaos-dashboard +fmt: SHELL:=$(RUN_IN_DEV_SHELL) +fmt: groupimports images/dev-env/.dockerbuilt ## Reformat go files with gofmt and goimports + $(CGO) fmt $$($(PACKAGE_LIST)) -e2e-image: image-e2e-helper +gosec-scan: SHELL:=$(RUN_IN_DEV_SHELL) +gosec-scan: images/dev-env/.dockerbuilt + gosec ./api/... ./controllers/... ./pkg/... || echo "*** sec-scan failed: known-issues ***" -GO_TARGET_PHONY := +groupimports: SHELL:=$(RUN_IN_DEV_SHELL) +groupimports: images/dev-env/.dockerbuilt ## Reformat go files with goimports + find . -type f -name '*.go' -not -path '**/zz_generated.*.go' -not -path './.cache/**' | xargs \ + -d $$'\n' -n 10 goimports -w -l -local github.com/chaos-mesh/chaos-mesh -BINARIES := +lint: SHELL:=$(RUN_IN_DEV_SHELL) +lint: images/dev-env/.dockerbuilt ## Lint go files with revive + revive -formatter friendly -config revive.toml $$($(PACKAGE_LIST)) -define COMPILE_GO_TEMPLATE -ifeq ($(IN_DOCKER),1) +tidy: SHELL:=$(RUN_IN_DEV_SHELL) +tidy: images/dev-env/.dockerbuilt ## Run go mod tidy in all submodules + go mod tidy + git diff -U --exit-code go.mod go.sum + cd api; go mod tidy; git diff -U --exit-code go.mod go.sum + cd e2e-test; go mod tidy; git diff -U --exit-code go.mod go.sum + cd e2e-test/cmd/e2e_helper; go mod tidy; git diff -U --exit-code go.mod go.sum -$(1): $(4) -ifeq ($(3),1) - $(CGO) build -ldflags "$(LDFLAGS)" -tags "${BUILD_TAGS}" -o $(1) $(2) -else - $(GO) build -ldflags "$(LDFLAGS)" -tags "${BUILD_TAGS}" -o $(1) $(2) -endif +vet: SHELL:=$(RUN_IN_DEV_SHELL) +vet: images/dev-env/.dockerbuilt ## Lint go files with go vet + $(CGOENV) go vet ./... -endif -GO_TARGET_PHONY += $(1) -endef +helm-values-schema: SHELL:=$(RUN_IN_DEV_SHELL) +helm-values-schema: images/dev-env/.dockerbuilt + helm schema -input helm/chaos-mesh/values.yaml -output helm/chaos-mesh/values.schema.json -BUILD_INDOCKER_ARG := --env IN_DOCKER=1 -ifeq ($(DOCKER_HOST),) - BUILD_INDOCKER_ARG += --volume $(ROOT):/mnt --user $(shell id -u):$(shell id -g) -else - CLEAN_TARGETS += Dockerfile -endif +##@ Common used building targets -ifneq ($(GO_BUILD_CACHE),) - BUILD_INDOCKER_ARG += --volume $(GO_BUILD_CACHE)/chaos-mesh-gopath:/tmp/go - BUILD_INDOCKER_ARG += --volume $(GO_BUILD_CACHE)/chaos-mesh-gobuild:/tmp/go-build -endif +all: manifests/crd.yaml image ## Build all CRD yaml manifests and components container images -define BUILD_IN_DOCKER_TEMPLATE -CLEAN_TARGETS += $(2) -ifneq ($(IN_DOCKER),1) - -$(2): image-build-env go_build_cache_directory - [[ "$(DOCKER_HOST)" == "" ]] || (printf "\ - FROM ${DOCKER_REGISTRY_PREFIX}pingcap/build-env:${IMAGE_TAG} \n\ - RUN rm -rf /mnt \n\ - COPY ./ /mnt \n"\ - > Dockerfile; docker build . -t ${DOCKER_REGISTRY_PREFIX}pingcap/build-env:${IMAGE_TAG}) - - DOCKER_ID=$$$$(docker run -d \ - $(BUILD_INDOCKER_ARG) \ - ${DOCKER_REGISTRY_PREFIX}pingcap/build-env:${IMAGE_TAG} \ - sleep infinity); \ - docker exec --workdir /mnt/ \ - --env IMG_LDFLAGS="${LDFLAGS}" \ - --env UI=${UI} --env SWAGGER=${SWAGGER} \ - $$$$DOCKER_ID /usr/bin/make $(2) && \ - ([[ "$(DOCKER_HOST)" == "" ]] || docker cp $$$$DOCKER_ID:/mnt/$(2) $(2)) && \ - docker rm -f $$$$DOCKER_ID -endif +chaosctl: ## Build chaosctl + $(GO) build -ldflags '$(LDFLAGS)' -o bin/chaosctl ./cmd/chaosctl/*.go -image-$(1)-dependencies := $(image-$(1)-dependencies) $(2) -BINARIES := $(BINARIES) $(2) -endef +image: image-chaos-daemon image-chaos-mesh image-chaos-dashboard $(if $(DEBUGGER), image-chaos-dlv) ## Build container images for Chaos Mesh components (chaos-controller-manager, chaos-daemon, chaos-dashboard) -ifeq ($(IN_DOCKER),1) -images/chaos-daemon/bin/pause: hack/pause.c - cc ./hack/pause.c -o images/chaos-daemon/bin/pause +ui: pnpm_install_dependencies ## Build the frontend UI of Chaos Dashboard +ifeq (${UI},1) + cd ui &&\ + pnpm build + hack/embed_ui_assets.sh endif -$(eval $(call BUILD_IN_DOCKER_TEMPLATE,chaos-daemon,images/chaos-daemon/bin/pause)) -$(eval $(call BUILD_IN_DOCKER_TEMPLATE,chaos-daemon,images/chaos-daemon/bin/chaos-daemon)) -$(eval $(call COMPILE_GO_TEMPLATE,images/chaos-daemon/bin/chaos-daemon,./cmd/chaos-daemon/main.go,1)) +##@ Cleanup -$(eval $(call BUILD_IN_DOCKER_TEMPLATE,chaos-dashboard,images/chaos-dashboard/bin/chaos-dashboard)) -$(eval $(call COMPILE_GO_TEMPLATE,images/chaos-dashboard/bin/chaos-dashboard,./cmd/chaos-dashboard/main.go,1,ui swagger_spec)) +.PHONY: clean +clean: clean-binary clean-image-built ## Cleanup artifacts + rm -rf $(CLEAN_TARGETS) -$(eval $(call BUILD_IN_DOCKER_TEMPLATE,chaos-mesh,images/chaos-mesh/bin/chaos-controller-manager)) -$(eval $(call COMPILE_GO_TEMPLATE,images/chaos-mesh/bin/chaos-controller-manager,./cmd/chaos-controller-manager/main.go,0)) +##@ Tests -prepare-install: all docker-push docker-push-dns-server +CLEAN_TARGETS += cover.out cover.out.tmp -prepare-e2e: e2e-image docker-push-e2e +coverage: SHELL:=$(RUN_IN_DEV_SHELL) +coverage: images/dev-env/.dockerbuilt ## Generate coverage report +ifeq ("$(CI)", "1") + @bash <(curl -s https://codecov.io/bash) -f cover.out -t $(CODECOV_TOKEN) +else + mkdir -p cover + gocov convert cover.out > cover.json + gocov-xml < cover.json > cover.xml + gocov-html < cover.json > cover/index.html +endif GINKGO_FLAGS ?= -e2e: e2e-build - ./test/image/e2e/bin/ginkgo ${GINKGO_FLAGS} ./test/image/e2e/bin/e2e.test -- --e2e-image ${DOCKER_REGISTRY_PREFIX}pingcap/e2e-helper:${IMAGE_TAG} - -image-chaos-mesh-e2e-dependencies += test/image/e2e/manifests test/image/e2e/chaos-mesh e2e-build -CLEAN_TARGETS += test/image/e2e/manifests test/image/e2e/chaos-mesh - -e2e-build: test/image/e2e/bin/ginkgo test/image/e2e/bin/e2e.test +PAUSE_IMAGE ?= gcr.io/google-containers/pause:latest +e2e: e2e-build ## Run e2e tests in current kubernetes cluster + ./e2e-test/image/e2e/bin/ginkgo ${GINKGO_FLAGS} ./e2e-test/image/e2e/bin/e2e.test -- --e2e-image ghcr.io/chaos-mesh/e2e-helper:${IMAGE_TAG} --pause-image ${PAUSE_IMAGE} -CLEAN_TARGETS+=test/image/e2e/bin/ginkgo -test/image/e2e/bin/ginkgo: - $(GO) build -ldflags "$(LDFLAGS)" -tags "${BUILD_TAGS}" -o test/image/e2e/bin/ginkgo github.com/onsi/ginkgo/ginkgo +define failpoint-ctl + find $(ROOT)/* -type d | grep -vE "(\.git|bin|\.cache|ui)" | xargs failpoint-ctl $1 +endef -CLEAN_TARGETS+=test/image/e2e/bin/e2e.test -test/image/e2e/bin/e2e.test: - $(GO) test -c -o ./test/image/e2e/bin/e2e.test ./test/e2e +failpoint-enable: SHELL:=$(RUN_IN_DEV_SHELL) +failpoint-enable: images/dev-env/.dockerbuilt ## Enable failpoint stub for testing + $(call failpoint-ctl,enable) -test/image/e2e/manifests: manifests - rm -rf test/image/e2e/manifests - cp -r manifests test/image/e2e +failpoint-disable: SHELL:=$(RUN_IN_DEV_SHELL) +failpoint-disable: images/dev-env/.dockerbuilt ## Disable failpoint stub for testing + $(call failpoint-ctl,disable) -test/image/e2e/chaos-mesh: helm/chaos-mesh - rm -rf test/image/e2e/chaos-mesh - cp -r helm/chaos-mesh test/image/e2e +test: SHELL:=$(RUN_IN_DEV_SHELL) +test: generate manifests test-utils images/dev-env/.dockerbuilt ## Run unit tests + $(call failpoint-ctl,enable) + CGO_ENABLED=1 $(GOTEST) -p 1 $$($(PACKAGE_LIST)) -coverprofile cover.out.tmp -covermode=atomic + cat cover.out.tmp | grep -v "_generated.deepcopy.go" > cover.out + $(call failpoint-ctl,disable) -define IMAGE_TEMPLATE -CLEAN_TARGETS += $(2)/.dockerbuilt +##@ Advanced building targets -image-$(1): $(2)/.dockerbuilt +test-utils: timer multithread_tracee pkg/time/fakeclock/fake_clock_gettime.o pkg/time/fakeclock/fake_gettimeofday.o -$(2)/.dockerbuilt:$(image-$(1)-dependencies) $(2)/Dockerfile -ifeq ($(DOCKER_CACHE),1) +timer: + $(GO) build -ldflags '$(LDFLAGS)' -o bin/test/timer ./test/cmd/timer/*.go -ifneq ($(DISABLE_CACHE_FROM),1) - DOCKER_BUILDKIT=1 DOCKER_CLI_EXPERIMENTAL=enabled docker buildx build --load --cache-to type=local,dest=$(DOCKER_CACHE_DIR)/image-$(1) --cache-from type=local,src=$(DOCKER_CACHE_DIR)/image-$(1) -t ${DOCKER_REGISTRY_PREFIX}pingcap/$(1):${IMAGE_TAG} ${DOCKER_BUILD_ARGS} $(2) -else - DOCKER_BUILDKIT=1 DOCKER_CLI_EXPERIMENTAL=enabled docker buildx build --load --cache-to type=local,dest=$(DOCKER_CACHE_DIR)/image-$(1) -t ${DOCKER_REGISTRY_PREFIX}pingcap/$(1):${IMAGE_TAG} ${DOCKER_BUILD_ARGS} $(2) -endif +multithread_tracee: test/cmd/multithread_tracee/main.c + cc test/cmd/multithread_tracee/main.c -lpthread -O2 -o ./bin/test/multithread_tracee -else ifneq ($(TARGET_PLATFORM),) - DOCKER_BUILDKIT=1 docker buildx build --load --platform linux/$(TARGET_PLATFORM) -t ${DOCKER_REGISTRY_PREFIX}pingcap/$(1):${IMAGE_TAG} --build-arg TARGET_PLATFORM=$(TARGET_PLATFORM) ${DOCKER_BUILD_ARGS} $(2) -else - DOCKER_BUILDKIT=1 docker build -t ${DOCKER_REGISTRY_PREFIX}pingcap/$(1):${IMAGE_TAG} ${DOCKER_BUILD_ARGS} $(2) +pnpm_install_dependencies: +ifeq (${UI},1) + cd ui &&\ + pnpm install --frozen-lockfile endif - touch $(2)/.dockerbuilt -endef -$(eval $(call IMAGE_TEMPLATE,chaos-daemon,images/chaos-daemon)) -$(eval $(call IMAGE_TEMPLATE,chaos-mesh,images/chaos-mesh)) -$(eval $(call IMAGE_TEMPLATE,chaos-dashboard,images/chaos-dashboard)) -$(eval $(call IMAGE_TEMPLATE,build-env,images/build-env)) -$(eval $(call IMAGE_TEMPLATE,e2e-helper,test/cmd/e2e_helper)) -$(eval $(call IMAGE_TEMPLATE,chaos-mesh-protoc,hack/protoc)) -$(eval $(call IMAGE_TEMPLATE,chaos-mesh-e2e,test/image/e2e)) -$(eval $(call IMAGE_TEMPLATE,chaos-kernel,images/chaos-kernel)) -$(eval $(call IMAGE_TEMPLATE,chaos-jvm,images/chaos-jvm)) - -binary: $(BINARIES) - -docker-push: - docker push "${DOCKER_REGISTRY_PREFIX}pingcap/chaos-mesh:${IMAGE_TAG}" - docker push "${DOCKER_REGISTRY_PREFIX}pingcap/chaos-dashboard:${IMAGE_TAG}" - docker push "${DOCKER_REGISTRY_PREFIX}pingcap/chaos-daemon:${IMAGE_TAG}" - -docker-push-e2e: - docker push "${DOCKER_REGISTRY_PREFIX}pingcap/e2e-helper:${IMAGE_TAG}" - -# the version of dns server should keep consistent with helm -DNS_SERVER_VERSION ?= v0.2.0 -docker-push-dns-server: - docker pull pingcap/coredns:${DNS_SERVER_VERSION} - docker tag pingcap/coredns:${DNS_SERVER_VERSION} "${DOCKER_REGISTRY_PREFIX}pingcap/coredns:${DNS_SERVER_VERSION}" - docker push "${DOCKER_REGISTRY_PREFIX}pingcap/coredns:${DNS_SERVER_VERSION}" - -docker-push-chaos-kernel: - docker push "${DOCKER_REGISTRY_PREFIX}pingcap/chaos-kernel:${IMAGE_TAG}" - -$(GOBIN)/controller-gen: - $(GO) get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.5 -$(GOBIN)/revive: - $(GO) get github.com/mgechev/revive@v1.0.2-0.20200225072153-6219ca02fffb -$(GOBIN)/failpoint-ctl: - $(GO) get github.com/pingcap/failpoint/failpoint-ctl@v0.0.0-20200210140405-f8f9fb234798 -$(GOBIN)/goimports: - $(GO) get golang.org/x/tools/cmd/goimports@v0.0.0-20200309202150-20ab64c0d93f -$(GOBIN)/gosec: - $(GO) get github.com/securego/gosec/cmd/gosec@v0.0.0-20200401082031-e946c8c39989 - -lint: $(GOBIN)/revive - @echo "linting" - $< -formatter friendly -config revive.toml $$($(PACKAGE_LIST)) - -bin/chaos-builder: - $(CGOENV) go build -ldflags '$(LDFLAGS)' -o bin/chaos-builder ./cmd/chaos-builder/... - -chaos-build: bin/chaos-builder - bin/chaos-builder - -# Generate code -generate: $(GOBIN)/controller-gen chaos-build - cd ./api/v1alpha1 ;\ - $< object:headerFile=../../hack/boilerplate/boilerplate.generatego.txt paths="./..." ; - -manifests/crd.yaml: config ensure-kustomize - $(KUSTOMIZE_BIN) build config/default > manifests/crd.yaml - -yaml: manifests/crd.yaml - -# Generate Go files from Chaos Mesh proto files. -ifeq ($(IN_DOCKER),1) -proto: - for dir in pkg/chaosdaemon ; do\ - protoc -I $$dir/pb $$dir/pb/*.proto --go_out=plugins=grpc:$$dir/pb --go_out=./$$dir/pb ;\ - done -else -proto: image-chaos-mesh-protoc - docker run --rm --workdir /mnt/ --volume $(shell pwd):/mnt \ - --user $(shell id -u):$(shell id -g) --env IN_DOCKER=1 ${DOCKER_REGISTRY_PREFIX}pingcap/chaos-mesh-protoc \ - /usr/bin/make proto +watchmaker: pkg/time/fakeclock/fake_clock_gettime.o pkg/time/fakeclock/fake_gettimeofday.o + $(CGO) build -ldflags '$(LDFLAGS)' -o bin/watchmaker ./cmd/watchmaker/... - make fmt -endif +# Build schedule-migration +schedule-migration: + $(GO) build -ldflags '$(LDFLAGS)' -o bin/schedule-migration ./tools/schedule-migration/*.go -tools := kubectl helm kind kubebuilder kustomize kubetest2 -define DOWNLOAD_TOOL -ensure-$(1): - @echo "ensuring $(1)" - ROOT=$(ROOT) && source ./hack/lib.sh && hack::ensure_$(1) +schedule-migration.tar.gz: schedule-migration + cp ./bin/schedule-migration ./schedule-migration + cp ./tools/schedule-migration/migrate.sh ./migrate.sh + tar -czvf schedule-migration.tar.gz schedule-migration migrate.sh + rm ./migrate.sh + rm ./schedule-migration -all-tool-dependencies := $(all-tool-dependencies) ensure-$(1) -endef +e2e-image: image-e2e-helper ## Build e2e test helper image -$(foreach tool, $(tools), $(eval $(call DOWNLOAD_TOOL,$(tool)))) +enter-buildenv: SHELL:=$(shell $(BASIC_IMAGE_ENV) $(ROOT)/build/get_env_shell.py --interactive build-env) +enter-buildenv: image-build-env + @bash -ensure-all: $(all-tool-dependencies) +enter-devenv: SHELL:=$(shell $(BASIC_IMAGE_ENV) $(ROOT)/build/get_env_shell.py --interactive dev-env) +enter-devenv: images/dev-env/.dockerbuilt + @bash -install-local-coverage-tools: - go get github.com/axw/gocov/gocov \ - && go get github.com/AlekSi/gocov-xml \ - && go get -u github.com/matm/gocov-html +images/chaos-daemon/bin/pause: SHELL:=$(RUN_IN_BUILD_SHELL) +images/chaos-daemon/bin/pause: hack/pause.c images/build-env/.dockerbuilt ## Build binary pause + cc ./hack/pause.c -o images/chaos-daemon/bin/pause -.PHONY: all clean test install manifests groupimports fmt vet tidy image \ - docker-push lint generate config mockgen generate-mock \ - $(all-tool-dependencies) install.sh $(GO_TARGET_PHONY) \ - manager chaosfs chaosdaemon chaos-dashboard \ - dashboard dashboard-server-frontend gosec-scan \ - proto bin/chaos-builder go_build_cache_directory +.PHONY: pkg/time/fakeclock/fake_clock_gettime.o +pkg/time/fakeclock/fake_clock_gettime.o: SHELL:=$(RUN_IN_BUILD_SHELL) +pkg/time/fakeclock/fake_clock_gettime.o: pkg/time/fakeclock/fake_clock_gettime.c images/build-env/.dockerbuilt + [[ "$$TARGET_PLATFORM" == "arm64" ]] && CFLAGS="-mcmodel=tiny" ;\ + cc -c ./pkg/time/fakeclock/fake_clock_gettime.c -fPIE -O2 -o pkg/time/fakeclock/fake_clock_gettime.o $$CFLAGS +pkg/time/fakeclock/fake_gettimeofday.o: SHELL:=$(RUN_IN_BUILD_SHELL) +pkg/time/fakeclock/fake_gettimeofday.o: pkg/time/fakeclock/fake_gettimeofday.c images/build-env/.dockerbuilt + [[ "$$TARGET_PLATFORM" == "arm64" ]] && CFLAGS="-mcmodel=tiny" ;\ + cc -c ./pkg/time/fakeclock/fake_gettimeofday.c -fPIE -O2 -o pkg/time/fakeclock/fake_gettimeofday.o $$CFLAGS + +CLEAN_TARGETS += e2e-test/image/e2e/manifests e2e-test/image/e2e/chaos-mesh + +e2e-test/image/e2e/manifests: manifests ## Copy CRD manifests to e2e image build directory + rm -rf e2e-test/image/e2e/manifests + cp -r manifests e2e-test/image/e2e + +e2e-test/image/e2e/chaos-mesh: helm/chaos-mesh ## Copy helm chart to e2e image build directory + rm -rf e2e-test/image/e2e/chaos-mesh + cp -r helm/chaos-mesh e2e-test/image/e2e + +CLEAN_TARGETS+=e2e-test/image/e2e/bin/ginkgo +e2e-test/image/e2e/bin/ginkgo: SHELL:=$(RUN_IN_DEV_SHELL) +e2e-test/image/e2e/bin/ginkgo: images/dev-env/.dockerbuilt + mkdir -p e2e-test/image/e2e/bin + cp /go/bin/ginkgo e2e-test/image/e2e/bin/ginkgo + +CLEAN_TARGETS+=e2e-test/image/e2e/bin/e2e.test +e2e-test/image/e2e/bin/e2e.test: SHELL:=$(RUN_IN_DEV_SHELL) +e2e-test/image/e2e/bin/e2e.test: images/dev-env/.dockerbuilt + cd e2e-test && $(GO) test -c -o ./image/e2e/bin/e2e.test ./e2e + +e2e-build: e2e-test/image/e2e/bin/ginkgo e2e-test/image/e2e/bin/e2e.test ## Build e2e test binary + +bin/chaos-builder: SHELL:=$(RUN_IN_DEV_SHELL) +bin/chaos-builder: images/dev-env/.dockerbuilt + $(CGOENV) go build -ldflags '$(LDFLAGS)' -buildvcs=false -o bin/chaos-builder ./cmd/chaos-builder/... + +.PHONY: all image clean test manifests manifests/crd.yaml \ + boilerplate tidy groupimports fmt vet lint install.sh schedule-migration \ + config proto \ + generate generate-deepcopy swagger_spec bin/chaos-builder \ + gosec-scan \ + failpoint-enable failpoint-disable \ diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000000..7221d49ffd --- /dev/null +++ b/OWNERS @@ -0,0 +1,6 @@ +reviewers: + - chaos-mesh-maintainers + - chaos-mesh-committers +approvers: + - chaos-mesh-maintainers + - chaos-mesh-committers diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES new file mode 100644 index 0000000000..d9850a8940 --- /dev/null +++ b/OWNERS_ALIASES @@ -0,0 +1,11 @@ +aliases: + chaos-mesh-maintainers: + - cwen0 + - YangKeao + - dcalvin + - STRRL + - g1eny0ung + chaos-mesh-committers: + - Andrewmatilde + - WangXiangUSTC + - xlgao-zju diff --git a/PROJECT b/PROJECT deleted file mode 100644 index f7826379ef..0000000000 --- a/PROJECT +++ /dev/null @@ -1,22 +0,0 @@ -version: "2" -domain: chaos-mesh.org -repo: github.com/chaos-mesh/chaos-mesh -resources: -- group: chaosmesh - version: v1alpha1 - kind: PodChaos -- group: chaosmesh - version: v1alpha1 - kind: NetworkChaos -- group: chaosmesh - version: v1alpha1 - kind: IoChaos -- group: chaosmesh - version: v1alpha1 - kind: TimeChaos -- group: chaosmesh - version: v1alpha1 - kind: KernelChaos -- group: chaosmesh - version: v1alpha1 - kind: StressChaos diff --git a/README.md b/README.md index 415dea0c5c..d3e33e38a9 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,37 @@ -chaos-mesh-logo +Chaos Mesh Logo +Chaos Mesh Logo -[![Build Status](https://internal.pingcap.net/idc-jenkins/job/build_chaos_mesh_master/badge/icon)](https://internal.pingcap.net/idc-jenkins/view/chaos-mesh/job/build_chaos_mesh_master/) +--- + + + +[![LICENSE](https://img.shields.io/github/license/chaos-mesh/chaos-mesh.svg)](https://github.com/chaos-mesh/chaos-mesh/blob/master/LICENSE) [![codecov](https://codecov.io/gh/chaos-mesh/chaos-mesh/branch/master/graph/badge.svg)](https://codecov.io/gh/chaos-mesh/chaos-mesh) -[![LICENSE](https://img.shields.io/github/license/pingcap/chaos-mesh.svg)](https://github.com/chaos-mesh/chaos-mesh/blob/master/LICENSE) -[![Language](https://img.shields.io/badge/Language-Go-blue.svg)](https://golang.org/) [![Go Report Card](https://goreportcard.com/badge/github.com/chaos-mesh/chaos-mesh)](https://goreportcard.com/report/github.com/chaos-mesh/chaos-mesh) [![GoDoc](https://img.shields.io/badge/Godoc-reference-blue.svg)](https://godoc.org/github.com/chaos-mesh/chaos-mesh) +[![Upload Image](https://github.com/chaos-mesh/chaos-mesh/actions/workflows/upload_image.yml/badge.svg?event=schedule)](https://github.com/chaos-mesh/chaos-mesh/actions/workflows/upload_image.yml) + [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fchaos-mesh%2Fchaos-mesh.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fchaos-mesh%2Fchaos-mesh?ref=badge_shield) +[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3680/badge)](https://bestpractices.coreinfrastructure.org/projects/3680) +[![Artifact Hub](https://img.shields.io/endpoint?url=https%3A%2F%2Fartifacthub.io%2Fbadge%2Frepository%2Fchaos-mesh)](https://artifacthub.io/packages/helm/chaos-mesh/chaos-mesh) + + + +Chaos Mesh is an open source cloud-native Chaos Engineering platform. It offers various types of fault simulation and has an enormous capability to orchestrate fault scenarios. + +Using Chaos Mesh, you can conveniently simulate various abnormalities that might occur in reality during the development, testing, and production environments and find potential problems in the system. To lower the threshold for a Chaos Engineering project, Chaos Mesh provides you with a visualization operation. You can easily design your Chaos scenarios on the Web UI and monitor the status of Chaos experiments. + +![cncf_logo](./static/cncf.png#gh-light-mode-only) +![cncf_logo](./static/cncf-white.png#gh-dark-mode-only) + +Chaos Mesh is a [Cloud Native Computing Foundation (CNCF)](https://www.cncf.io/) incubating project. If you are an organization that wants to help shape the evolution of technologies that are container-packaged, dynamically-scheduled and microservices-oriented, consider joining the CNCF. For details about who's involved and how Chaos Mesh plays a role, read the CNCF [announcement](https://www.cncf.io/announcements/2020/09/02/cloud-native-computing-foundation-announces-tikv-graduation/). -> **Note:** -> -> This readme and related documentation are Work in Progress. +--- -Chaos Mesh® is a [Cloud Native Computing Foundation (CNCF)](https://www.cncf.io/) hosted project. It is a cloud-native Chaos Engineering platform that orchestrates chaos on Kubernetes environments. At the current stage, it has the following components: +At the current stage, Chaos Mesh has the following components: - **Chaos Operator**: the core component for chaos orchestration. Fully open sourced. -- **Chaos Dashboard**: a Web UI for managing, designing, monitoring Chaos Experiments; under development. +- **Chaos Dashboard**: a Web UI for managing, designing, monitoring Chaos Experiments. See the following demo video for a quick view of Chaos Mesh: @@ -23,37 +39,26 @@ See the following demo video for a quick view of Chaos Mesh: ## Chaos Operator -Chaos Operator injects chaos into the applications and Kubernetes infrastructure in a manageable way, which provides easy, custom definitions for chaos experiments and automatic orchestration. There are three components at play: +Chaos Operator injects chaos into the applications and Kubernetes infrastructure in a manageable way, which provides easy, custom definitions for chaos experiments and automatic orchestration. There are two components at play: -**Controller-manager**: used to schedule and manage the lifecycle of CRD objects +**Chaos Controller Manager**: is primarily responsible for the scheduling and management of Chaos experiments. This component contains several CRD Controllers, such as Workflow Controller, Scheduler Controller, and Controllers of various fault types. -**Chaos-daemon**: runs as daemonset with privileged system permissions over network, Cgroup, etc. for a specific node +**Chaos Daemon**: runs as DaemonSet and has Privileged permission by default (which can be disabled). This component mainly interferes with specific network devices, file systems, kernels by hacking into the target Pod Namespace. -![Chaos Operator](./static/chaos-mesh.svg) +![Chaos Operator](./static/chaos-mesh.png) -Chaos Operator uses [Custom Resource Definition (CRD)](https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/) to define chaos objects. -The current implementation supports a few types of CRD objects for fault injection, namely DNSChaos, PodChaos, PodIoChaos, PodNetworkChaos, NetworkChaos, IoChaos, TimeChaos, StressChaos, and KernelChaos, which correspond to the following major actions (experiments): +Chaos Operator uses [CustomResourceDefinition (CRD)](https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/) to define chaos objects. -- pod-kill: The selected pod is killed (ReplicaSet or something similar may be needed to ensure the pod will be restarted). -- pod-failure: The selected pod will be unavailable in a specified period of time. -- container-kill: The selected container is killed in the selected pod. -- netem chaos: Network chaos such as delay, duplication, etc. -- network-partition: Simulate network partition. -- IO chaos: Simulate file system faults such as I/O delay, read/write errors, etc. -- time chaos: The selected pod will be injected with clock skew. -- cpu-burn: Simulate the CPU of the selected pod stress. -- memory-burn: Simulate the memory of the selected pod stress. -- kernel chaos: The selected pod will be injected with (slab, bio, etc) errors. -- dns chaos: The selected pod will be injected with dns errors, such as error, random. +The current implementation supports a few types of CRD objects for fault injection, namely `PodChaos`, `NetworkChaos`, `IOChaos`, `TimeChaos`, `StressChaos`, and so on. +You can get the full list of CRD objects and their specifications in the [Chaos Mesh Docs](https://chaos-mesh.org/docs/). ## Quick start -- [Get Started on kind](https://chaos-mesh.org/docs/get_started/get_started_on_kind) -- [Get Started on minikube](https://chaos-mesh.org/docs/get_started/get_started_on_minikube) +See [Quick Start](https://chaos-mesh.org/docs/quick-start) and [Install Chaos Mesh using Helm](https://chaos-mesh.org/docs/production-installation-using-helm/). -## Deploy and use +## Contributing -See [Docs](https://chaos-mesh.org/docs/). +See the [contributing guide](./CONTRIBUTING.md) and [development guide](https://chaos-mesh.org/docs/developer-guide-overview). ## Adopters @@ -63,15 +68,12 @@ See [ADOPTERS](ADOPTERS.md). Blogs on Chaos Mesh design & implementation, features, chaos engineering, community updates, etc. See [Chaos Mesh Blogs](https://chaos-mesh.org/blog). Here are some recommended ones for you to start with: -- [Chaos Mesh - Your Chaos Engineering Solution for System Resiliency on Kubernetes](https://pingcap.com/blog/chaos-mesh-your-chaos-engineering-solution-for-system-resiliency-on-kubernetes/) -- [Run Your First Chaos Experiment in 10 Minutes](https://pingcap.com/blog/run-first-chaos-experiment-in-ten-minutes/) -- [Simulating Clock Skew in K8s Without Affecting Other Containers on the Node](https://pingcap.com/blog/simulating-clock-skew-in-k8s-without-affecting-other-containers-on-node/) -- [Building an Automated Testing Framework Based on Chaos Mesh® and Argo](https://chaos-mesh.org/blog/building_automated_testing_framework) -- [Chaos Mesh 1.0: Chaos Engineering on Kubernetes Made Easier](https://chaos-mesh.org/blog/chaos-mesh-1.0-chaos-engineering-on-kubernetes-made-easier) - -## Contribute - -See the [contributing guide](./CONTRIBUTING.md) and [development guide](https://chaos-mesh.org/docs/development_guides/development_overview). +- [Chaos Mesh 2.0: To a Chaos Engineering Ecology](https://chaos-mesh.org/blog/chaos-mesh-2.0-to-a-chaos-engineering-ecology/) +- [Chaos Mesh - Your Chaos Engineering Solution for System Resiliency on Kubernetes](https://chaos-mesh.org/blog/chaos_mesh_your_chaos_engineering_solution/) +- [Run Your First Chaos Experiment in 10 Minutes](https://chaos-mesh.org/blog/run_your_first_chaos_experiment/) +- [How to Simulate I/O Faults at Runtime](https://chaos-mesh.org/blog/how-to-simulate-io-faults-at-runtime/) +- [Simulating Clock Skew in K8s Without Affecting Other Containers on the Node](https://chaos-mesh.org/blog/simulating-clock-skew-in-k8s-without-affecting-other-containers-on-node/) +- [Building an Automated Testing Framework Based on Chaos Mesh and Argo](https://chaos-mesh.org/blog/building_automated_testing_framework) ## Community @@ -79,22 +81,25 @@ Please reach out for bugs, feature requests, and other issues via: - Following us on Twitter [@chaos_mesh](https://twitter.com/chaos_mesh). -- Joining the #project-chaos-mesh channel in the [CNCF Slack](https://slack.cncf.io/) workspace. +- Joining the `#project-chaos-mesh` channel in the [CNCF Slack](https://slack.cncf.io/) workspace. -- Filing an issue or opening a PR against this repository. +- Filling an issue or opening a PR against this repository. -### Community meeting +### Community meetings -On the fourth Friday of every month (unless otherwise specified), the Chaos Mesh community holds a monthly meeting by video conference to discuss the status of Chaos Mesh. +- Chaos Mesh Community Monthly (Community and project-level updates, community sharing/demo, office hours) + - Time: on the fourth Thursday of every month (unless otherwise specified) + - [RSVP here](https://community.cncf.io/chaos-mesh-community/) + - [Meeting minutes](https://docs.google.com/document/d/1H8IfmhIJiJ1ltg-XLjqR_P_RaMHUGrl1CzvHnKM_9Sc/edit?usp=sharing) -**Quick links:** +- Chaos Mesh Development Meeting (Releases, roadmap/features/RFC planning and discussion, issue triage/discussion, etc) + - Time: Every other Tuesday (unless otherwise specified) + - [RSVP here](https://community.cncf.io/chaos-mesh-community/) + - [Meeting minutes](https://docs.google.com/document/d/1s9X6tTOy3OGZaLDZQesGw1BNOrxQfWExjBFIn5irpPE/edit) -- [RSVP here](https://community.cncf.io/chaos-mesh-community/) -- [Meeting notes](https://docs.google.com/document/d/1H8IfmhIJiJ1ltg-XLjqR_P_RaMHUGrl1CzvHnKM_9Sc/edit?usp=sharing) +### Community blogs -### Community blog - -- Grant Tarrant-Fisher: [Integrate your Reliability Toolkit with Your World, Part 2](https://medium.com/chaosiq/integrate-your-reliability-toolkit-with-your-world-part-2-e012f2c2a7f6) +- Grant Tarrant-Fisher: [Integrate your Reliability Toolkit with Your World](https://medium.com/search?q=Integrate+your+Reliability+Toolkit+with+Your+World) - Yoshinori Teraoka: [Streake: Chaos Mesh によるカオスエンジニアリング](https://medium.com/sreake-jp/chaos-mesh-%E3%81%AB%E3%82%88%E3%82%8B%E3%82%AB%E3%82%AA%E3%82%B9%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%83%AA%E3%83%B3%E3%82%B0-46fa2897c742) - Sébastien Prud'homme: [Chaos Mesh : un générateur de chaos pour Kubernetes](https://www.cowboysysop.com/post/chaos-mesh-un-generateur-de-chaos-pour-kubernetes/) - Craig Morten @@ -104,6 +109,22 @@ On the fourth Friday of every month (unless otherwise specified), the Chaos Mesh - kondoumh: [​Kubernetes ネイティブなカオスエンジニアリングツール Chaos Mesh を使ってみる](https://blog.kondoumh.com/entry/2020/10/23/123431) - Vadim Tkachenko: [ChaosMesh to Create Chaos in Kubernetes](https://www.percona.com/blog/2020/11/05/chaosmesh-to-create-chaos-in-kubernetes/) - Hui Zhang: [How a Top Game Company Uses Chaos Engineering to Improve Testing](https://chaos-mesh.org/blog/how-a-top-game-company-uses-chaos-engineering-to-improve-testing) +- Anurag Paliwal + - [Securing tenant services while using chaos mesh using OPA](https://anuragpaliwal-93749.medium.com/securing-tenant-services-while-using-chaos-mesh-using-opa-3ae80c7f4b85) + - [Securing namespaces using restrict authorization feature in chaos mesh](https://anuragpaliwal-93749.medium.com/securing-namespaces-using-restrict-authorization-feature-in-chaos-mesh-2e110c3e0fb7) +- Pavan Kumar: [Chaos Engineering in Kubernetes using Chaos Mesh](https://link.medium.com/1V90dEknugb) +- Jessica Cherry: [Test your Kubernetes experiments with an open source web interface](https://opensource.com/article/21/6/chaos-mesh-kubernetes) +- λ.eranga: [Chaos Engineering with Chaos Mesh](https://medium.com/rahasak/chaos-engineering-with-chaos-mesh-b040169b51bd) +- Tomáš Kubica: [Kubernetes prakticky: zlounství s Chaos Mesh a Azure Chaos Studio](https://www.tomaskubica.cz/post/2021/kubernetes-prakticky-zlounstvi-s-chaos-mesh-a-azure-chaos-studio2/) +- mend: [Chaos Meshで何ができるのか見てみた](https://qiita.com/mend/items/dcdfab5e980467bf58e9) + +### Community talks + +- Twain Taylor: [Chaos Mesh Simplifies & Organizes Chaos Engineering For Kubernetes](https://youtu.be/shbrjAY86ZQ) +- Saiyam Pathak + - [Let's explore chaos mesh](https://youtu.be/kMbTYItsTTI) + - [Chaos Mesh - Chaos Engineering for Kubernetes](https://youtu.be/HAU_cjW1bMw) + - [Chaos Mesh 2.0](https://youtu.be/HmQ9cFwxF7g) ## Media coverage @@ -113,20 +134,13 @@ On the fourth Friday of every month (unless otherwise specified), the Chaos Mesh - InfoQ: [Chaos Engineering on Kubernetes : Chaos Mesh Generally Available with v1.0](https://www.infoq.com/news/2020/10/kubernetes-chaos-mesh-ga/) - TechGenix: [Chaos Mesh Promises to Bring Order to Chaos Engineering](http://techgenix.com/chaos-mesh-chaos-engineering/) -## FAQs - -See [FAQs](https://chaos-mesh.org/docs/faqs). - -## Roadmap - -See [ROADMAP](./ROADMAP.md). - ## License -Chaos Mesh is licensed under the Apache License, Version 2.0. See [LICENSE](./LICENSE) for the full license text. +Chaos Mesh is licensed under the Apache License, Version 2.0. See [LICENSE](./LICENSE) for the full content. + [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fchaos-mesh%2Fchaos-mesh.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fchaos-mesh%2Fchaos-mesh?ref=badge_large) ## Trademark -Chaos Mesh® is a trademark of The Linux Foundation. All rights reserved. +Chaos Mesh is a trademark of The Linux Foundation. All rights reserved. diff --git a/ROADMAP.md b/ROADMAP.md index 6a1d540695..8403e0de4c 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,6 +1,6 @@ # Chaos Mesh Roadmap -This document defines the roadmap for Chaos Mesh development. +This document is intended to describe high-level plans for the Chaos Mesh project and is neither comprehensive nor prescriptive. For a more granular view of planned work, please refer to the project's upcoming [milestones](https://github.com/chaos-mesh/chaos-mesh/milestones). ## v1.0 @@ -15,18 +15,27 @@ This document defines the roadmap for Chaos Mesh development. ## v2.0 -- [ ] Improve Chaos Dashboard and make it easier to use -- [ ] Support status checks. A status check is used to evaluate the health of your environment. -- [ ] Support defining the scenario to manage a group of chaos experiments. -- [ ] Support generating the report for each chaos scenario. -- [ ] Add JVM chaos. Support injecting faults into Java applications. -- [ ] Add HTTP Chaos. Support injecting faults into http connections. -- [ ] Add GRPC Chaos. Support injecting faults into GRPC connections. -- [ ] Support injecting faults into native components of Kubernetes. +- [x] Improve Chaos Dashboard and make it easier to use +- [x] Support status checks. A status check is used to evaluate the health of your environment. +- [x] Support defining the scenario to manage a group of chaos experiments. +- [x] Support generating the report for each chaos scenario. +- [x] Add JVM chaos. Support injecting faults into Java applications. +- [x] Add HTTP Chaos. Support injecting faults into http connections. +- [ ] ~~Add GRPC Chaos. Support injecting faults into GRPC connections.~~ +- [ ] ~~Support injecting faults into native components of Kubernetes.~~ + +## Medium term -## Long-term +- [x] Manage and schedule chaos experiments on Kubernetes targets and non-Kubernetes targets on a unified dashboard. +- [x] Improve JVMChaos and support dynamic injection. +- [ ] Support injecting faults into native components of Kubernetes. +- [ ] More comprehensive status inspection mechanism and reports. +- [ ] Improve observability via events logs and metrics. +- [ ] Improve authentication system, and support using GCP/AWS account to log in chaos dashboard. +- [ ] Add GRPC Chaos. Support injecting faults into GRPC connections. +- [ ] A new component to force recovery chaos experiments, and avoid experiments going out of control. +- [ ] Build a hub for users sharing their own chaos workflow and chaos types. +- [ ] Support doing chaos experiments on multiple Kubernetes clusters. +- [ ] Provide a plugin approach to extend complex chaos types, such as RabbitMQChaos, RedisChaos... +- [ ] Continue to enrich fault types. -- [x] chaos-operator -- [x] chaos-dashboard -- [ ] chaos-verify -- [ ] chaos-cloud diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..59c077fe44 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,24 @@ +# Chaos Mesh Security Policy + +Chaos Mesh is a growing community devoted to building a chaos engineering ecology under the cloud-native realm. As maintainers of Chaos Mesh, we attach great importance to code security. We are very grateful to the users, security vulnerability researchers, etc. for reporting security vulnerabilities to us. All reported security vulnerabilities will be carefully assessed, addressed, and answered by us. + +## Supported Versions + +We provide security updates for the two most recent minor versions released on GitHub. + +For example, if `v1.2.2` is the most recent stable version, we will address security updates for `v1.1.0` and later, Once `v1.3.0` is released, we will no longer provide updates for `v1.1.x` releases. + +## Reporting a Vulnerability + +To report a security problem in Chaos Mesh, please contact the Chaos Mesh Security Team: chaos-mesh-security@lists.cncf.io. +The team will help diagnose the severity of the issue and determine how to address the issue. Issues deemed to be non-critical will be filed as GitHub issues. Critical issues will receive immediate attention and be fixed as quickly as possible. + +## Disclosure policy + +For known public security vulnerabilities, we will disclose the disclosure as soon as possible after receiving the report. Vulnerabilities discovered for the first time will be disclosed in accordance with the following process: + +1. The received security vulnerability report shall be handed over to the security team for follow-up coordination and repair work. +2. After the vulnerability is confirmed, we will create a draft Security Advisory on Github that lists the details of the vulnerability. +3. Invite related personnel to discuss the fix. +4. Fork the temporary private repository on Github, and collaborate to fix the vulnerability. +5. After the fixed code is merged into all supported versions, the vulnerability will be publicly posted in the GitHub Advisory Database. diff --git a/api/genericwebhook/bfs.go b/api/genericwebhook/bfs.go new file mode 100644 index 0000000000..007d9a5569 --- /dev/null +++ b/api/genericwebhook/bfs.go @@ -0,0 +1,108 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package genericwebhook + +import ( + "container/list" + "reflect" + + "k8s.io/apimachinery/pkg/util/validation/field" +) + +type fieldCallback func(path *field.Path, obj interface{}, field *reflect.StructField) bool + +type FieldWalker struct { + obj interface{} + callback fieldCallback +} + +func NewFieldWalker(obj interface{}, callback fieldCallback) *FieldWalker { + return &FieldWalker{ + obj: obj, + callback: callback, + } +} + +type iterateNode struct { + Val reflect.Value + Path *field.Path + Field *reflect.StructField +} + +func (w *FieldWalker) Walk() { + objVal := reflect.ValueOf(w.obj) + + items := list.New() + items.PushBack(iterateNode{ + Val: objVal, + Path: nil, + }) + + for { + if items.Len() == 0 { + break + } + + item := items.Front() + items.Remove(item) + + node := item.Value.(iterateNode) + // If node is not the root node, then we need to check whether + // we need to iterate its children. + if node.Path != nil { + val := node.Val + if val.Kind() != reflect.Ptr { + // If it's not a pointer or a slice, then we need to + // take the address of it, to be able to modify it. + val = val.Addr() + } + if !w.callback(node.Path, val.Interface(), node.Field) { + continue + } + } + + if node.Val.Kind() == reflect.Ptr && node.Val.IsZero() { + continue + } + objVal = reflect.Indirect(node.Val) + objType := objVal.Type() + switch objType.Kind() { + case reflect.Struct: + for i := 0; i < objVal.NumField(); i++ { + field := objType.Field(i) + fieldVal := objVal.Field(i) + + // The field should be exported + if fieldVal.CanInterface() { + items.PushBack(iterateNode{ + Val: fieldVal, + Path: node.Path.Child(field.Name), + Field: &field, + }) + } + } + case reflect.Slice: + for i := 0; i < objVal.Len(); i++ { + items.PushBack(iterateNode{ + Val: objVal.Index(i), + Path: node.Path.Index(i), + Field: nil, + }) + } + } + + } +} diff --git a/api/genericwebhook/bfs_test.go b/api/genericwebhook/bfs_test.go new file mode 100644 index 0000000000..c063f6bf3e --- /dev/null +++ b/api/genericwebhook/bfs_test.go @@ -0,0 +1,119 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package genericwebhook + +import ( + "reflect" + "testing" + + "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func TestBfs(t *testing.T) { + g := gomega.NewGomegaWithT(t) + + { + type Test struct { + A, B, C int + } + + testStruct := &Test{1, 2, 3} + walker := NewFieldWalker(testStruct, func(path *field.Path, obj interface{}, field *reflect.StructField) bool { + val := obj.(*int) + *val = 2 + return true + }) + walker.Walk() + g.Expect(testStruct).To(gomega.Equal(&Test{2, 2, 2})) + } + + { + type Test struct { + A, B int + C *int + } + + testC := 3 + two := 2 + testStruct := &Test{1, 2, &testC} + walker := NewFieldWalker(testStruct, func(path *field.Path, obj interface{}, field *reflect.StructField) bool { + switch obj := obj.(type) { + case *int: + *obj = 2 + case **int: + *obj = &two + default: + panic("unexpected type") + } + return true + }) + walker.Walk() + g.Expect(testStruct).To(gomega.Equal(&Test{2, 2, &two})) + } + + { + type Inside struct { + A, B int + } + type DeepTest struct { + A, B int + C Inside + } + + testStruct := &DeepTest{1, 2, Inside{3, 4}} + walker := NewFieldWalker(testStruct, func(path *field.Path, obj interface{}, field *reflect.StructField) bool { + switch obj := obj.(type) { + case *int: + *obj = 2 + case *Inside: + *obj = Inside{2, 2} + default: + panic("unexpected type") + } + + return false + }) + walker.Walk() + g.Expect(testStruct).To(gomega.Equal(&DeepTest{2, 2, Inside{2, 2}})) + } + + { + type Inside struct { + A, B int + } + type DeepTest struct { + A, B int + C Inside + } + + testStruct := &DeepTest{1, 2, Inside{3, 4}} + walker := NewFieldWalker(testStruct, func(path *field.Path, obj interface{}, field *reflect.StructField) bool { + switch obj := obj.(type) { + case *int: + *obj = 2 + case *Inside: + return true + default: + panic("unexpected type") + } + + return false + }) + walker.Walk() + g.Expect(testStruct).To(gomega.Equal(&DeepTest{2, 2, Inside{2, 2}})) + } +} diff --git a/api/genericwebhook/defaulter.go b/api/genericwebhook/defaulter.go new file mode 100644 index 0000000000..30ff5f5d2e --- /dev/null +++ b/api/genericwebhook/defaulter.go @@ -0,0 +1,92 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package genericwebhook + +import ( + "reflect" + "strings" + + "k8s.io/apimachinery/pkg/util/validation/field" +) + +type Defaulter interface { + Default(root interface{}, field *reflect.StructField) +} + +// Default would walk through all the fields of target struct recursively, and set the default value which declared with struct tag "default". +// +// Parameter obj should be a pointer to a data struct. +// +// Default should return an empty field.ErrorList. +func Default(obj interface{}) field.ErrorList { + // TODO: how to resolve invalid input, for example: obj is a pointer to pointer + errorList := field.ErrorList{} + + root := obj + walker := NewFieldWalker(obj, func(path *field.Path, obj interface{}, field *reflect.StructField) bool { + webhookAttr := "" + if field != nil { + webhookAttr = field.Tag.Get("webhook") + } + attributes := strings.Split(webhookAttr, ",") + + webhook := "" + nilable := false + if len(attributes) > 0 { + webhook = attributes[0] + } + if len(attributes) > 1 { + nilable = attributes[1] == "nilable" + } + + defaulter := getDefaulter(obj, webhook, nilable) + if defaulter != nil { + defaulter.Default(root, field) + } + + return true + }) + walker.Walk() + + return errorList +} + +func getDefaulter(obj interface{}, webhook string, nilable bool) Defaulter { + // There are two possible situations: + // 1. The field is a value (int, string, normal struct, etc), and the obj is the reference of it. + // 2. The field is a pointer to a value or a slice, then the obj is itself. + + val := reflect.ValueOf(obj) + + if defaulter, ok := obj.(Defaulter); ok { + if nilable || !val.IsZero() { + return defaulter + } + } + + if webhook != "" { + webhookImpl := webhooks[webhook] + + v := val.Convert(webhookImpl).Interface() + if defaulter, ok := v.(Defaulter); ok { + if nilable || !val.IsZero() { + return defaulter + } + } + } + + return nil +} diff --git a/api/genericwebhook/validater.go b/api/genericwebhook/validater.go new file mode 100644 index 0000000000..7f8106f49e --- /dev/null +++ b/api/genericwebhook/validater.go @@ -0,0 +1,102 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package genericwebhook + +import ( + "reflect" + "strings" + + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +type FieldValidator interface { + Validate(root interface{}, path *field.Path) field.ErrorList +} + +// Validate would walk through all the fields of target struct recursively, and validate the value with validator declared with struct tag "webhook". +// +// Parameter obj should be a pointer to a data struct. +// +// Validate should return an empty field.ErrorList if all the fields are valid, or return each field.Error for every invalid values. +func Validate(obj interface{}) field.ErrorList { + // TODO: how to resolve invalid input, for example: obj is a pointer to pointer + errorList := field.ErrorList{} + + root := obj + walker := NewFieldWalker(obj, func(path *field.Path, obj interface{}, field *reflect.StructField) bool { + webhookAttr := "" + if field != nil { + webhookAttr = field.Tag.Get("webhook") + } + attributes := strings.Split(webhookAttr, ",") + + webhook := "" + nilable := false + if len(attributes) > 0 { + webhook = attributes[0] + } + if len(attributes) > 1 { + nilable = attributes[1] == "nilable" + } + + validator := getValidator(obj, webhook, nilable) + if validator != nil { + if err := validator.Validate(root, path); err != nil { + errorList = append(errorList, err...) + } + } + + return true + }) + walker.Walk() + + return errorList +} + +func Aggregate(errs field.ErrorList) error { + if errs == nil || len(errs) == 0 { + return nil + } + return errors.New(errs.ToAggregate().Error()) +} + +func getValidator(obj interface{}, webhook string, nilable bool) FieldValidator { + // There are two possible situations: + // 1. The field is a value (int, string, normal struct, etc), and the obj is the reference of it. + // 2. The field is a pointer to a value or a slice, then the obj is itself. + + val := reflect.ValueOf(obj) + + if validator, ok := obj.(FieldValidator); ok { + if nilable || !val.IsZero() { + return validator + } + } + + if webhook != "" { + webhookImpl := webhooks[webhook] + + v := val.Convert(webhookImpl).Interface() + if validator, ok := v.(FieldValidator); ok { + if nilable || !val.IsZero() { + return validator + } + } + } + + return nil +} diff --git a/api/genericwebhook/webhook.go b/api/genericwebhook/webhook.go new file mode 100644 index 0000000000..b1f78b5fb0 --- /dev/null +++ b/api/genericwebhook/webhook.go @@ -0,0 +1,24 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package genericwebhook + +import "reflect" + +var webhooks map[string]reflect.Type = make(map[string]reflect.Type) + +func Register(name string, obj reflect.Type) { + webhooks[name] = obj +} diff --git a/api/go.mod b/api/go.mod new file mode 100644 index 0000000000..1e0c7daaf0 --- /dev/null +++ b/api/go.mod @@ -0,0 +1,111 @@ +module github.com/chaos-mesh/chaos-mesh/api + +go 1.20 + +require ( + github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 + github.com/bxcodec/faker v2.0.1+incompatible + github.com/docker/go-units v0.5.0 + github.com/google/uuid v1.3.1 + github.com/onsi/ginkgo/v2 v2.12.0 + github.com/onsi/gomega v1.27.10 + github.com/pkg/errors v0.9.1 + github.com/robfig/cron/v3 v3.0.1 + k8s.io/api v0.28.2 + k8s.io/apimachinery v0.28.2 + k8s.io/client-go v0.28.2 + sigs.k8s.io/controller-runtime v0.16.2 +) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.10.1 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/zapr v1.2.4 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/prometheus/client_golang v1.16.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/testify v1.8.3 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.25.0 // indirect + golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.12.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiextensions-apiserver v0.28.1 // indirect + k8s.io/component-base v0.28.2 // indirect + k8s.io/klog/v2 v2.100.1 // indirect + k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect + k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) + +replace ( + k8s.io/api => k8s.io/api v0.28.2 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.28.2 + k8s.io/apimachinery => k8s.io/apimachinery v0.28.2 + k8s.io/apiserver => k8s.io/apiserver v0.28.2 + k8s.io/cli-runtime => k8s.io/cli-runtime v0.28.2 + k8s.io/client-go => k8s.io/client-go v0.28.2 + k8s.io/cloud-provider => k8s.io/cloud-provider v0.28.2 + k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.28.2 + k8s.io/code-generator => k8s.io/code-generator v0.28.2 + k8s.io/component-base => k8s.io/component-base v0.28.2 + k8s.io/component-helpers => k8s.io/component-helpers v0.28.2 + k8s.io/controller-manager => k8s.io/controller-manager v0.28.2 + k8s.io/cri-api => k8s.io/cri-api v0.28.2 + k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.28.2 + k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.28.2 + k8s.io/endpointslice => k8s.io/endpointslice v0.28.2 + k8s.io/kms => k8s.io/kms v0.28.2 + k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.28.2 + k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.28.2 + k8s.io/kube-proxy => k8s.io/kube-proxy v0.28.2 + k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.28.2 + k8s.io/kubectl => k8s.io/kubectl v0.28.2 + k8s.io/kubelet => k8s.io/kubelet v0.28.2 + k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.28.2 + k8s.io/metrics => k8s.io/metrics v0.28.2 + k8s.io/mount-utils => k8s.io/mount-utils v0.28.2 + k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.28.2 + k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.28.2 + k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.28.2 + k8s.io/sample-controller => k8s.io/sample-controller v0.28.2 +) diff --git a/api/go.sum b/api/go.sum new file mode 100644 index 0000000000..be03d79b5f --- /dev/null +++ b/api/go.sum @@ -0,0 +1,233 @@ +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bxcodec/faker v2.0.1+incompatible h1:P0KUpUw5w6WJXwrPfv35oc91i4d8nf40Nwln+M/+faA= +github.com/bxcodec/faker v2.0.1+incompatible/go.mod h1:BNzfpVdTwnFJ6GtfYTcQu6l6rHShT+veBxNCnjCx5XM= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= +github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= +github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= +github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/onsi/ginkgo/v2 v2.12.0 h1:UIVDowFPwpg6yMUpPjGkYvf06K3RAiJXUhCxEwQVHRI= +github.com/onsi/ginkgo/v2 v2.12.0/go.mod h1:ZNEzXISYlqpb8S36iN71ifqLi3vVD1rVJGvWRCJOUpQ= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= +go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= +golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= +k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= +k8s.io/apiextensions-apiserver v0.28.2 h1:J6/QRWIKV2/HwBhHRVITMLYoypCoPY1ftigDM0Kn+QU= +k8s.io/apiextensions-apiserver v0.28.2/go.mod h1:5tnkxLGa9nefefYzWuAlWZ7RZYuN/765Au8cWLA6SRg= +k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= +k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= +k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= +k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= +k8s.io/component-base v0.28.2 h1:Yc1yU+6AQSlpJZyvehm/NkJBII72rzlEsd6MkBQ+G0E= +k8s.io/component-base v0.28.2/go.mod h1:4IuQPQviQCg3du4si8GpMrhAIegxpsgPngPRR/zWpzc= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.16.2 h1:mwXAVuEk3EQf478PQwQ48zGOXvW27UJc8NHktQVuIPU= +sigs.k8s.io/controller-runtime v0.16.2/go.mod h1:vpMu3LpI5sYWtujJOa2uPK61nB5rbwlN7BAB8aSLvGU= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/api/v1alpha1/awschaos_types.go b/api/v1alpha1/awschaos_types.go index 8610526cfb..09061517cd 100644 --- a/api/v1alpha1/awschaos_types.go +++ b/api/v1alpha1/awschaos_types.go @@ -1,88 +1,122 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( + "encoding/json" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // +kubebuilder:object:root=true -// +chaos-mesh:base +// +kubebuilder:printcolumn:name="action",type=string,JSONPath=`.spec.action` +// +kubebuilder:printcolumn:name="duration",type=string,JSONPath=`.spec.duration` +// +chaos-mesh:experiment +// +chaos-mesh:oneshot=in.Spec.Action==Ec2Restart -// AwsChaos is the Schema for the awschaos API -type AwsChaos struct { +// AWSChaos is the Schema for the awschaos API +type AWSChaos struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec AwsChaosSpec `json:"spec"` - Status AwsChaosStatus `json:"status,omitempty"` + Spec AWSChaosSpec `json:"spec"` + Status AWSChaosStatus `json:"status,omitempty"` } -// AwsChaosAction represents the chaos action about aws. -type AwsChaosAction string +var _ InnerObjectWithSelector = (*AWSChaos)(nil) +var _ InnerObject = (*AWSChaos)(nil) + +// AWSChaosAction represents the chaos action about aws. +type AWSChaosAction string const ( // Ec2Stop represents the chaos action of stopping ec2. - Ec2Stop AwsChaosAction = "ec2-stop" + Ec2Stop AWSChaosAction = "ec2-stop" // Ec2Restart represents the chaos action of restarting ec2. - Ec2Restart AwsChaosAction = "ec2-restart" + Ec2Restart AWSChaosAction = "ec2-restart" // DetachVolume represents the chaos action of detaching the volume of ec2. - DetachVolume AwsChaosAction = "detach-volume" + DetachVolume AWSChaosAction = "detach-volume" ) -// AwsChaosSpec is the content of the specification for an AwsChaos -type AwsChaosSpec struct { +// AWSChaosSpec is the content of the specification for an AWSChaos +type AWSChaosSpec struct { // Action defines the specific aws chaos action. // Supported action: ec2-stop / ec2-restart / detach-volume // Default action: ec2-stop // +kubebuilder:validation:Enum=ec2-stop;ec2-restart;detach-volume - Action AwsChaosAction `json:"action"` + Action AWSChaosAction `json:"action"` // Duration represents the duration of the chaos action. // +optional - Duration *string `json:"duration,omitempty"` + Duration *string `json:"duration,omitempty" webhook:"Duration"` - // Scheduler defines some schedule rules to control the running time of the chaos experiment about time. + // SecretName defines the name of kubernetes secret. // +optional - Scheduler *SchedulerSpec `json:"scheduler,omitempty"` + SecretName *string `json:"secretName,omitempty" webhook:",nilable"` - // SecretName defines the name of kubernetes secret. + AWSSelector `json:",inline"` + + // RemoteCluster represents the remote cluster where the chaos will be deployed // +optional - SecretName *string `json:"secretName,omitempty"` + RemoteCluster string `json:"remoteCluster,omitempty"` +} - // AwsRegion defines the region of aws. - AwsRegion string `json:"awsRegion"` +// AWSChaosStatus represents the status of an AWSChaos +type AWSChaosStatus struct { + ChaosStatus `json:",inline"` +} + +type AWSSelector struct { + // TODO: it would be better to split them into multiple different selector and implementation + // but to keep the minimal modification on current implementation, it hasn't been splited. + + // Endpoint indicates the endpoint of the aws server. Just used it in test now. + // +ui:form:ignore + // +optional + Endpoint *string `json:"endpoint,omitempty"` + + // AWSRegion defines the region of aws. + AWSRegion string `json:"awsRegion"` // Ec2Instance indicates the ID of the ec2 instance. Ec2Instance string `json:"ec2Instance"` // EbsVolume indicates the ID of the EBS volume. // Needed in detach-volume. + // +ui:form:when=action=='detach-volume' // +optional - EbsVolume *string `json:"volumeID,omitempty"` + EbsVolume *string `json:"volumeID,omitempty" webhook:"EbsVolume,nilable"` // DeviceName indicates the name of the device. // Needed in detach-volume. + // +ui:form:when=action=='detach-volume' // +optional - DeviceName *string `json:"deviceName,omitempty"` + DeviceName *string `json:"deviceName,omitempty" webhook:"AWSDeviceName,nilable"` +} - // Endpoint indicates the endpoint of the aws server. Just used it in test now. - // +optional - Endpoint *string `json:"endpoint,omitempty"` +func (obj *AWSChaos) GetSelectorSpecs() map[string]interface{} { + return map[string]interface{}{ + ".": &obj.Spec.AWSSelector, + } } -// AwsChaosStatus represents the status of an AwsChaos -type AwsChaosStatus struct { - ChaosStatus `json:",inline"` +func (selector *AWSSelector) Id() string { + // TODO: handle the error here + // or ignore it is enough ? + json, _ := json.Marshal(selector) + + return string(json) } diff --git a/api/v1alpha1/awschaos_types_test.go b/api/v1alpha1/awschaos_types_test.go index 04da0332f1..3188cdaf90 100644 --- a/api/v1alpha1/awschaos_types_test.go +++ b/api/v1alpha1/awschaos_types_test.go @@ -1,25 +1,25 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "context" - "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) @@ -27,10 +27,10 @@ import ( // These tests are written in BDD-style using Ginkgo framework. Refer to // http://onsi.github.io/ginkgo to learn more. -var _ = Describe("AwsChaos", func() { +var _ = Describe("AWSChaos", func() { var ( key types.NamespacedName - created, fetched *AwsChaos + created, fetched *AWSChaos ) BeforeEach(func() { @@ -50,22 +50,24 @@ var _ = Describe("AwsChaos", func() { Namespace: "default", } - created = &AwsChaos{ + created = &AWSChaos{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: "default", }, - Spec: AwsChaosSpec{ - Action: Ec2Stop, - Ec2Instance: testInstance, - SecretName: &testSecretName, + Spec: AWSChaosSpec{ + Action: Ec2Stop, + AWSSelector: AWSSelector{ + Ec2Instance: testInstance, + }, + SecretName: &testSecretName, }, } By("creating an API obj") Expect(k8sClient.Create(context.TODO(), created)).To(Succeed()) - fetched = &AwsChaos{} + fetched = &AWSChaos{} Expect(k8sClient.Get(context.TODO(), key, fetched)).To(Succeed()) Expect(fetched).To(Equal(created)) @@ -73,19 +75,5 @@ var _ = Describe("AwsChaos", func() { Expect(k8sClient.Delete(context.TODO(), created)).To(Succeed()) Expect(k8sClient.Get(context.TODO(), key, created)).ToNot(Succeed()) }) - - It("should set next start time successfully", func() { - awschaos := &AwsChaos{} - nTime := time.Now() - awschaos.SetNextStart(nTime) - Expect(awschaos.GetNextStart()).To(Equal(nTime)) - }) - - It("should set recover time successfully", func() { - awschaos := &AwsChaos{} - nTime := time.Now() - awschaos.SetNextRecover(nTime) - Expect(awschaos.GetNextRecover()).To(Equal(nTime)) - }) }) }) diff --git a/api/v1alpha1/awschaos_webhook.go b/api/v1alpha1/awschaos_webhook.go index 4f150c4c4f..4295f59eef 100644 --- a/api/v1alpha1/awschaos_webhook.go +++ b/api/v1alpha1/awschaos_webhook.go @@ -1,132 +1,78 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - "fmt" + "reflect" - "k8s.io/apimachinery/pkg/runtime" + "github.com/pkg/errors" "k8s.io/apimachinery/pkg/util/validation/field" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/webhook" -) - -// log is for logging in this package. -var awschaoslog = logf.Log.WithName("awschaos-resource") - -// +kubebuilder:webhook:path=/mutate-chaos-mesh-org-v1alpha1-awschaos,mutating=true,failurePolicy=fail,groups=chaos-mesh.org,resources=awschaos,verbs=create;update,versions=v1alpha1,name=mawschaos.kb.io - -var _ webhook.Defaulter = &AwsChaos{} -// Default implements webhook.Defaulter so a webhook will be registered for the type -func (in *AwsChaos) Default() { - awschaoslog.Info("default", "name", in.Name) -} - -// +kubebuilder:webhook:verbs=create;update,path=/validate-chaos-mesh-org-v1alpha1-awschaos,mutating=false,failurePolicy=fail,groups=chaos-mesh.org,resources=awschaos,versions=v1alpha1,name=vawschaos.kb.io + "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" +) -var _ ChaosValidator = &AwsChaos{} +type EbsVolume string +type AWSDeviceName string -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (in *AwsChaos) ValidateCreate() error { - awschaoslog.Info("validate create", "name", in.Name) - return in.Validate() -} - -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (in *AwsChaos) ValidateUpdate(old runtime.Object) error { - awschaoslog.Info("validate update", "name", in.Name) - return in.Validate() -} +func (in *EbsVolume) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} -// ValidateDelete implements webhook.Validator so a webhook will be registered for the type -func (in *AwsChaos) ValidateDelete() error { - awschaoslog.Info("validate delete", "name", in.Name) + awsChaos := root.(*AWSChaos) + if awsChaos.Spec.Action == DetachVolume { + if in == nil { + err := errors.Wrapf(errInvalidValue, "the ID of EBS volume is required on %s action", awsChaos.Spec.Action) + allErrs = append(allErrs, field.Invalid(path, in, err.Error())) + } + } - // Nothing to do? - return nil + return allErrs } -// Validate validates chaos object -func (in *AwsChaos) Validate() error { - specField := field.NewPath("spec") - allErrs := in.ValidateScheduler(specField) - allErrs = append(allErrs, in.ValidatePodMode(specField)...) - allErrs = append(allErrs, in.Spec.validateEbsVolume(specField.Child("volumeID"))...) - allErrs = append(allErrs, in.Spec.validateDeviceName(specField.Child("deviceName"))...) +func (in *AWSDeviceName) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} - if len(allErrs) > 0 { - return fmt.Errorf(allErrs.ToAggregate().Error()) + awsChaos := root.(*AWSChaos) + if awsChaos.Spec.Action == DetachVolume { + if in == nil { + err := errors.Wrapf(errInvalidValue, "the name of device is required on %s action", awsChaos.Spec.Action) + allErrs = append(allErrs, field.Invalid(path, in, err.Error())) + } } - return nil + + return allErrs } -// ValidateScheduler validates the scheduler and duration -func (in *AwsChaos) ValidateScheduler(spec *field.Path) field.ErrorList { +// Validate validates aws chaos actions +func (in *AWSChaosAction) Validate(root interface{}, path *field.Path) field.ErrorList { allErrs := field.ErrorList{} - schedulerField := spec.Child("scheduler") - switch in.Spec.Action { + // in cannot be nil + switch *in { case Ec2Stop, DetachVolume: - allErrs = append(allErrs, ValidateScheduler(in, spec)...) case Ec2Restart: - // We choose to ignore the Duration property even user define it - if in.Spec.Scheduler != nil { - _, err := ParseCron(in.Spec.Scheduler.Cron, schedulerField.Child("cron")) - allErrs = append(allErrs, err...) - } default: - err := fmt.Errorf("awschaos[%s/%s] have unknown action type", in.Namespace, in.Name) - log.Error(err, "Wrong AwsChaos Action type") + err := errors.WithStack(errUnknownAction) + log.Error(err, "Wrong AWSChaos Action type") - actionField := spec.Child("action") - allErrs = append(allErrs, field.Invalid(actionField, in.Spec.Action, err.Error())) + allErrs = append(allErrs, field.Invalid(path, in, err.Error())) } return allErrs } -// ValidatePodMode validates the value with podmode -func (in *AwsChaos) ValidatePodMode(spec *field.Path) field.ErrorList { - // Because aws chaos does not need a pod mode, so return nil here. - return nil -} - -// SelectSpec returns the selector config for authority validate -func (in *AwsChaos) GetSelectSpec() []SelectSpec { - return nil -} - -// validateEbsVolume validates the EbsVolume -func (in *AwsChaosSpec) validateEbsVolume(containerField *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if in.Action == DetachVolume { - if in.EbsVolume == nil { - err := fmt.Errorf("the ID of EBS volume should not be empty on %s action", in.Action) - allErrs = append(allErrs, field.Invalid(containerField, in.EbsVolume, err.Error())) - } - } - return allErrs -} - -// validateDeviceName validates the DeviceName -func (in *AwsChaosSpec) validateDeviceName(containerField *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if in.Action == DetachVolume { - if in.DeviceName == nil { - err := fmt.Errorf("the name of device should not be empty on %s action", in.Action) - allErrs = append(allErrs, field.Invalid(containerField, in.DeviceName, err.Error())) - } - } - return allErrs +func init() { + genericwebhook.Register("EbsVolume", reflect.PtrTo(reflect.TypeOf(EbsVolume("")))) + genericwebhook.Register("AWSDeviceName", reflect.PtrTo(reflect.TypeOf(AWSDeviceName("")))) } diff --git a/api/v1alpha1/awschaos_webhook_test.go b/api/v1alpha1/awschaos_webhook_test.go index fec7e55261..a79989fa75 100644 --- a/api/v1alpha1/awschaos_webhook_test.go +++ b/api/v1alpha1/awschaos_webhook_test.go @@ -1,134 +1,107 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) var _ = Describe("awschaos_webhook", func() { - Context("ChaosValidator of awschaos", func() { + Context("webhook.Validator of awschaos", func() { It("Validate", func() { type TestCase struct { name string - chaos AwsChaos - execute func(chaos *AwsChaos) error + chaos AWSChaos + execute func(chaos *AWSChaos) error expect string } - duration := "400s" testDeviceName := "testDeviceName" testEbsVolume := "testEbsVolume" tcs := []TestCase{ { name: "simple ValidateCreate for DetachVolume", - chaos: AwsChaos{ + chaos: AWSChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo1", }, - Spec: AwsChaosSpec{ + Spec: AWSChaosSpec{ Action: DetachVolume, }, }, - execute: func(chaos *AwsChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "only define the Scheduler and execute Ec2Stop", - chaos: AwsChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo4", - }, - Spec: AwsChaosSpec{ - Scheduler: &SchedulerSpec{ - Cron: "@every 10m", - }, - Action: Ec2Stop, - }, - }, - execute: func(chaos *AwsChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "only define the Duration and execute Ec2Stop", - chaos: AwsChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo5", - }, - Spec: AwsChaosSpec{ - Action: Ec2Stop, - Duration: &duration, - }, - }, - execute: func(chaos *AwsChaos) error { - return chaos.ValidateCreate() + execute: func(chaos *AWSChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, { name: "unknow action", - chaos: AwsChaos{ + chaos: AWSChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo6", }, }, - execute: func(chaos *AwsChaos) error { - return chaos.ValidateCreate() + execute: func(chaos *AWSChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, { name: "validate the DetachVolume without EbsVolume", - chaos: AwsChaos{ + chaos: AWSChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo7", }, - Spec: AwsChaosSpec{ - Action: DetachVolume, - DeviceName: &testDeviceName, + Spec: AWSChaosSpec{ + Action: DetachVolume, + AWSSelector: AWSSelector{ + DeviceName: &testDeviceName, + }, }, }, - execute: func(chaos *AwsChaos) error { - return chaos.ValidateCreate() + execute: func(chaos *AWSChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, { name: "validate the DetachVolume without DeviceName", - chaos: AwsChaos{ + chaos: AWSChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo7", }, - Spec: AwsChaosSpec{ - Action: DetachVolume, - EbsVolume: &testEbsVolume, + Spec: AWSChaosSpec{ + Action: DetachVolume, + AWSSelector: AWSSelector{ + EbsVolume: &testEbsVolume, + }, }, }, - execute: func(chaos *AwsChaos) error { - return chaos.ValidateCreate() + execute: func(chaos *AWSChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, diff --git a/api/v1alpha1/azurechaos_types.go b/api/v1alpha1/azurechaos_types.go new file mode 100644 index 0000000000..32c02f3623 --- /dev/null +++ b/api/v1alpha1/azurechaos_types.go @@ -0,0 +1,115 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "encoding/json" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +// +kubebuilder:printcolumn:name="action",type=string,JSONPath=`.spec.action` +// +kubebuilder:printcolumn:name="duration",type=string,JSONPath=`.spec.duration` +// +chaos-mesh:experiment +// +chaos-mesh:oneshot=in.Spec.Action==AzureVmRestart + +// AzureChaos is the Schema for the azurechaos API +type AzureChaos struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AzureChaosSpec `json:"spec"` + Status AzureChaosStatus `json:"status,omitempty"` +} + +var _ InnerObjectWithSelector = (*AzureChaos)(nil) +var _ InnerObject = (*AzureChaos)(nil) + +// AzureChaosAction represents the chaos action about azure. +type AzureChaosAction string + +const ( + // AzureVmStop represents the chaos action of stopping vm. + AzureVmStop AzureChaosAction = "vm-stop" + // AzureVmRestart represents the chaos action of restarting vm. + AzureVmRestart AzureChaosAction = "vm-restart" + // AzureDiskDetach represents the chaos action of detaching the disk from vm. + AzureDiskDetach AzureChaosAction = "disk-detach" +) + +// AzureChaosSpec is the content of the specification for an AzureChaos +type AzureChaosSpec struct { + // Action defines the specific azure chaos action. + // Supported action: vm-stop / vm-restart / disk-detach + // Default action: vm-stop + // +kubebuilder:validation:Enum=vm-stop;vm-restart;disk-detach + Action AzureChaosAction `json:"action"` + + // Duration represents the duration of the chaos action. + // +optional + Duration *string `json:"duration,omitempty" webhook:"Duration"` + + AzureSelector `json:",inline"` +} + +// AzureChaosStatus represents the status of an AzureChaos +type AzureChaosStatus struct { + ChaosStatus `json:",inline"` +} + +type AzureSelector struct { + // SubscriptionID defines the id of Azure subscription. + SubscriptionID string `json:"subscriptionID"` + + // ResourceGroupName defines the name of ResourceGroup + ResourceGroupName string `json:"resourceGroupName"` + + // VMName defines the name of Virtual Machine + VMName string `json:"vmName"` + + // DiskName indicates the name of the disk. + // Needed in disk-detach. + // +optional + DiskName *string `json:"diskName,omitempty" webhook:"DiskName,nilable"` + + // LUN indicates the Logical Unit Number of the data disk. + // Needed in disk-detach. + // +optional + LUN *int `json:"lun,omitempty" webhook:"LUN,nilable"` + + // SecretName defines the name of kubernetes secret. It is used for Azure credentials. + // +optional + SecretName *string `json:"secretName,omitempty"` + + // RemoteCluster represents the remote cluster where the chaos will be deployed + // +optional + RemoteCluster string `json:"remoteCluster,omitempty"` +} + +func (obj *AzureChaos) GetSelectorSpecs() map[string]interface{} { + return map[string]interface{}{ + ".": &obj.Spec.AzureSelector, + } +} + +func (selector *AzureSelector) Id() string { + // TODO: handle the error here + // or ignore it is enough ? + json, _ := json.Marshal(selector) + + return string(json) +} diff --git a/api/v1alpha1/azurechaos_types_test.go b/api/v1alpha1/azurechaos_types_test.go new file mode 100644 index 0000000000..1525880682 --- /dev/null +++ b/api/v1alpha1/azurechaos_types_test.go @@ -0,0 +1,82 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// These tests are written in BDD-style using Ginkgo framework. Refer to +// http://onsi.github.io/ginkgo to learn more. + +var _ = Describe("AzureChaos", func() { + var ( + key types.NamespacedName + created, fetched *AzureChaos + ) + + BeforeEach(func() { + // Add any setup steps that needs to be executed before each test + }) + + AfterEach(func() { + // Add any teardown steps that needs to be executed after each test + }) + + Context("Create API", func() { + It("should create an object successfully", func() { + testSubscriptionID := "testSubscriptionID" + testResourceGroupName := "testResourceGroupName" + testVMName := "testVMName" + + key = types.NamespacedName{ + Name: "foo", + Namespace: "default", + } + + created = &AzureChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + }, + Spec: AzureChaosSpec{ + Action: AzureVmStop, + AzureSelector: AzureSelector{ + SubscriptionID: testSubscriptionID, + ResourceGroupName: testResourceGroupName, + VMName: testVMName, + }, + }, + } + + By("creating an API obj") + Expect(k8sClient.Create(context.TODO(), created)).To(Succeed()) + + fetched = &AzureChaos{} + Expect(k8sClient.Get(context.TODO(), key, fetched)).To(Succeed()) + Expect(fetched).To(Equal(created)) + + By("deleting the created object") + Expect(k8sClient.Delete(context.TODO(), created)).To(Succeed()) + Expect(k8sClient.Get(context.TODO(), key, created)).ToNot(Succeed()) + }) + }) +}) diff --git a/api/v1alpha1/azurechaos_webhook.go b/api/v1alpha1/azurechaos_webhook.go new file mode 100644 index 0000000000..4329214af2 --- /dev/null +++ b/api/v1alpha1/azurechaos_webhook.go @@ -0,0 +1,78 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "fmt" + "reflect" + + "k8s.io/apimachinery/pkg/util/validation/field" + + "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" +) + +type DiskName string +type LUN int + +func (in *DiskName) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + azurechaos := root.(*AzureChaos) + if azurechaos.Spec.Action == AzureDiskDetach { + if in == nil { + err := fmt.Errorf("the name of data disk should not be empty on %s action", azurechaos.Spec.Action) + allErrs = append(allErrs, field.Invalid(path, in, err.Error())) + } + } + + return allErrs +} + +func (in *LUN) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + azurechaos := root.(*AzureChaos) + if azurechaos.Spec.Action == AzureDiskDetach { + if in == nil { + err := fmt.Errorf("the LUN of data disk should not be empty on %s action", azurechaos.Spec.Action) + allErrs = append(allErrs, field.Invalid(path, in, err.Error())) + } + } + + return allErrs +} + +// Validate validates the azure chaos actions +func (in *AzureChaosAction) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + // in cannot be nil + switch *in { + case AzureVmStop, AzureDiskDetach: + case AzureVmRestart: + default: + err := fmt.Errorf("azurechaos have unknown action type") + log.Error(err, "Wrong AzureChaos Action type") + + allErrs = append(allErrs, field.Invalid(path, in, err.Error())) + } + return allErrs +} + +func init() { + genericwebhook.Register("DiskName", reflect.PtrTo(reflect.TypeOf(DiskName("")))) + genericwebhook.Register("LUN", reflect.PtrTo(reflect.TypeOf(LUN(0)))) +} diff --git a/api/v1alpha1/azurechaos_webhook_test.go b/api/v1alpha1/azurechaos_webhook_test.go new file mode 100644 index 0000000000..c44cef7b07 --- /dev/null +++ b/api/v1alpha1/azurechaos_webhook_test.go @@ -0,0 +1,120 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("azurechaos_webhook", func() { + Context("webhook.Validator of azurechaos", func() { + It("Validate", func() { + + type TestCase struct { + name string + chaos AzureChaos + execute func(chaos *AzureChaos) error + expect string + } + testDiskName := "testDiskName" + testLUN := 0 + tcs := []TestCase{ + { + name: "simple ValidateCreate for disk-detach", + chaos: AzureChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo1", + }, + Spec: AzureChaosSpec{ + Action: AzureDiskDetach, + }, + }, + execute: func(chaos *AzureChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "unknow action", + chaos: AzureChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo6", + }, + }, + execute: func(chaos *AzureChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate the disk-detach without LUN", + chaos: AzureChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo7", + }, + Spec: AzureChaosSpec{ + Action: AzureDiskDetach, + AzureSelector: AzureSelector{ + DiskName: &testDiskName, + }, + }, + }, + execute: func(chaos *AzureChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate the DetachVolume without DiskName", + chaos: AzureChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo7", + }, + Spec: AzureChaosSpec{ + Action: AzureDiskDetach, + AzureSelector: AzureSelector{ + LUN: &testLUN, + }, + }, + }, + execute: func(chaos *AzureChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + } + + for _, tc := range tcs { + err := tc.execute(&tc.chaos) + if tc.expect == "error" { + Expect(err).To(HaveOccurred()) + } else { + Expect(err).NotTo(HaveOccurred()) + } + } + }) + }) +}) diff --git a/api/v1alpha1/blockchaos_types.go b/api/v1alpha1/blockchaos_types.go new file mode 100644 index 0000000000..bd3a0c7c21 --- /dev/null +++ b/api/v1alpha1/blockchaos_types.go @@ -0,0 +1,98 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +kubebuilder:object:root=true +// +kubebuilder:printcolumn:name="action",type=string,JSONPath=`.spec.action` +// +kubebuilder:printcolumn:name="duration",type=string,JSONPath=`.spec.duration` +// +chaos-mesh:experiment + +// BlockChaos is the Schema for the blockchaos API +type BlockChaos struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec BlockChaosSpec `json:"spec"` + Status BlockChaosStatus `json:"status,omitempty"` +} + +type BlockChaosAction string + +const ( + BlockDelay BlockChaosAction = "delay" +) + +// BlockChaosSpec is the content of the specification for a BlockChaos +type BlockChaosSpec struct { + // Action defines the specific block chaos action. + // Supported action: delay + // +kubebuilder:validation:Enum=delay + Action BlockChaosAction `json:"action"` + + // Delay defines the delay distribution. + // +optional + Delay *BlockDelaySpec `json:"delay,omitempty"` + + ContainerNodeVolumePathSelector `json:",inline"` + + // Duration represents the duration of the chaos action. + // +optional + Duration *string `json:"duration,omitempty" webhook:"Duration"` + + // RemoteCluster represents the remote cluster where the chaos will be deployed + // +optional + RemoteCluster string `json:"remoteCluster,omitempty"` +} + +// BlockDelaySpec describes the block delay specification +type BlockDelaySpec struct { + // Latency defines the latency of every io request. + Latency string `json:"latency,omitempty" webhook:"Duration"` + + // +optional + Correlation string `json:"correlation,omitempty" default:"0" webhook:"FloatStr"` + + // +optional + Jitter string `json:"jitter,omitempty" default:"0ms" webhook:"Duration"` +} + +// ContainerNodeVolumePathSelector is the selector to select a node and a PV on it +type ContainerNodeVolumePathSelector struct { + ContainerSelector `json:",inline"` + + VolumeName string `json:"volumeName"` +} + +// BlockChaosStatus represents the status of a BlockChaos +type BlockChaosStatus struct { + ChaosStatus `json:",inline"` + + // InjectionIds always specifies the number of injected chaos action + // +optional + InjectionIds map[string]int `json:"ids,omitempty"` +} + +func (obj *BlockChaos) GetSelectorSpecs() map[string]interface{} { + return map[string]interface{}{ + ".": &obj.Spec.ContainerNodeVolumePathSelector, + } +} + +func (obj *BlockChaos) GetCustomStatus() interface{} { + return &obj.Status.InjectionIds +} diff --git a/api/v1alpha1/blockchaos_webhook.go b/api/v1alpha1/blockchaos_webhook.go new file mode 100644 index 0000000000..4ed6247465 --- /dev/null +++ b/api/v1alpha1/blockchaos_webhook.go @@ -0,0 +1,32 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func (in *BlockChaosSpec) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if in.Action == BlockDelay { + if in.Delay == nil { + err := errors.Errorf("delay should be set on %s action", in.Action) + allErrs = append(allErrs, field.Invalid(path.Child("delay"), in.Delay, err.Error())) + } + } + return allErrs +} diff --git a/api/v1alpha1/blockchaos_webhook_test.go b/api/v1alpha1/blockchaos_webhook_test.go new file mode 100644 index 0000000000..6e743f5167 --- /dev/null +++ b/api/v1alpha1/blockchaos_webhook_test.go @@ -0,0 +1,269 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("blockchaos_webhook", func() { + Context("webhook.Validator of blockchaos", func() { + It("Validate", func() { + + type TestCase struct { + name string + chaos BlockChaos + execute func(chaos *BlockChaos) error + expect string + } + errorDuration := "400S" + + tcs := []TestCase{ + { + name: "simple ValidateCreate", + chaos: BlockChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo1", + }, + }, + execute: func(chaos *BlockChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "", + }, + { + name: "simple ValidateUpdate", + chaos: BlockChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo2", + }, + }, + execute: func(chaos *BlockChaos) error { + _, err := chaos.ValidateUpdate(chaos) + return err + }, + expect: "", + }, + { + name: "simple ValidateDelete", + chaos: BlockChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo3", + }, + }, + execute: func(chaos *BlockChaos) error { + _, err := chaos.ValidateDelete() + return err + }, + expect: "", + }, + { + name: "parse the duration error", + chaos: BlockChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo6", + }, + Spec: BlockChaosSpec{ + Duration: &errorDuration, + }, + }, + execute: func(chaos *BlockChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate value with FixedPercentMode", + chaos: BlockChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo7", + }, + Spec: BlockChaosSpec{ + ContainerNodeVolumePathSelector: ContainerNodeVolumePathSelector{ + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Value: "0", + Mode: FixedMode, + }, + }, + VolumeName: "", + }, + }, + }, + execute: func(chaos *BlockChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate value with FixedPercentMode, parse value error", + chaos: BlockChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo8", + }, + Spec: BlockChaosSpec{ + ContainerNodeVolumePathSelector: ContainerNodeVolumePathSelector{ + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Value: "num", + Mode: FixedMode, + }, + }, + VolumeName: "", + }, + }, + }, + execute: func(chaos *BlockChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate value with RandomMaxPercentMode", + chaos: BlockChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo9", + }, + Spec: BlockChaosSpec{ + ContainerNodeVolumePathSelector: ContainerNodeVolumePathSelector{ + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Value: "0", + Mode: RandomMaxPercentMode, + }, + }, + VolumeName: "", + }, + }, + }, + execute: func(chaos *BlockChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate value with RandomMaxPercentMode ,parse value error", + chaos: BlockChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo10", + }, + Spec: BlockChaosSpec{ + ContainerNodeVolumePathSelector: ContainerNodeVolumePathSelector{ + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Value: "num", + Mode: RandomMaxPercentMode, + }, + }, + }, + }, + }, + execute: func(chaos *BlockChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate value with FixedPercentMode", + chaos: BlockChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo11", + }, + Spec: BlockChaosSpec{ + ContainerNodeVolumePathSelector: ContainerNodeVolumePathSelector{ + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Value: "101", + Mode: FixedPercentMode, + }, + }, + }, + }, + }, + execute: func(chaos *BlockChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate delay", + chaos: BlockChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo12", + }, + Spec: BlockChaosSpec{ + Action: BlockDelay, + Delay: nil, + }, + }, + execute: func(chaos *BlockChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate delay", + chaos: BlockChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo13", + }, + Spec: BlockChaosSpec{ + Action: BlockDelay, + Delay: &BlockDelaySpec{ + Latency: "1SSS", + }, + }, + }, + execute: func(chaos *BlockChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + } + + for _, tc := range tcs { + err := tc.execute(&tc.chaos) + if tc.expect == "error" { + Expect(err).To(HaveOccurred()) + } else { + Expect(err).NotTo(HaveOccurred()) + } + } + }) + }) +}) diff --git a/api/v1alpha1/common_errors.go b/api/v1alpha1/common_errors.go new file mode 100644 index 0000000000..5fe19d60fa --- /dev/null +++ b/api/v1alpha1/common_errors.go @@ -0,0 +1,25 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "github.com/pkg/errors" +) + +var ( + errUnknownAction = errors.New("unknown action") + errInvalidValue = errors.New("invalid value") +) diff --git a/api/v1alpha1/common_types.go b/api/v1alpha1/common_types.go index d5a8b77e0e..438b9b5164 100644 --- a/api/v1alpha1/common_types.go +++ b/api/v1alpha1/common_types.go @@ -1,305 +1,185 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "time" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/webhook" ) const ( // PauseAnnotationKey defines the annotation used to pause a chaos PauseAnnotationKey = "experiment.chaos-mesh.org/pause" + LabelManagedBy = "managed-by" ) -// LabelSelectorRequirements is list of LabelSelectorRequirement -type LabelSelectorRequirements []metav1.LabelSelectorRequirement - -// +kubebuilder:object:generate=false - -// SelectSpec defines a common interface for selector -type SelectSpec interface { - GetSelector() SelectorSpec - GetMode() PodMode - GetValue() string -} - -// SelectorSpec defines the some selectors to select objects. -// If the all selectors are empty, all objects will be used in chaos experiment. -type SelectorSpec struct { - // Namespaces is a set of namespace to which objects belong. - // +optional - Namespaces []string `json:"namespaces,omitempty"` - - // Nodes is a set of node name and objects must belong to these nodes. +type ChaosStatus struct { + // Conditions represents the current global condition of the chaos // +optional - Nodes []string `json:"nodes,omitempty"` + Conditions []ChaosCondition `json:"conditions,omitempty"` - // Pods is a map of string keys and a set values that used to select pods. - // The key defines the namespace which pods belong, - // and the each values is a set of pod names. - // +optional - Pods map[string][]string `json:"pods,omitempty"` + // Experiment records the last experiment state. + Experiment ExperimentStatus `json:"experiment"` +} - // Map of string keys and values that can be used to select nodes. - // Selector which must match a node's labels, - // and objects must belong to these selected nodes. - // +optional - NodeSelectors map[string]string `json:"nodeSelectors,omitempty"` +type ChaosConditionType string - // Map of string keys and values that can be used to select objects. - // A selector based on fields. - // +optional - FieldSelectors map[string]string `json:"fieldSelectors,omitempty"` +const ( + ConditionSelected ChaosConditionType = "Selected" + ConditionAllInjected ChaosConditionType = "AllInjected" + ConditionAllRecovered ChaosConditionType = "AllRecovered" + ConditionPaused ChaosConditionType = "Paused" +) - // Map of string keys and values that can be used to select objects. - // A selector based on labels. +type ChaosCondition struct { + Type ChaosConditionType `json:"type"` + Status corev1.ConditionStatus `json:"status"` // +optional - LabelSelectors map[string]string `json:"labelSelectors,omitempty"` + Reason string `json:"reason,omitempty"` +} - // a slice of label selector expressions that can be used to select objects. - // A list of selectors based on set-based label expressions. - // +optional - ExpressionSelectors LabelSelectorRequirements `json:"expressionSelectors,omitempty"` +type DesiredPhase string - // Map of string keys and values that can be used to select objects. - // A selector based on annotations. - // +optional - AnnotationSelectors map[string]string `json:"annotationSelectors,omitempty"` +const ( + // The target of `RunningPhase` is to make all selected targets (container or pod) into "Injected" phase + RunningPhase DesiredPhase = "Run" + // The target of `StoppedPhase` is to make all selected targets (container or pod) into "NotInjected" phase + StoppedPhase DesiredPhase = "Stop" +) - // PodPhaseSelectors is a set of condition of a pod at the current time. - // supported value: Pending / Running / Succeeded / Failed / Unknown +type ExperimentStatus struct { + // +kubebuilder:validation:Enum=Run;Stop + DesiredPhase `json:"desiredPhase,omitempty"` // +optional - PodPhaseSelectors []string `json:"podPhaseSelectors,omitempty"` + // Records are used to track the running status + Records []*Record `json:"containerRecords,omitempty"` } -// ClusterScoped returns true if the selector selects Pods in the cluster -func (s SelectorSpec) ClusterScoped() bool { - // in fact, this will never happened, will add namespace if it is empty, so len(s.Namespaces) can not be 0, - // but still add judgentment here for safe - // https://github.com/chaos-mesh/chaos-mesh/blob/478d00d01bb0f9fb08a1085428a7da8c8f9df4e8/api/v1alpha1/common_webhook.go#L22 - if len(s.Namespaces) == 0 && len(s.Pods) == 0 { - return true - } - - return false +type Record struct { + Id string `json:"id"` + SelectorKey string `json:"selectorKey"` + Phase Phase `json:"phase"` + // InjectedCount is a counter to record the sum of successful injections + InjectedCount int `json:"injectedCount"` + // RecoveredCount is a counter to record the sum of successful recoveries + RecoveredCount int `json:"recoveredCount"` + // Events are the essential details about the injections and recoveries + Events []RecordEvent `json:"events,omitempty"` } -// AffectedNamespaces returns all the namespaces which the selector effect -func (s SelectorSpec) AffectedNamespaces() []string { - affectedNamespacesMap := make(map[string]struct{}) - affectedNamespacesArray := make([]string, 0, 2) - - for namespace := range s.Pods { - affectedNamespacesMap[namespace] = struct{}{} - } - - for _, namespace := range s.Namespaces { - affectedNamespacesMap[namespace] = struct{}{} - } - - for namespace := range affectedNamespacesMap { - affectedNamespacesArray = append(affectedNamespacesArray, namespace) - } +type Phase string - return affectedNamespacesArray -} +const ( + // NotInjected means the target is not injected yet. The controller could call "Inject" on the target + NotInjected Phase = "Not Injected" + // Injected means the target is injected. It's safe to recover it. + Injected Phase = "Injected" +) -// SchedulerSpec defines information about schedule of the chaos experiment. -type SchedulerSpec struct { - // Cron defines a cron job rule. - // - // Some rule examples: - // "0 30 * * * *" means to "Every hour on the half hour" - // "@hourly" means to "Every hour" - // "@every 1h30m" means to "Every hour thirty" - // - // More rule info: https://godoc.org/github.com/robfig/cron - Cron string `json:"cron"` +type RecordEvent struct { + // Type means the stage of this event + Type RecordEventType `json:"type"` + // Operation represents the operation we are doing, when we crate this event + Operation RecordEventOperation `json:"operation"` + // Message is the detail message, e.g. the reason why we failed to inject the chaos + Message string `json:"message,omitempty"` + // Timestamp is time when we create this event + Timestamp *metav1.Time `json:"timestamp"` } -// PodMode represents the mode to run pod chaos action. -type PodMode string +type RecordEventType string const ( - // OnePodMode represents that the system will do the chaos action on one pod selected randomly. - OnePodMode PodMode = "one" - // AllPodMode represents that the system will do the chaos action on all pods - // regardless of status (not ready or not running pods includes). - // Use this label carefully. - AllPodMode PodMode = "all" - // FixedPodMode represents that the system will do the chaos action on a specific number of running pods. - FixedPodMode PodMode = "fixed" - // FixedPercentPodMode to specify a fixed % that can be inject chaos action. - FixedPercentPodMode PodMode = "fixed-percent" - // RandomMaxPercentPodMode to specify a maximum % that can be inject chaos action. - RandomMaxPercentPodMode PodMode = "random-max-percent" + // TypeSucceeded means the stage of this event is successful + TypeSucceeded RecordEventType = "Succeeded" + // TypeFailed means the stage of this event is failed + TypeFailed RecordEventType = "Failed" ) -// ChaosPhase is the current status of chaos task. -type ChaosPhase string +type RecordEventOperation string const ( - ChaosPhaseNone ChaosPhase = "" - ChaosPhaseNormal ChaosPhase = "Normal" - ChaosPhaseAbnormal ChaosPhase = "Abnormal" + // Apply means this event is recorded, when we inject the chaos + // typically, when we call impl.Apply() + Apply RecordEventOperation = "Apply" + // Recover means this event is recorded, when we recover the chaos + // typically, when we call impl.Recover() + Recover RecordEventOperation = "Recover" ) -type ChaosStatus struct { - FailedMessage string `json:"failedMessage,omitempty"` - - Scheduler ScheduleStatus `json:"scheduler,omitempty"` - - // Experiment records the last experiment state. - Experiment ExperimentStatus `json:"experiment"` -} - -func (in *ChaosStatus) GetNextStart() time.Time { - if in.Scheduler.NextStart == nil { - return time.Time{} - } - return in.Scheduler.NextStart.Time -} - -func (in *ChaosStatus) SetNextStart(t time.Time) { - if t.IsZero() { - in.Scheduler.NextStart = nil - return - } - - if in.Scheduler.NextStart == nil { - in.Scheduler.NextStart = &metav1.Time{} +// NewRecordEvent is a constructor of RecordEvent in status +func NewRecordEvent(eventType RecordEventType, eventStage RecordEventOperation, + msg string, time metav1.Time) *RecordEvent { + return &RecordEvent{ + Type: eventType, + Operation: eventStage, + Message: msg, + Timestamp: &time, } - in.Scheduler.NextStart.Time = t } -func (in *ChaosStatus) GetNextRecover() time.Time { - if in.Scheduler.NextRecover == nil { - return time.Time{} - } - return in.Scheduler.NextRecover.Time -} - -func (in *ChaosStatus) SetNextRecover(t time.Time) { - if t.IsZero() { - in.Scheduler.NextRecover = nil - return - } - - if in.Scheduler.NextRecover == nil { - in.Scheduler.NextRecover = &metav1.Time{} - } - in.Scheduler.NextRecover.Time = t -} - -// ScheduleStatus is the current status of chaos scheduler. -type ScheduleStatus struct { - // Next time when this action will be applied again - // +optional - NextStart *metav1.Time `json:"nextStart,omitempty"` - - // Next time when this action will be recovered - // +optional - NextRecover *metav1.Time `json:"nextRecover,omitempty"` -} - -// ExperimentPhase is the current status of chaos experiment. -type ExperimentPhase string - -const ( - ExperimentPhaseUninitialized ExperimentPhase = "" - ExperimentPhaseRunning ExperimentPhase = "Running" - ExperimentPhaseWaiting ExperimentPhase = "Waiting" - ExperimentPhasePaused ExperimentPhase = "Paused" - ExperimentPhaseFailed ExperimentPhase = "Failed" - ExperimentPhaseFinished ExperimentPhase = "Finished" -) - -type ExperimentStatus struct { - // +optional - Phase ExperimentPhase `json:"phase,omitempty"` - // +optional - Reason string `json:"reason,omitempty"` - // +optional - StartTime *metav1.Time `json:"startTime,omitempty"` - // +optional - EndTime *metav1.Time `json:"endTime,omitempty"` - // +optional - Duration string `json:"duration,omitempty"` - // +optional - PodRecords []PodStatus `json:"podRecords,omitempty"` -} - -var log = ctrl.Log.WithName("validate-webhook") - -// +kubebuilder:object:generate=false - -// InnerSchedulerObject is the Object for the twophase reconcile -type InnerSchedulerObject interface { - InnerObject - GetDuration() (*time.Duration, error) - - GetNextStart() time.Time - SetNextStart(time.Time) - - GetNextRecover() time.Time - SetNextRecover(time.Time) - - GetScheduler() *SchedulerSpec -} +var log = ctrl.Log.WithName("api") // +kubebuilder:object:generate=false // InnerObject is basic Object for the Reconciler type InnerObject interface { + StatefulObject IsDeleted() bool IsPaused() bool - GetChaos() *ChaosInstance - GetSpecAndMetaString() (string, error) - StatefulObject + DurationExceeded(time.Time) (bool, time.Duration, error) + IsOneShot() bool } // +kubebuilder:object:generate=false // StatefulObject defines a basic Object that can get the status type StatefulObject interface { - runtime.Object + GenericChaos GetStatus() *ChaosStatus } // +kubebuilder:object:generate=false +type InnerObjectWithCustomStatus interface { + InnerObject -// ChaosInstance defines some common attribute for a chaos -type ChaosInstance struct { - Name string - Namespace string - Kind string - StartTime time.Time - EndTime time.Time - Action string - Duration string - Status string - UID string + GetCustomStatus() interface{} } // +kubebuilder:object:generate=false +type InnerObjectWithSelector interface { + InnerObject -// ChaosList defines a common interface for chaos lists -type ChaosList interface { - runtime.Object - ListChaos() []*ChaosInstance + GetSelectorSpecs() map[string]interface{} +} + +// +kubebuilder:object:generate=false + +// WebhookObject is basic Object which implement `webhook.Validator` and `webhook.Defaulter` +type WebhookObject interface { + webhook.Validator + webhook.Defaulter +} + +// +kubebuilder:object:generate=false +type RemoteObject interface { + StatefulObject + GetRemoteCluster() string } diff --git a/api/v1alpha1/common_validation.go b/api/v1alpha1/common_validation.go deleted file mode 100644 index acd75aa06e..0000000000 --- a/api/v1alpha1/common_validation.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package v1alpha1 - -import ( - "fmt" - "strconv" - "time" - - cronv3 "github.com/robfig/cron/v3" - - "k8s.io/apimachinery/pkg/util/validation/field" -) - -const ( - // ValidateSchedulerError defines the error message for ValidateScheduler - ValidateSchedulerError = "schedule and duration should be omitted or defined at the same time" - - // ValidatePodchaosSchedulerError defines the error message for ValidateScheduler of Podchaos - ValidatePodchaosSchedulerError = "schedule should be omitted" - - // ValidateValueParseError defines the error message for value parse error - ValidateValueParseError = "parse value field error:%s" -) - -// ValidateScheduler validates the InnerSchedulerObject -func ValidateScheduler(schedulerObject InnerSchedulerObject, spec *field.Path) field.ErrorList { - - allErrs := field.ErrorList{} - - schedulerField := spec.Child("scheduler") - durationField := spec.Child("duration") - duration, err := schedulerObject.GetDuration() - if err != nil { - allErrs = append(allErrs, field.Invalid(durationField, nil, - fmt.Sprintf("parse duration field error:%s", err))) - } - - scheduler := schedulerObject.GetScheduler() - - if duration != nil && scheduler != nil { - errs := validateSchedulerParams(duration, durationField, scheduler, schedulerField) - if len(errs) != 0 { - allErrs = append(allErrs, errs...) - } - } else if (duration == nil && scheduler != nil) || (duration != nil && scheduler == nil) { - allErrs = append(allErrs, field.Invalid(schedulerField, scheduler, ValidateSchedulerError)) - } - return allErrs -} - -func validateSchedulerParams(duration *time.Duration, durationField *field.Path, spec *SchedulerSpec, schedulerField *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if duration != nil && spec != nil { - cronField := schedulerField.Child("cron") - _, err := ParseCron(spec.Cron, cronField) - if len(err) != 0 { - allErrs = append(allErrs, err...) - } - } - return allErrs -} - -// ParseCron returns a new crontab schedule representing the given standardSpec (https://en.wikipedia.org/wiki/Cron) -func ParseCron(standardSpec string, cronField *field.Path) (cronv3.Schedule, field.ErrorList) { - allErrs := field.ErrorList{} - scheduler, err := cronv3.ParseStandard(standardSpec) - if err != nil { - allErrs = append(allErrs, field.Invalid(cronField, standardSpec, - fmt.Sprintf("parse cron field error:%s", err))) - } - return scheduler, allErrs -} - -// ValidatePodMode validates the value with podmode -func ValidatePodMode(value string, mode PodMode, valueField *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - - switch mode { - case FixedPodMode: - num, err := strconv.Atoi(value) - if err != nil { - allErrs = append(allErrs, field.Invalid(valueField, value, - fmt.Sprintf(ValidateValueParseError, err))) - break - } - - if num <= 0 { - allErrs = append(allErrs, field.Invalid(valueField, value, - fmt.Sprintf("value must be greater than 0 with mode:%s", FixedPodMode))) - } - - case RandomMaxPercentPodMode, FixedPercentPodMode: - percentage, err := strconv.Atoi(value) - if err != nil { - allErrs = append(allErrs, field.Invalid(valueField, value, - fmt.Sprintf(ValidateValueParseError, err))) - break - } - - if percentage <= 0 || percentage > 100 { - allErrs = append(allErrs, field.Invalid(valueField, value, - fmt.Sprintf("value of %d is invalid, Must be (0,100] with mode:%s", - percentage, mode))) - } - } - - return allErrs -} diff --git a/api/v1alpha1/common_webhook.go b/api/v1alpha1/common_webhook.go index 06e5869134..6d2b275b0b 100644 --- a/api/v1alpha1/common_webhook.go +++ b/api/v1alpha1/common_webhook.go @@ -1,43 +1,180 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( + "fmt" + "reflect" + "strconv" + "time" + + "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/util/validation/field" - "sigs.k8s.io/controller-runtime/pkg/webhook" + + "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" ) -// DefaultNamespace set the namespace of chaos object as the default namespace selector if namespaces not set -func (in *SelectorSpec) DefaultNamespace(namespace string) { - if len(in.Namespaces) == 0 { - in.Namespaces = []string{namespace} +const ( + // ValidateValueParseError defines the error message for value parse error + ValidateValueParseError = "parse value field error:%s" +) + +// FIXME: interface ContainsDuration only used for validating EmbedChaos in Workflow + +// +kubebuilder:object:generate=false +type ContainsDuration interface { + GetDuration() (*time.Duration, error) +} + +type Duration string + +func (d *Duration) Validate(root interface{}, path *field.Path) field.ErrorList { + if d == nil { + return nil + } + + if len(*d) == 0 { + // allow duration to be zero + // TODO: control by tag + return nil + } + + _, err := time.ParseDuration(string(*d)) + if err != nil { + return field.ErrorList{ + field.Invalid(path, d, fmt.Sprintf("parse duration field error: %s", err.Error())), + } } + + return nil } -// +kubebuilder:object:generate=false +func (d *Duration) Default(root interface{}, field *reflect.StructField) { + if d == nil { + return + } + + // d cannot be nil + if len(*d) == 0 && field != nil { + *d = Duration(field.Tag.Get("default")) + } +} + +func (p *PodSelector) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if p == nil { + return nil + } + + mode := p.Mode + value := p.Value + valueField := path.Child("value") + + switch mode { + case FixedMode: + num, err := strconv.Atoi(value) + if err != nil { + allErrs = append(allErrs, field.Invalid(valueField, value, + fmt.Sprintf(ValidateValueParseError, err))) + break + } + + if num <= 0 { + allErrs = append(allErrs, field.Invalid(valueField, value, + fmt.Sprintf("value must be greater than 0 with mode:%s", FixedMode))) + } + + case RandomMaxPercentMode, FixedPercentMode: + percentage, err := strconv.Atoi(value) + if err != nil { + allErrs = append(allErrs, field.Invalid(valueField, value, + fmt.Sprintf(ValidateValueParseError, err))) + break + } + + if percentage <= 0 || percentage > 100 { + allErrs = append(allErrs, field.Invalid(valueField, value, + fmt.Sprintf("value of %d is invalid, Must be (0,100] with mode:%s", + percentage, mode))) + } + } + + return allErrs +} + +func (p *PodSelector) Default(root interface{}, field *reflect.StructField) { + if p == nil { + return + } + + metaData, err := meta.Accessor(root) + if err != nil { + return + } + + if len(p.Selector.Namespaces) == 0 { + p.Selector.Namespaces = []string{metaData.GetNamespace()} + } +} + +type Percent int + +type FloatStr string + +func (p *Percent) Validate(root interface{}, path *field.Path) field.ErrorList { + if p == nil { + return nil + } + + allErrs := field.ErrorList{} + + if *p > 100 || *p < 0 { + allErrs = append(allErrs, field.Invalid(path, p, + "percent field should be in 0-100")) + } + + return allErrs +} + +func (f *FloatStr) Validate(root interface{}, path *field.Path) field.ErrorList { + if f == nil { + return nil + } + + _, err := strconv.ParseFloat(string(*f), 32) + if err != nil { + return field.ErrorList{ + field.Invalid(path, f, + fmt.Sprintf("parse correlation field error:%s", err.Error())), + } + } + + return nil +} + +func (f *FloatStr) Default(root interface{}, field *reflect.StructField) { + // f cannot be nil + if len(*f) == 0 && field != nil { + *f = FloatStr(field.Tag.Get("default")) + } +} -// ChaosValidator describes the interface should be implemented in chaos -type ChaosValidator interface { - webhook.Validator - // Validate validates chaos object - Validate() error - // ValidateScheduler validates the scheduler and duration - ValidateScheduler(spec *field.Path) field.ErrorList - // ValidatePodMode validates the value with podmode - ValidatePodMode(spec *field.Path) field.ErrorList - - // GetSelectSpec returns the selector config for authority validate - // Note: network chaos also contains select spec in target, so return array - GetSelectSpec() []SelectSpec +func init() { + genericwebhook.Register("Duration", reflect.PtrTo(reflect.TypeOf(Duration("")))) + genericwebhook.Register("Percent", reflect.PtrTo(reflect.TypeOf(Percent(0)))) + genericwebhook.Register("FloatStr", reflect.PtrTo(reflect.TypeOf(FloatStr("")))) } diff --git a/api/v1alpha1/common_webhook_test.go b/api/v1alpha1/common_webhook_test.go index 91bf447c14..f49ace4bb9 100644 --- a/api/v1alpha1/common_webhook_test.go +++ b/api/v1alpha1/common_webhook_test.go @@ -1,20 +1,22 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -22,7 +24,7 @@ import ( var _ = Describe("common_webhook", func() { Context("Defaulter", func() { It("set default namespace selector", func() { - selector := &SelectorSpec{} + selector := &PodSelectorSpec{} selector.DefaultNamespace(metav1.NamespaceDefault) Expect(selector.Namespaces[0]).To(Equal(metav1.NamespaceDefault)) }) diff --git a/api/v1alpha1/dnschaos_type.go b/api/v1alpha1/dnschaos_type.go index 0db3229953..a51f90f824 100644 --- a/api/v1alpha1/dnschaos_type.go +++ b/api/v1alpha1/dnschaos_type.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 @@ -35,7 +37,9 @@ const ( // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. // +kubebuilder:object:root=true -// +chaos-mesh:base +// +kubebuilder:printcolumn:name="action",type=string,JSONPath=`.spec.action` +// +kubebuilder:printcolumn:name="duration",type=string,JSONPath=`.spec.duration` +// +chaos-mesh:experiment // DNSChaos is the Schema for the networkchaos API type DNSChaos struct { @@ -47,9 +51,12 @@ type DNSChaos struct { // +optional // Most recently observed status of the chaos experiment about pods - Status DNSChaosStatus `json:"status"` + Status DNSChaosStatus `json:"status,omitempty"` } +var _ InnerObjectWithSelector = (*DNSChaos)(nil) +var _ InnerObject = (*DNSChaos)(nil) + // DNSChaosSpec defines the desired state of DNSChaos type DNSChaosSpec struct { // Action defines the specific DNS chaos action. @@ -58,26 +65,10 @@ type DNSChaosSpec struct { // +kubebuilder:validation:Enum=error;random Action DNSChaosAction `json:"action"` - // Mode defines the mode to run chaos action. - // Supported mode: one / all / fixed / fixed-percent / random-max-percent - // +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent - Mode PodMode `json:"mode"` - - // Value is required when the mode is set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - // If `FixedPodMode`, provide an integer of pods to do chaos action. - // If `FixedPercentPodMod`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. - // If `RandomMaxPercentPodMod`, provide a number from 0-100 to specify the max percent of pods to do chaos action - // +optional - Value string `json:"value"` - - // Selector is used to select pods that are used to inject chaos action. - Selector SelectorSpec `json:"selector"` + ContainerSelector `json:",inline"` // Duration represents the duration of the chaos action - Duration *string `json:"duration,omitempty"` - - // Scheduler defines some schedule rules to control the running time of the chaos experiment about network. - Scheduler *SchedulerSpec `json:"scheduler,omitempty"` + Duration *string `json:"duration,omitempty" webhook:"Duration"` // Choose which domain names to take effect, support the placeholder ? and wildcard *, or the Specified domain name. // Note: @@ -87,25 +78,20 @@ type DNSChaosSpec struct { // The value is ["google.com", "github.*", "chaos-mes?.org"], // will take effect on "google.com", "github.com" and "chaos-mesh.org" // +optional - DomainNamePatterns []string `json:"patterns"` -} + DomainNamePatterns []string `json:"patterns,omitempty"` -// GetSelector is a getter for Selector (for implementing SelectSpec) -func (in *DNSChaosSpec) GetSelector() SelectorSpec { - return in.Selector -} - -// GetMode is a getter for Mode (for implementing SelectSpec) -func (in *DNSChaosSpec) GetMode() PodMode { - return in.Mode -} - -// GetValue is a getter for Value (for implementing SelectSpec) -func (in *DNSChaosSpec) GetValue() string { - return in.Value + // RemoteCluster represents the remote cluster where the chaos will be deployed + // +optional + RemoteCluster string `json:"remoteCluster,omitempty"` } // DNSChaosStatus defines the observed state of DNSChaos type DNSChaosStatus struct { ChaosStatus `json:",inline"` } + +func (obj *DNSChaos) GetSelectorSpecs() map[string]interface{} { + return map[string]interface{}{ + ".": &obj.Spec.ContainerSelector, + } +} diff --git a/api/v1alpha1/dnschaos_type_test.go b/api/v1alpha1/dnschaos_type_test.go index adbbd36eb2..e3bac6a8b3 100644 --- a/api/v1alpha1/dnschaos_type_test.go +++ b/api/v1alpha1/dnschaos_type_test.go @@ -1,25 +1,25 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "context" - "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) @@ -54,8 +54,12 @@ var _ = Describe("DNSChaos", func() { Namespace: "default", }, Spec: DNSChaosSpec{ - Action: ErrorAction, - Mode: OnePodMode, + Action: ErrorAction, + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Mode: OneMode, + }, + }, DomainNamePatterns: []string{}, }, } @@ -71,19 +75,5 @@ var _ = Describe("DNSChaos", func() { Expect(k8sClient.Delete(context.TODO(), created)).To(Succeed()) Expect(k8sClient.Get(context.TODO(), key, created)).ToNot(Succeed()) }) - - It("should set next start time successfully", func() { - dnschaos := &DNSChaos{} - nTime := time.Now() - dnschaos.SetNextStart(nTime) - Expect(dnschaos.GetNextStart()).To(Equal(nTime)) - }) - - It("should set recover time successfully", func() { - dnschaos := &DNSChaos{} - nTime := time.Now() - dnschaos.SetNextRecover(nTime) - Expect(dnschaos.GetNextRecover()).To(Equal(nTime)) - }) }) }) diff --git a/api/v1alpha1/dnschaos_webhook.go b/api/v1alpha1/dnschaos_webhook.go deleted file mode 100644 index c444a52142..0000000000 --- a/api/v1alpha1/dnschaos_webhook.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package v1alpha1 - -import ( - "fmt" - - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/validation/field" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - "sigs.k8s.io/controller-runtime/pkg/webhook" -) - -// log is for logging in this package. -var dnschaoslog = logf.Log.WithName("dnschaos-resource") - -// +kubebuilder:webhook:path=/mutate-chaos-mesh-org-v1alpha1-dnschaos,mutating=true,failurePolicy=fail,groups=chaos-mesh.org,resources=dnschaos,verbs=create;update,versions=v1alpha1,name=mdnschaos.kb.io - -var _ webhook.Defaulter = &DNSChaos{} - -// Default implements webhook.Defaulter so a webhook will be registered for the type -func (in *DNSChaos) Default() { - dnschaoslog.Info("default", "name", in.Name) - - in.Spec.Selector.DefaultNamespace(in.GetNamespace()) -} - -// +kubebuilder:webhook:verbs=create;update,path=/validate-chaos-mesh-org-v1alpha1-dnschaos,mutating=false,failurePolicy=fail,groups=chaos-mesh.org,resources=dnschaos,versions=v1alpha1,name=vdnschaos.kb.io - -var _ ChaosValidator = &DNSChaos{} - -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (in *DNSChaos) ValidateCreate() error { - dnschaoslog.Info("validate create", "name", in.Name) - return in.Validate() -} - -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (in *DNSChaos) ValidateUpdate(old runtime.Object) error { - dnschaoslog.Info("validate update", "name", in.Name) - return in.Validate() -} - -// ValidateDelete implements webhook.Validator so a webhook will be registered for the type -func (in *DNSChaos) ValidateDelete() error { - dnschaoslog.Info("validate delete", "name", in.Name) - - // Nothing to do? - return nil -} - -// Validate validates chaos object -func (in *DNSChaos) Validate() error { - specField := field.NewPath("spec") - allErrs := in.ValidateScheduler(specField) - allErrs = append(allErrs, in.ValidatePodMode(specField)...) - - if len(allErrs) > 0 { - return fmt.Errorf(allErrs.ToAggregate().Error()) - } - - return nil -} - -// SelectSpec returns the selector config for authority validate -func (in *DNSChaos) GetSelectSpec() []SelectSpec { - return []SelectSpec{&in.Spec} -} - -// ValidateScheduler validates the scheduler and duration -func (in *DNSChaos) ValidateScheduler(spec *field.Path) field.ErrorList { - return ValidateScheduler(in, spec) -} - -// ValidatePodMode validates the value with podmode -func (in *DNSChaos) ValidatePodMode(spec *field.Path) field.ErrorList { - return ValidatePodMode(in.Spec.Value, in.Spec.Mode, spec.Child("value")) -} diff --git a/api/v1alpha1/gcpchaos_types.go b/api/v1alpha1/gcpchaos_types.go index e48de5d121..64807fd39f 100644 --- a/api/v1alpha1/gcpchaos_types.go +++ b/api/v1alpha1/gcpchaos_types.go @@ -4,64 +4,79 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( + "encoding/json" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // +kubebuilder:object:root=true -// +chaos-mesh:base +// +kubebuilder:printcolumn:name="action",type=string,JSONPath=`.spec.action` +// +kubebuilder:printcolumn:name="duration",type=string,JSONPath=`.spec.duration` +// +chaos-mesh:experiment +// +chaos-mesh:oneshot=in.Spec.Action==NodeReset -// GcpChaos is the Schema for the gcpchaos API -type GcpChaos struct { +// GCPChaos is the Schema for the gcpchaos API +type GCPChaos struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec GcpChaosSpec `json:"spec"` - Status GcpChaosStatus `json:"status,omitempty"` + Spec GCPChaosSpec `json:"spec"` + Status GCPChaosStatus `json:"status,omitempty"` } -// GcpChaosAction represents the chaos action about gcp. -type GcpChaosAction string +var _ InnerObjectWithCustomStatus = (*GCPChaos)(nil) +var _ InnerObjectWithSelector = (*GCPChaos)(nil) +var _ InnerObject = (*GCPChaos)(nil) + +// GCPChaosAction represents the chaos action about gcp. +type GCPChaosAction string const ( // NodeStop represents the chaos action of stopping the node. - NodeStop GcpChaosAction = "node-stop" + NodeStop GCPChaosAction = "node-stop" // NodeReset represents the chaos action of resetting the node. - NodeReset GcpChaosAction = "node-reset" + NodeReset GCPChaosAction = "node-reset" // DiskLoss represents the chaos action of detaching the disk. - DiskLoss GcpChaosAction = "disk-loss" + DiskLoss GCPChaosAction = "disk-loss" ) -// GcpChaosSpec is the content of the specification for a GcpChaos -type GcpChaosSpec struct { +// GCPChaosSpec is the content of the specification for a GCPChaos +type GCPChaosSpec struct { // Action defines the specific gcp chaos action. // Supported action: node-stop / node-reset / disk-loss // Default action: node-stop // +kubebuilder:validation:Enum=node-stop;node-reset;disk-loss - Action GcpChaosAction `json:"action"` + Action GCPChaosAction `json:"action"` // Duration represents the duration of the chaos action. // +optional - Duration *string `json:"duration,omitempty"` - - // Scheduler defines some schedule rules to control the running time of the chaos experiment about time. - // +optional - Scheduler *SchedulerSpec `json:"scheduler,omitempty"` + Duration *string `json:"duration,omitempty" webhook:"Duration"` // SecretName defines the name of kubernetes secret. It is used for GCP credentials. // +optional SecretName *string `json:"secretName,omitempty"` - // Project defines the name of gcp project. + GCPSelector `json:",inline"` + + // RemoteCluster represents the remote cluster where the chaos will be deployed + // +optional + RemoteCluster string `json:"remoteCluster,omitempty"` +} + +type GCPSelector struct { + // Project defines the ID of gcp project. Project string `json:"project"` // Zone defines the zone of gcp project. @@ -70,17 +85,36 @@ type GcpChaosSpec struct { // Instance defines the name of the instance Instance string `json:"instance"` - // The device name of the disk to detach. + // The device name of disks to detach. // Needed in disk-loss. + // +ui:form:when=action=='disk-loss' // +optional - DeviceName *string `json:"deviceName,omitempty"` + DeviceNames []string `json:"deviceNames,omitempty" webhook:"GCPDeviceNames,nilable"` +} + +func (obj *GCPChaos) GetSelectorSpecs() map[string]interface{} { + return map[string]interface{}{ + ".": &obj.Spec.GCPSelector, + } +} + +func (selector *GCPSelector) Id() string { + // TODO: handle the error here + // or ignore it is enough ? + json, _ := json.Marshal(selector) + + return string(json) } -// GcpChaosStatus represents the status of a GcpChaos -type GcpChaosStatus struct { +// GCPChaosStatus represents the status of a GCPChaos +type GCPChaosStatus struct { ChaosStatus `json:",inline"` - // The attached disk info string. + // The attached disk info strings. // Needed in disk-loss. - AttachedDiskString string `json:"attachedDiskString,omitempty"` + AttachedDisksStrings []string `json:"attachedDiskStrings,omitempty"` +} + +func (obj *GCPChaos) GetCustomStatus() interface{} { + return &obj.Status.AttachedDisksStrings } diff --git a/api/v1alpha1/gcpchaos_types_test.go b/api/v1alpha1/gcpchaos_types_test.go index a1810c1c73..942712ce6a 100644 --- a/api/v1alpha1/gcpchaos_types_test.go +++ b/api/v1alpha1/gcpchaos_types_test.go @@ -4,22 +4,22 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "context" - "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) @@ -27,10 +27,10 @@ import ( // These tests are written in BDD-style using Ginkgo framework. Refer to // http://onsi.github.io/ginkgo to learn more. -var _ = Describe("GcpChaos", func() { +var _ = Describe("GCPChaos", func() { var ( key types.NamespacedName - created, fetched *GcpChaos + created, fetched *GCPChaos ) BeforeEach(func() { @@ -52,16 +52,18 @@ var _ = Describe("GcpChaos", func() { Namespace: "default", } - created = &GcpChaos{ + created = &GCPChaos{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: "default", }, - Spec: GcpChaosSpec{ - Action: NodeReset, - Project: testProject, - Zone: testZone, - Instance: testInstance, + Spec: GCPChaosSpec{ + Action: NodeReset, + GCPSelector: GCPSelector{ + Project: testProject, + Zone: testZone, + Instance: testInstance, + }, SecretName: &testSecretName, }, } @@ -69,7 +71,7 @@ var _ = Describe("GcpChaos", func() { By("creating an API obj") Expect(k8sClient.Create(context.TODO(), created)).To(Succeed()) - fetched = &GcpChaos{} + fetched = &GCPChaos{} Expect(k8sClient.Get(context.TODO(), key, fetched)).To(Succeed()) Expect(fetched).To(Equal(created)) @@ -77,19 +79,5 @@ var _ = Describe("GcpChaos", func() { Expect(k8sClient.Delete(context.TODO(), created)).To(Succeed()) Expect(k8sClient.Get(context.TODO(), key, created)).ToNot(Succeed()) }) - - It("should set next start time successfully", func() { - gcpchaos := &GcpChaos{} - nTime := time.Now() - gcpchaos.SetNextStart(nTime) - Expect(gcpchaos.GetNextStart()).To(Equal(nTime)) - }) - - It("should set recover time successfully", func() { - gcpchaos := &GcpChaos{} - nTime := time.Now() - gcpchaos.SetNextRecover(nTime) - Expect(gcpchaos.GetNextRecover()).To(Equal(nTime)) - }) }) }) diff --git a/api/v1alpha1/gcpchaos_webhook.go b/api/v1alpha1/gcpchaos_webhook.go index bd719b8aa9..22d49b12da 100644 --- a/api/v1alpha1/gcpchaos_webhook.go +++ b/api/v1alpha1/gcpchaos_webhook.go @@ -4,116 +4,57 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - "fmt" + "reflect" - "k8s.io/apimachinery/pkg/runtime" + "github.com/pkg/errors" "k8s.io/apimachinery/pkg/util/validation/field" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/webhook" -) - -// log is for logging in this package. -var gcpchaoslog = logf.Log.WithName("gcpchaos-resource") - -// +kubebuilder:webhook:path=/mutate-chaos-mesh-org-v1alpha1-gcpchaos,mutating=true,failurePolicy=fail,groups=chaos-mesh.org,resources=gcpchaos,verbs=create;update,versions=v1alpha1,name=mgcpchaos.kb.io - -var _ webhook.Defaulter = &GcpChaos{} - -// Default implements webhook.Defaulter so a webhook will be registered for the type -func (in *GcpChaos) Default() { - gcpchaoslog.Info("default", "name", in.Name) -} - -// +kubebuilder:webhook:verbs=create;update,path=/validate-chaos-mesh-org-v1alpha1-gcpchaos,mutating=false,failurePolicy=fail,groups=chaos-mesh.org,resources=gcpchaos,versions=v1alpha1,name=vgcpchaos.kb.io - -var _ ChaosValidator = &GcpChaos{} - -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (in *GcpChaos) ValidateCreate() error { - gcpchaoslog.Info("validate create", "name", in.Name) - return in.Validate() -} - -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (in *GcpChaos) ValidateUpdate(old runtime.Object) error { - gcpchaoslog.Info("validate update", "name", in.Name) - return in.Validate() -} -// ValidateDelete implements webhook.Validator so a webhook will be registered for the type -func (in *GcpChaos) ValidateDelete() error { - gcpchaoslog.Info("validate delete", "name", in.Name) - - // Nothing to do? - return nil -} - -// SelectSpec returns the selector config for authority validate -func (in *GcpChaos) GetSelectSpec() []SelectSpec { - return nil -} - -// Validate validates chaos object -func (in *GcpChaos) Validate() error { - specField := field.NewPath("spec") - allErrs := in.ValidateScheduler(specField) - allErrs = append(allErrs, in.ValidatePodMode(specField)...) - allErrs = append(allErrs, in.Spec.validateDeviceName(specField.Child("deviceName"))...) - - if len(allErrs) > 0 { - return fmt.Errorf(allErrs.ToAggregate().Error()) - } - return nil -} + "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" +) -// ValidateScheduler validates the scheduler and duration -func (in *GcpChaos) ValidateScheduler(spec *field.Path) field.ErrorList { +// validateDeviceName validates the gcp chaos actions +func (in GCPChaosAction) Validate(root interface{}, path *field.Path) field.ErrorList { allErrs := field.ErrorList{} - schedulerField := spec.Child("scheduler") - switch in.Spec.Action { + switch in { case NodeStop, DiskLoss: - allErrs = append(allErrs, ValidateScheduler(in, spec)...) case NodeReset: - // We choose to ignore the Duration property even user define it - if in.Spec.Scheduler != nil { - _, err := ParseCron(in.Spec.Scheduler.Cron, schedulerField.Child("cron")) - allErrs = append(allErrs, err...) - } default: - err := fmt.Errorf("awschaos[%s/%s] have unknown action type", in.Namespace, in.Name) - log.Error(err, "Wrong AwsChaos Action type") + err := errors.WithStack(errUnknownAction) + log.Error(err, "Wrong GCPChaos Action type") - actionField := spec.Child("action") - allErrs = append(allErrs, field.Invalid(actionField, in.Spec.Action, err.Error())) + allErrs = append(allErrs, field.Invalid(path, in, err.Error())) } return allErrs } -// ValidatePodMode validates the value with podmode -func (in *GcpChaos) ValidatePodMode(spec *field.Path) field.ErrorList { - // Because gcp chaos does not need a pod mode, so return nil here. - return nil -} +type GCPDeviceNames []string // validateDeviceName validates the DeviceName -func (in *GcpChaosSpec) validateDeviceName(containerField *field.Path) field.ErrorList { +func (in *GCPDeviceNames) Validate(root interface{}, path *field.Path) field.ErrorList { allErrs := field.ErrorList{} - if in.Action == DiskLoss { - if in.DeviceName == nil { - err := fmt.Errorf("the name of device should not be empty on %s action", in.Action) - allErrs = append(allErrs, field.Invalid(containerField, in.DeviceName, err.Error())) + obj := root.(*GCPChaos) + if obj.Spec.Action == DiskLoss { + if *in == nil { + err := errors.Errorf("at least one device name is required on %s action", obj.Spec.Action) + allErrs = append(allErrs, field.Invalid(path, *in, err.Error())) } } return allErrs } + +func init() { + genericwebhook.Register("GCPDeviceNames", reflect.PtrTo(reflect.TypeOf(GCPDeviceNames{}))) +} diff --git a/api/v1alpha1/gcpchaos_webhook_test.go b/api/v1alpha1/gcpchaos_webhook_test.go index 68b50b389d..a1ed399c30 100644 --- a/api/v1alpha1/gcpchaos_webhook_test.go +++ b/api/v1alpha1/gcpchaos_webhook_test.go @@ -4,17 +4,21 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - . "github.com/onsi/ginkgo" + "fmt" + + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -25,74 +29,39 @@ var _ = Describe("gcpchaos_webhook", func() { type TestCase struct { name string - chaos GcpChaos - execute func(chaos *GcpChaos) error + chaos GCPChaos + execute func(chaos *GCPChaos) error expect string } - duration := "400s" tcs := []TestCase{ { name: "simple ValidateCreate for DiskLoss", - chaos: GcpChaos{ + chaos: GCPChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo1", }, - Spec: GcpChaosSpec{ + Spec: GCPChaosSpec{ Action: DiskLoss, }, }, - execute: func(chaos *GcpChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "only define the Scheduler and execute NodeStop", - chaos: GcpChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo4", - }, - Spec: GcpChaosSpec{ - Scheduler: &SchedulerSpec{ - Cron: "@every 10m", - }, - Action: NodeStop, - }, - }, - execute: func(chaos *GcpChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "only define the Duration and execute NodeStop", - chaos: GcpChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo5", - }, - Spec: GcpChaosSpec{ - Action: NodeStop, - Duration: &duration, - }, - }, - execute: func(chaos *GcpChaos) error { - return chaos.ValidateCreate() + execute: func(chaos *GCPChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, { name: "unknow action", - chaos: GcpChaos{ + chaos: GCPChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo6", }, }, - execute: func(chaos *GcpChaos) error { - return chaos.ValidateCreate() + execute: func(chaos *GCPChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, @@ -101,6 +70,9 @@ var _ = Describe("gcpchaos_webhook", func() { for _, tc := range tcs { err := tc.execute(&tc.chaos) if tc.expect == "error" { + if err == nil { + fmt.Println("Aha") + } Expect(err).To(HaveOccurred()) } else { Expect(err).NotTo(HaveOccurred()) diff --git a/api/v1alpha1/go.mod b/api/v1alpha1/go.mod deleted file mode 100644 index e56f50e703..0000000000 --- a/api/v1alpha1/go.mod +++ /dev/null @@ -1,15 +0,0 @@ -module github.com/chaos-mesh/chaos-mesh/api/v1alpha1 - -go 1.13 - -require ( - github.com/bxcodec/faker v2.0.1+incompatible - github.com/docker/go-units v0.3.3 - github.com/onsi/ginkgo v1.10.1 - github.com/onsi/gomega v1.7.0 - github.com/robfig/cron/v3 v3.0.1 - k8s.io/api v0.17.0 - k8s.io/apimachinery v0.17.0 - k8s.io/client-go v0.17.0 - sigs.k8s.io/controller-runtime v0.4.0 -) diff --git a/api/v1alpha1/go.sum b/api/v1alpha1/go.sum deleted file mode 100644 index f0eba106e3..0000000000 --- a/api/v1alpha1/go.sum +++ /dev/null @@ -1,408 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/bxcodec/faker v2.0.1+incompatible h1:P0KUpUw5w6WJXwrPfv35oc91i4d8nf40Nwln+M/+faA= -github.com/bxcodec/faker v2.0.1+incompatible/go.mod h1:BNzfpVdTwnFJ6GtfYTcQu6l6rHShT+veBxNCnjCx5XM= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk= -github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= -github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54= -github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= -github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= -github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= -github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= -github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= -github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7 h1:u4bArs140e9+AfE52mFHOXVFnOSBJBRlzTHrOPLOIhE= -github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= -github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.4.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.3.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= -github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= -github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= -github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180112015858-5ccada7d0a7b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180117170059-2c42eef0765b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0= -gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= -gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.0.0-20190918155943-95b840bb6a1f h1:8FRUST8oUkEI45WYKyD8ed7Ad0Kg5v11zHyPkEVb2xo= -k8s.io/api v0.0.0-20190918155943-95b840bb6a1f/go.mod h1:uWuOHnjmNrtQomJrvEBg0c0HRNyQ+8KTEERVsK0PW48= -k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM= -k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= -k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783 h1:V6ndwCPoao1yZ52agqOKaUAl7DYWVGiXjV7ePA2i610= -k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783/go.mod h1:xvae1SZB3E17UpV59AWc271W/Ph25N+bjPyR63X6tPY= -k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4= -k8s.io/apimachinery v0.17.0 h1:xRBnuie9rXcPxUkDizUsGvPf1cnlZCFu210op7J7LJo= -k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad/go.mod h1:XPCXEwhjaFN29a8NldXA901ElnKeKLrLtREO9ZhFyhg= -k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90 h1:mLmhKUm1X+pXu0zXMEzNsOF5E2kKFGe5o6BZBIIqA6A= -k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90/go.mod h1:J69/JveO6XESwVgG53q3Uz5OSfgsv4uxpScmmyYOOlk= -k8s.io/client-go v0.17.0 h1:8QOGvUGdqDMFrm9sD6IUFl256BcffynGoe80sxgTEDg= -k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= -k8s.io/code-generator v0.0.0-20190912054826-cd179ad6a269/go.mod h1:V5BD6M4CyaN5m+VthcclXWsVcT1Hu+glwa1bi3MIsyE= -k8s.io/component-base v0.0.0-20190918160511-547f6c5d7090/go.mod h1:933PBGtQFJky3TEwYx4aEPZ4IxqhWh3R6DCmzqIn1hA= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= -k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/utils v0.0.0-20190801114015-581e00157fb1 h1:+ySTxfHnfzZb9ys375PXNlLhkJPLKgHajBU0N62BDvE= -k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= -k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= -modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= -modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= -modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= -modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= -sigs.k8s.io/controller-runtime v0.4.0 h1:wATM6/m+3w8lj8FXNaO6Fs/rq/vqoOjO1Q116Z9NPsg= -sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns= -sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= -sigs.k8s.io/testing_frameworks v0.1.2 h1:vK0+tvjF0BZ/RYFeZ1E6BYBwHJJXhjuZ3TdsEKH+UQM= -sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w= -sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/api/v1alpha1/groupversion_info.go b/api/v1alpha1/groupversion_info.go index 35e9bb8cfb..fb19236ac9 100644 --- a/api/v1alpha1/groupversion_info.go +++ b/api/v1alpha1/groupversion_info.go @@ -1,15 +1,17 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// // Package v1alpha1 contains API Schema definitions for the chaosmesh v1alpha1 API group // +kubebuilder:object:generate=true diff --git a/api/v1alpha1/httpchaos_types.go b/api/v1alpha1/httpchaos_types.go index d4399f9bcb..d3b27e9e39 100644 --- a/api/v1alpha1/httpchaos_types.go +++ b/api/v1alpha1/httpchaos_types.go @@ -1,22 +1,27 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) // +kubebuilder:object:root=true -// +chaos-mesh:base +// +kubebuilder:printcolumn:name="duration",type=string,JSONPath=`.spec.duration` +// +chaos-mesh:experiment // HTTPChaos is the Schema for the HTTPchaos API type HTTPChaos struct { @@ -27,87 +32,72 @@ type HTTPChaos struct { Status HTTPChaosStatus `json:"status,omitempty"` } -// HTTPChaosAction represents the chaos action about HTTP. -type HTTPChaosAction string +var _ InnerObjectWithCustomStatus = (*HTTPChaos)(nil) +var _ InnerObjectWithSelector = (*HTTPChaos)(nil) +var _ InnerObject = (*HTTPChaos)(nil) -const ( - HTTPDelayAction HTTPChaosAction = "delay" - HTTPAbortAction = "abort" - HTTPMixedAction = "mixed" -) +type HTTPChaosSpec struct { + PodSelector `json:",inline"` -type Matcher struct { - Name string `json:"name"` - ExactMatch *string `json:"exact_match,omitempty"` - RegexMatch *string `json:"regex_match,omitempty"` - SafeRegexMatch *string `json:"safe_regex_match,omitempty"` - RangeMatch *string `json:"range_match,omitempty"` - PresentMatch *string `json:"present_match,omitempty"` - PrefixMatch *string `json:"prefix_match,omitempty"` - SuffixMatch *string `json:"suffix_match,omitempty"` - InvertMatch *string `json:"invert_match,omitempty"` -} + // Target is the object to be selected and injected. + // +kubebuilder:validation:Enum=Request;Response + Target PodHttpChaosTarget `json:"target"` -type HTTPChaosSpec struct { - // Selector is used to select pods that are used to inject chaos action. - Selector SelectorSpec `json:"selector"` - - // Scheduler defines some schedule rules to - // control the running time of the chaos experiment about pods. - Scheduler *SchedulerSpec `json:"scheduler,omitempty"` - - // Action defines the specific pod chaos action. - // Supported action: delay | abort | mixed - // Default action: delay - // +kubebuilder:validation:Enum=delay;abort;mixed - Action HTTPChaosAction `json:"action"` - - // Mode defines the mode to run chaos action. - // Supported mode: one / all / fixed / fixed-percent / random-max-percent - // +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent - Mode PodMode `json:"mode"` - - // Value is required when the mode is set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - // If `FixedPodMode`, provide an integer of pods to do chaos action. - // If `FixedPercentPodMod`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. - // IF `RandomMaxPercentPodMod`, provide a number from 0-100 to specify the max percent of pods to do chaos action + PodHttpChaosActions `json:",inline"` + + // Port represents the target port to be proxy of. + Port int32 `json:"port,omitempty" webhook:"Port"` + + // Path is a rule to select target by uri path in http request. // +optional - Value string `json:"value"` + Path *string `json:"path,omitempty"` - // Duration represents the duration of the chaos action. - // It is required when the action is `PodFailureAction`. - // 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". + // Method is a rule to select target by http method in request. // +optional - Duration *string `json:"duration,omitempty"` + Method *string `json:"method,omitempty" webhook:"HTTPMethod"` - // Percent defines the percentage of injection errors and provides a number from 0-100. - // default: 100. + // Code is a rule to select target by http status code in response. // +optional - Percent string `json:"percent,omitempty"` + Code *int32 `json:"code,omitempty"` - // Specifies how the header match will be performed to route the request. - Headers []Matcher `json:"headers,omitempty"` -} + // RequestHeaders is a rule to select target by http headers in request. + // The key-value pairs represent header name and header value pairs. + // +optional + RequestHeaders map[string]string `json:"request_headers,omitempty"` -func (in *HTTPChaosSpec) GetHeaders() []Matcher { - return in.Headers -} + // ResponseHeaders is a rule to select target by http headers in response. + // The key-value pairs represent header name and header value pairs. + // +optional + ResponseHeaders map[string]string `json:"response_headers,omitempty"` -func (in *HTTPChaosSpec) GetMode() PodMode { - return in.Mode -} + // TLS is the tls config, + // will override PodHttpChaos if there are multiple HTTPChaos experiments are applied + // +optional + TLS *PodHttpChaosTLS `json:"tls,omitempty"` -func (in *HTTPChaosSpec) GetValue() string { - return in.Value -} + // Duration represents the duration of the chaos action. + // +optional + Duration *string `json:"duration,omitempty" webhook:"Duration"` -func (in *HTTPChaosSpec) GetSelector() SelectorSpec { - return in.Selector + // RemoteCluster represents the remote cluster where the chaos will be deployed + // +optional + RemoteCluster string `json:"remoteCluster,omitempty"` } type HTTPChaosStatus struct { ChaosStatus `json:",inline"` + + // Instances always specifies podhttpchaos generation or empty + // +optional + Instances map[string]int64 `json:"instances,omitempty"` +} + +func (obj *HTTPChaos) GetSelectorSpecs() map[string]interface{} { + return map[string]interface{}{ + ".": &obj.Spec.PodSelector, + } +} + +func (obj *HTTPChaos) GetCustomStatus() interface{} { + return &obj.Status.Instances } diff --git a/api/v1alpha1/httpchaos_types_test.go b/api/v1alpha1/httpchaos_types_test.go index d06e5e657f..0ec6fc8ef9 100644 --- a/api/v1alpha1/httpchaos_types_test.go +++ b/api/v1alpha1/httpchaos_types_test.go @@ -1,25 +1,25 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "context" - "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) @@ -48,14 +48,24 @@ var _ = Describe("HTTPChaos", func() { Namespace: "default", } + path := "/api" + delay := "10s" + created = &HTTPChaos{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: "default", }, Spec: HTTPChaosSpec{ - Action: HTTPDelayAction, - Mode: OnePodMode, + PodSelector: PodSelector{ + Mode: OneMode, + }, + Target: PodHttpRequest, + Port: 80, + Path: &path, + PodHttpChaosActions: PodHttpChaosActions{ + Delay: &delay, + }, }, } @@ -70,19 +80,5 @@ var _ = Describe("HTTPChaos", func() { Expect(k8sClient.Delete(context.TODO(), created)).To(Succeed()) Expect(k8sClient.Get(context.TODO(), key, created)).ToNot(Succeed()) }) - - It("should set next start time successfully", func() { - httpChaos := &HTTPChaos{} - nTime := time.Now() - httpChaos.SetNextStart(nTime) - Expect(httpChaos.GetNextStart()).To(Equal(nTime)) - }) - - It("should set recover time successfully", func() { - httpChaos := &HTTPChaos{} - nTime := time.Now() - httpChaos.SetNextRecover(nTime) - Expect(httpChaos.GetNextRecover()).To(Equal(nTime)) - }) }) }) diff --git a/api/v1alpha1/httpchaos_webhook.go b/api/v1alpha1/httpchaos_webhook.go index 7179ab33fe..ed045fa9a1 100644 --- a/api/v1alpha1/httpchaos_webhook.go +++ b/api/v1alpha1/httpchaos_webhook.go @@ -4,83 +4,88 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "fmt" + "net/http" + "reflect" + "time" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/webhook" -) - -// log is for logging in this package. -var httpchaoslog = logf.Log.WithName("httpchaos-resource") - -// +kubebuilder:webhook:path=/mutate-chaos-mesh-org-v1alpha1-httpchaos,mutating=true,failurePolicy=fail,groups=chaos-mesh.org,resources=httpchaos,verbs=create;update,versions=v1alpha1,name=mhttpchaos.kb.io - -var _ webhook.Defaulter = &HTTPChaos{} - -// Default implements webhook.Defaulter so a webhook will be registered for the type -func (in *HTTPChaos) Default() { - httpchaoslog.Info("default", "name", in.Name) -} - -// +kubebuilder:webhook:verbs=create;update,path=/validate-chaos-mesh-org-v1alpha1-httpchaos,mutating=false,failurePolicy=fail,groups=chaos-mesh.org,resources=httpchaos,versions=v1alpha1,name=vhttpchaos.kb.io -var _ ChaosValidator = &HTTPChaos{} - -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (in *HTTPChaos) ValidateCreate() error { - httpchaoslog.Info("validate create", "name", in.Name) - return in.Validate() -} - -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (in *HTTPChaos) ValidateUpdate(old runtime.Object) error { - httpchaoslog.Info("validate update", "name", in.Name) - return in.Validate() -} + "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" +) -// ValidateDelete implements webhook.Validator so a webhook will be registered for the type -func (in *HTTPChaos) ValidateDelete() error { - httpchaoslog.Info("validate delete", "name", in.Name) +type Delay string - // Nothing to do? - return nil +func (in *Delay) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if in != nil { + _, err := time.ParseDuration(string(*in)) + if err != nil { + allErrs = append(allErrs, field.Invalid(path, in, fmt.Sprintf("invalid duration %s", *in))) + } + } + return allErrs } -// Validate validates chaos object -func (in *HTTPChaos) Validate() error { - specField := field.NewPath("spec") - allErrs := in.ValidateScheduler(specField) - allErrs = append(allErrs, in.ValidatePodMode(specField)...) +type Port int32 - if len(allErrs) > 0 { - return fmt.Errorf(allErrs.ToAggregate().Error()) +func (in *Port) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + // in cannot be zero or negative + if *in <= 0 { + allErrs = append(allErrs, field.Invalid(path, in, fmt.Sprintf("port %d is not supported", *in))) } - return nil + return allErrs } -// ValidateScheduler validates the scheduler and duration -func (in *HTTPChaos) ValidateScheduler(spec *field.Path) field.ErrorList { - return ValidateScheduler(in, spec) +type HTTPMethod string + +func (in *HTTPMethod) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if in != nil && root.(*HTTPChaos).Spec.Target == PodHttpRequest { + switch *in { + case http.MethodGet: + case http.MethodPost: + case http.MethodPut: + case http.MethodDelete: + case http.MethodPatch: + case http.MethodHead: + case http.MethodOptions: + case http.MethodTrace: + case http.MethodConnect: + default: + allErrs = append(allErrs, field.Invalid(path, in, fmt.Sprintf("method %s is not supported", *in))) + } + } + return allErrs } -// ValidatePodMode validates the value with podmode -func (in *HTTPChaos) ValidatePodMode(spec *field.Path) field.ErrorList { - return ValidatePodMode(in.Spec.Value, in.Spec.Mode, spec.Child("value")) +func (in *PodHttpChaosTarget) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + switch *in { + case PodHttpRequest: + case PodHttpResponse: + default: + allErrs = append(allErrs, field.Invalid(path, in, fmt.Sprintf("target %s is not supported", *in))) + } + return allErrs } -// SelectSpec returns the selector config for authority validate -func (in *HTTPChaos) GetSelectSpec() []SelectSpec { - return []SelectSpec{&in.Spec} +func init() { + genericwebhook.Register("Delay", reflect.PtrTo(reflect.TypeOf(Delay("")))) + genericwebhook.Register("Port", reflect.PtrTo(reflect.TypeOf(Port(0)))) + genericwebhook.Register("HTTPMethod", reflect.PtrTo(reflect.TypeOf(HTTPMethod("")))) + genericwebhook.Register("PodHttpChaosTarget", reflect.PtrTo(reflect.TypeOf(PodHttpChaosTarget("")))) } diff --git a/api/v1alpha1/httpchaos_webhook_test.go b/api/v1alpha1/httpchaos_webhook_test.go new file mode 100644 index 0000000000..2afeb1b645 --- /dev/null +++ b/api/v1alpha1/httpchaos_webhook_test.go @@ -0,0 +1,406 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "net/http" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("HTTPChaos Webhook", func() { + Context("webhook.Validator of httpchaos", func() { + It("Validate", func() { + type TestCase struct { + name string + chaos HTTPChaos + execute func(chaos *HTTPChaos) error + expect string + } + errorDuration := "400S" + errorMethod := "gET" + validMethod := http.MethodGet + errorDelay := "1" + valideDelay := "1s" + + tcs := []TestCase{ + { + name: "simple ValidateCreate", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo1", + }, + Spec: HTTPChaosSpec{ + Target: PodHttpRequest, + Port: 80, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "", + }, + { + name: "simple ValidateUpdate", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo2", + }, + Spec: HTTPChaosSpec{ + Target: PodHttpRequest, + Port: 80, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateUpdate(chaos) + return err + }, + expect: "", + }, + { + name: "simple ValidateDelete", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo3", + }, + Spec: HTTPChaosSpec{ + Target: PodHttpRequest, + Port: 80, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateDelete() + return err + }, + expect: "", + }, + { + name: "parse the duration error", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo6", + }, + Spec: HTTPChaosSpec{ + Duration: &errorDuration, + Target: PodHttpRequest, + Port: 80, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate value with FixedPercentMode", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo7", + }, + Spec: HTTPChaosSpec{ + PodSelector: PodSelector{ + Value: "0", + Mode: FixedMode, + }, + Port: 80, + Target: PodHttpRequest, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate value with FixedPercentMode, parse value error", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo8", + }, + Spec: HTTPChaosSpec{ + PodSelector: PodSelector{ + Value: "num", + Mode: FixedMode, + }, + Port: 80, + Target: PodHttpRequest, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate value with RandomMaxPercentMode", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo9", + }, + Spec: HTTPChaosSpec{ + PodSelector: PodSelector{ + Value: "0", + Mode: RandomMaxPercentMode, + }, + Port: 80, + Target: PodHttpRequest, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate value with RandomMaxPercentMode ,parse value error", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo10", + }, + Spec: HTTPChaosSpec{ + PodSelector: PodSelector{ + Value: "num", + Mode: RandomMaxPercentMode, + }, + Port: 80, + Target: PodHttpRequest, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate value with FixedPercentMode", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo11", + }, + Spec: HTTPChaosSpec{ + PodSelector: PodSelector{ + Value: "101", + Mode: FixedPercentMode, + }, + Port: 80, + Target: PodHttpRequest, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate port 1", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo12", + }, + Spec: HTTPChaosSpec{ + Target: PodHttpRequest, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate port 2", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo13", + }, + Spec: HTTPChaosSpec{ + Port: -1, + Target: PodHttpRequest, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate target 1", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo14", + }, + Spec: HTTPChaosSpec{ + Port: 80, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate target 2", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo15", + }, + Spec: HTTPChaosSpec{ + Port: 80, + Target: "request", + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "valid method 1", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo16", + }, + Spec: HTTPChaosSpec{ + Port: 80, + Target: PodHttpRequest, + Method: &validMethod, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "ok", + }, + { + name: "valid method 2", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo17", + }, + Spec: HTTPChaosSpec{ + Port: 80, + Target: PodHttpResponse, + Method: &errorMethod, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "ok", + }, + { + name: "invalid method", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo18", + }, + Spec: HTTPChaosSpec{ + Port: 80, + Target: PodHttpRequest, + Method: &errorMethod, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "valid delay", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo19", + }, + Spec: HTTPChaosSpec{ + Port: 80, + Target: PodHttpRequest, + PodHttpChaosActions: PodHttpChaosActions{ + Delay: &valideDelay, + }, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "ok", + }, + { + name: "invalid delay", + chaos: HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo20", + }, + Spec: HTTPChaosSpec{ + Port: 80, + Target: PodHttpRequest, + PodHttpChaosActions: PodHttpChaosActions{ + Delay: &errorDelay, + }, + }, + }, + execute: func(chaos *HTTPChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + } + + for _, tc := range tcs { + err := tc.execute(&tc.chaos) + if tc.expect == "error" { + Expect(err).To(HaveOccurred()) + } else { + Expect(err).NotTo(HaveOccurred()) + } + } + }) + }) +}) diff --git a/api/v1alpha1/iochaos_types.go b/api/v1alpha1/iochaos_types.go index 19f8ce6bb8..5455257202 100644 --- a/api/v1alpha1/iochaos_types.go +++ b/api/v1alpha1/iochaos_types.go @@ -1,15 +1,17 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 @@ -21,57 +23,54 @@ import ( // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. // +kubebuilder:object:root=true -// +chaos-mesh:base +// +kubebuilder:printcolumn:name="action",type=string,JSONPath=`.spec.action` +// +kubebuilder:printcolumn:name="duration",type=string,JSONPath=`.spec.duration` +// +chaos-mesh:experiment -// IoChaos is the Schema for the iochaos API -type IoChaos struct { +// IOChaos is the Schema for the iochaos API +type IOChaos struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec IoChaosSpec `json:"spec,omitempty"` - Status IoChaosStatus `json:"status,omitempty"` + Spec IOChaosSpec `json:"spec,omitempty"` + Status IOChaosStatus `json:"status,omitempty"` } -// IoChaosSpec defines the desired state of IoChaos -type IoChaosSpec struct { - // Selector is used to select pods that are used to inject chaos action. - Selector SelectorSpec `json:"selector"` - - // Mode defines the mode to run chaos action. - // Supported mode: one / all / fixed / fixed-percent / random-max-percent - // +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent - Mode PodMode `json:"mode"` +var _ InnerObjectWithCustomStatus = (*IOChaos)(nil) +var _ InnerObjectWithSelector = (*IOChaos)(nil) +var _ InnerObject = (*IOChaos)(nil) - // Value is required when the mode is set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - // If `FixedPodMode`, provide an integer of pods to do chaos action. - // If `FixedPercentPodMod`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. - // IF `RandomMaxPercentPodMod`, provide a number from 0-100 to specify the max percent of pods to do chaos action - // +optional - Value string `json:"value"` +// IOChaosSpec defines the desired state of IOChaos +type IOChaosSpec struct { + ContainerSelector `json:",inline"` // Action defines the specific pod chaos action. // Supported action: latency / fault / attrOverride / mistake // +kubebuilder:validation:Enum=latency;fault;attrOverride;mistake - Action IoChaosType `json:"action"` + Action IOChaosType `json:"action"` // Delay defines the value of I/O chaos action delay. // A delay string is a possibly signed sequence of // decimal numbers, each with optional fraction and a unit suffix, // such as "300ms". // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + // +ui:form:when=action=='latency' // +optional - Delay string `json:"delay,omitempty"` + Delay string `json:"delay,omitempty" webhook:"Duration"` // Errno defines the error code that returned by I/O action. // refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html + // +ui:form:when=action=='fault' // +optional - Errno uint32 `json:"errno,omitempty"` + Errno uint32 `json:"errno,omitempty" webhook:"IOErrno"` // Attr defines the overrided attribution + // +ui:form:when=action=='attrOverride' // +optional Attr *AttrOverrideSpec `json:"attr,omitempty"` // Mistake defines what types of incorrectness are injected to IO operations + // +ui:form:when=action=='mistake' // +optional Mistake *MistakeSpec `json:"mistake,omitempty"` @@ -87,19 +86,12 @@ type IoChaosSpec struct { // Percent defines the percentage of injection errors and provides a number from 0-100. // default: 100. // +optional - Percent int `json:"percent,omitempty"` + // +kubebuilder:default=100 + Percent int `json:"percent,omitempty" webhook:"Percent"` // VolumePath represents the mount path of injected volume VolumePath string `json:"volumePath"` - // ContainerName indicates the target container to inject iochaos in - // +optional - ContainerName *string `json:"containerName,omitempty"` - - // Scheduler defines some schedule rules to - // control the running time of the chaos experiment about pods. - Scheduler *SchedulerSpec `json:"scheduler,omitempty"` - // Duration represents the duration of the chaos action. // It is required when the action is `PodFailureAction`. // A duration string is a possibly signed sequence of @@ -107,22 +99,28 @@ type IoChaosSpec struct { // such as "300ms", "-1.5h" or "2h45m". // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". // +optional - Duration *string `json:"duration,omitempty"` -} + Duration *string `json:"duration,omitempty" webhook:"Duration"` -func (in *IoChaosSpec) GetSelector() SelectorSpec { - return in.Selector + // RemoteCluster represents the remote cluster where the chaos will be deployed + // +optional + RemoteCluster string `json:"remoteCluster,omitempty"` } -func (in *IoChaosSpec) GetMode() PodMode { - return in.Mode +// IOChaosStatus defines the observed state of IOChaos +type IOChaosStatus struct { + ChaosStatus `json:",inline"` + + // Instances always specifies podiochaos generation or empty + // +optional + Instances map[string]int64 `json:"instances,omitempty"` } -func (in *IoChaosSpec) GetValue() string { - return in.Value +func (obj *IOChaos) GetSelectorSpecs() map[string]interface{} { + return map[string]interface{}{ + ".": &obj.Spec.ContainerSelector, + } } -// IoChaosStatus defines the observed state of IoChaos -type IoChaosStatus struct { - ChaosStatus `json:",inline"` +func (obj *IOChaos) GetCustomStatus() interface{} { + return &obj.Status.Instances } diff --git a/api/v1alpha1/iochaos_types_test.go b/api/v1alpha1/iochaos_types_test.go index e42511b5ae..787e2d27eb 100644 --- a/api/v1alpha1/iochaos_types_test.go +++ b/api/v1alpha1/iochaos_types_test.go @@ -1,25 +1,25 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "context" - "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) @@ -27,10 +27,10 @@ import ( // These tests are written in BDD-style using Ginkgo framework. Refer to // http://onsi.github.io/ginkgo to learn more. -var _ = Describe("IoChaos", func() { +var _ = Describe("IOChaos", func() { var ( key types.NamespacedName - created, fetched *IoChaos + created, fetched *IOChaos ) BeforeEach(func() { @@ -48,21 +48,25 @@ var _ = Describe("IoChaos", func() { Namespace: "default", } - created = &IoChaos{ + created = &IOChaos{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: "default", }, - Spec: IoChaosSpec{ + Spec: IOChaosSpec{ Action: IoLatency, - Mode: OnePodMode, + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Mode: OneMode, + }, + }, }, } By("creating an API obj") Expect(k8sClient.Create(context.TODO(), created)).To(Succeed()) - fetched = &IoChaos{} + fetched = &IOChaos{} Expect(k8sClient.Get(context.TODO(), key, fetched)).To(Succeed()) Expect(fetched).To(Equal(created)) @@ -70,19 +74,5 @@ var _ = Describe("IoChaos", func() { Expect(k8sClient.Delete(context.TODO(), created)).To(Succeed()) Expect(k8sClient.Get(context.TODO(), key, created)).ToNot(Succeed()) }) - - It("should set next start time successfully", func() { - iochaos := &IoChaos{} - nTime := time.Now() - iochaos.SetNextStart(nTime) - Expect(iochaos.GetNextStart()).To(Equal(nTime)) - }) - - It("should set recover time successfully", func() { - iochaos := &IoChaos{} - nTime := time.Now() - iochaos.SetNextRecover(nTime) - Expect(iochaos.GetNextRecover()).To(Equal(nTime)) - }) }) }) diff --git a/api/v1alpha1/iochaos_webhook.go b/api/v1alpha1/iochaos_webhook.go index 2e7d82790f..ca1a401f86 100644 --- a/api/v1alpha1/iochaos_webhook.go +++ b/api/v1alpha1/iochaos_webhook.go @@ -1,140 +1,44 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "fmt" - "time" + "reflect" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" - ctrl "sigs.k8s.io/controller-runtime" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - "sigs.k8s.io/controller-runtime/pkg/webhook" -) - -// log is for logging in this package. -var iochaoslog = logf.Log.WithName("iochaos-resource") - -// SetupWebhookWithManager setup IoChaos's webhook with manager -func (in *IoChaos) SetupWebhookWithManager(mgr ctrl.Manager) error { - return ctrl.NewWebhookManagedBy(mgr). - For(in). - Complete() -} - -// +kubebuilder:webhook:path=/mutate-chaos-mesh-org-v1alpha1-iochaos,mutating=true,failurePolicy=fail,groups=chaos-mesh.org,resources=iochaos,verbs=create;update,versions=v1alpha1,name=miochaos.kb.io - -var _ webhook.Defaulter = &IoChaos{} - -// Default implements webhook.Defaulter so a webhook will be registered for the type -func (in *IoChaos) Default() { - iochaoslog.Info("default", "name", in.Name) - - in.Spec.Selector.DefaultNamespace(in.GetNamespace()) -} - -// +kubebuilder:webhook:verbs=create;update,path=/validate-chaos-mesh-org-v1alpha1-iochaos,mutating=false,failurePolicy=fail,groups=chaos-mesh.org,resources=iochaos,versions=v1alpha1,name=viochaos.kb.io - -var _ ChaosValidator = &IoChaos{} - -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (in *IoChaos) ValidateCreate() error { - iochaoslog.Info("validate create", "name", in.Name) - return in.Validate() -} - -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (in *IoChaos) ValidateUpdate(old runtime.Object) error { - iochaoslog.Info("validate update", "name", in.Name) - return in.Validate() -} - -// ValidateDelete implements webhook.Validator so a webhook will be registered for the type -func (in *IoChaos) ValidateDelete() error { - iochaoslog.Info("validate delete", "name", in.Name) - - // Nothing to do? - return nil -} - -// Validate validates chaos object -func (in *IoChaos) Validate() error { - specField := field.NewPath("spec") - allErrs := in.ValidateScheduler(specField) - allErrs = append(allErrs, in.ValidatePodMode(specField)...) - allErrs = append(allErrs, in.Spec.validateDelay(specField.Child("delay"))...) - allErrs = append(allErrs, in.Spec.validateErrno(specField.Child("errno"))...) - allErrs = append(allErrs, in.Spec.validatePercent(specField.Child("percent"))...) - allErrs = append(allErrs, in.Spec.validateMistake(specField.Child("mistake"))...) - - if len(allErrs) > 0 { - return fmt.Errorf(allErrs.ToAggregate().Error()) - } - return nil -} -// ValidateScheduler validates the scheduler and duration -func (in *IoChaos) ValidateScheduler(spec *field.Path) field.ErrorList { - return ValidateScheduler(in, spec) -} + "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" +) -// ValidatePodMode validates the value with podmode -func (in *IoChaos) ValidatePodMode(spec *field.Path) field.ErrorList { - return ValidatePodMode(in.Spec.Value, in.Spec.Mode, spec.Child("value")) -} +type IOErrno uint32 -// SelectSpec returns the selector config for authority validate -func (in *IoChaos) GetSelectSpec() []SelectSpec { - return []SelectSpec{&in.Spec} -} - -func (in *IoChaosSpec) validateDelay(delay *field.Path) field.ErrorList { +func (in *IOErrno) Validate(root interface{}, path *field.Path) field.ErrorList { allErrs := field.ErrorList{} - if in.Action == IoLatency { - _, err := time.ParseDuration(in.Delay) - if err != nil { - allErrs = append(allErrs, field.Invalid(delay, in.Delay, - fmt.Sprintf("parse delay field error:%s for action:%s", err, in.Action))) + obj := root.(*IOChaos) + if obj.Spec.Action == IoFaults { + // in cannot be nil + if *in == 0 { + allErrs = append(allErrs, field.Invalid(path, in, + fmt.Sprintf("action %s: errno 0 is not supported", obj.Spec.Action))) } } return allErrs } -func (in *IoChaosSpec) validateErrno(errno *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if in.Action == IoFaults { - if in.Errno == 0 { - allErrs = append(allErrs, field.Invalid(errno, in.Errno, - fmt.Sprintf("action %s: errno 0 is not supported", in.Action))) - } - } - return allErrs -} - -func (in *IoChaosSpec) validatePercent(percentField *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if in.Percent > 100 || in.Percent < 0 { - allErrs = append(allErrs, field.Invalid(percentField, in.Percent, - "percent field should be in 0-100")) - } - - return allErrs -} - -// Doing nothing now, but keep it here for future use -func (in *IoChaosSpec) validateMistake(mistakeField *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - return allErrs +func init() { + genericwebhook.Register("IOErrno", reflect.PtrTo(reflect.TypeOf(IOErrno(0)))) } diff --git a/api/v1alpha1/iochaos_webhook_test.go b/api/v1alpha1/iochaos_webhook_test.go index 4aab57e710..1a34003e0b 100644 --- a/api/v1alpha1/iochaos_webhook_test.go +++ b/api/v1alpha1/iochaos_webhook_test.go @@ -1,20 +1,22 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -22,232 +24,209 @@ import ( var _ = Describe("iochaos_webhook", func() { Context("Defaulter", func() { It("set default namespace selector", func() { - iochaos := &IoChaos{ + iochaos := &IOChaos{ ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault}, } iochaos.Default() Expect(iochaos.Spec.Selector.Namespaces[0]).To(Equal(metav1.NamespaceDefault)) }) }) - Context("ChaosValidator of iochaos", func() { + Context("webhook.Validator of iochaos", func() { It("Validate", func() { type TestCase struct { name string - chaos IoChaos - execute func(chaos *IoChaos) error + chaos IOChaos + execute func(chaos *IOChaos) error expect string } - duration := "400s" errorDuration := "400S" tcs := []TestCase{ { name: "simple ValidateCreate", - chaos: IoChaos{ + chaos: IOChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo1", }, }, - execute: func(chaos *IoChaos) error { - return chaos.ValidateCreate() + execute: func(chaos *IOChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "", }, { name: "simple ValidateUpdate", - chaos: IoChaos{ + chaos: IOChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo2", }, }, - execute: func(chaos *IoChaos) error { - return chaos.ValidateUpdate(chaos) + execute: func(chaos *IOChaos) error { + _, err := chaos.ValidateUpdate(chaos) + return err }, expect: "", }, { name: "simple ValidateDelete", - chaos: IoChaos{ + chaos: IOChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo3", }, }, - execute: func(chaos *IoChaos) error { - return chaos.ValidateDelete() + execute: func(chaos *IOChaos) error { + _, err := chaos.ValidateDelete() + return err }, expect: "", }, { - name: "only define the Scheduler", - chaos: IoChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo4", - }, - Spec: IoChaosSpec{ - Scheduler: &SchedulerSpec{ - Cron: "@every 10m", - }, - }, - }, - execute: func(chaos *IoChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "only define the Duration", - chaos: IoChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo5", - }, - Spec: IoChaosSpec{ - Duration: &duration, - }, - }, - execute: func(chaos *IoChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "parse the duration and scheduler error", - chaos: IoChaos{ + name: "parse the duration error", + chaos: IOChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo6", }, - Spec: IoChaosSpec{ - Duration: &errorDuration, - Scheduler: &SchedulerSpec{Cron: "xx"}, + Spec: IOChaosSpec{ + Duration: &errorDuration, }, }, - execute: func(chaos *IoChaos) error { - return chaos.ValidateCreate() + execute: func(chaos *IOChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, { - name: "validate value with FixedPercentPodMode", - chaos: IoChaos{ + name: "validate value with FixedPercentMode", + chaos: IOChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo7", }, - Spec: IoChaosSpec{ - Value: "0", - Mode: FixedPodMode, + Spec: IOChaosSpec{ + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Value: "0", + Mode: FixedMode, + }, + }, }, }, - execute: func(chaos *IoChaos) error { - return chaos.ValidateCreate() + execute: func(chaos *IOChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, { - name: "validate value with FixedPercentPodMode, parse value error", - chaos: IoChaos{ + name: "validate value with FixedPercentMode, parse value error", + chaos: IOChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo8", }, - Spec: IoChaosSpec{ - Value: "num", - Mode: FixedPodMode, + Spec: IOChaosSpec{ + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Value: "num", + Mode: FixedMode, + }, + }, }, }, - execute: func(chaos *IoChaos) error { - return chaos.ValidateCreate() + execute: func(chaos *IOChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, { - name: "validate value with RandomMaxPercentPodMode", - chaos: IoChaos{ + name: "validate value with RandomMaxPercentMode", + chaos: IOChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo9", }, - Spec: IoChaosSpec{ - Value: "0", - Mode: RandomMaxPercentPodMode, + Spec: IOChaosSpec{ + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Value: "0", + Mode: RandomMaxPercentMode, + }, + }, }, }, - execute: func(chaos *IoChaos) error { - return chaos.ValidateCreate() + execute: func(chaos *IOChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, { - name: "validate value with RandomMaxPercentPodMode ,parse value error", - chaos: IoChaos{ + name: "validate value with RandomMaxPercentMode ,parse value error", + chaos: IOChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo10", }, - Spec: IoChaosSpec{ - Value: "num", - Mode: RandomMaxPercentPodMode, + Spec: IOChaosSpec{ + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Value: "num", + Mode: RandomMaxPercentMode, + }, + }, }, }, - execute: func(chaos *IoChaos) error { - return chaos.ValidateCreate() + execute: func(chaos *IOChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, { - name: "validate value with FixedPercentPodMode", - chaos: IoChaos{ + name: "validate value with FixedPercentMode", + chaos: IOChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo11", }, - Spec: IoChaosSpec{ - Value: "101", - Mode: FixedPercentPodMode, + Spec: IOChaosSpec{ + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Value: "101", + Mode: FixedPercentMode, + }, + }, }, }, - execute: func(chaos *IoChaos) error { - return chaos.ValidateCreate() + execute: func(chaos *IOChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, { name: "validate delay", - chaos: IoChaos{ + chaos: IOChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, Name: "foo12", }, - Spec: IoChaosSpec{ + Spec: IOChaosSpec{ Delay: "1S", Action: IoLatency, }, }, - execute: func(chaos *IoChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "parse the scheduler.cron error", - chaos: IoChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo15", - }, - Spec: IoChaosSpec{ - Duration: &duration, - Scheduler: &SchedulerSpec{Cron: "xx"}, - }, - }, - execute: func(chaos *IoChaos) error { - return chaos.ValidateCreate() + execute: func(chaos *IOChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, diff --git a/api/v1alpha1/jvmchaos_types.go b/api/v1alpha1/jvmchaos_types.go index 7ac373e193..d4d31f4a9a 100644 --- a/api/v1alpha1/jvmchaos_types.go +++ b/api/v1alpha1/jvmchaos_types.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 @@ -19,148 +21,140 @@ import ( // JVMChaosSpec defines the desired state of JVMChaos type JVMChaosSpec struct { - // Mode defines the mode to run chaos action. - // Supported mode: one / all / fixed / fixed-percent / random-max-percent - Mode PodMode `json:"mode"` - - // Value is required when the mode is set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - // If `FixedPodMode`, provide an integer of pods to do chaos action. - // If `FixedPercentPodMod`, provide a number from 0-100 to specify the max % of pods the server can do chaos action. - // If `RandomMaxPercentPodMod`, provide a number from 0-100 to specify the % of pods to do chaos action - // +optional - Value string `json:"value"` - - // Selector is used to select pods that are used to inject chaos action. - Selector SelectorSpec `json:"selector"` + ContainerSelector `json:",inline"` // Duration represents the duration of the chaos action // +optional - Duration *string `json:"duration,omitempty"` - - // Scheduler defines some schedule rules to control the running time of the chaos experiment about time. - // +optional - Scheduler *SchedulerSpec `json:"scheduler,omitempty"` + Duration *string `json:"duration,omitempty" webhook:"Duration"` // Action defines the specific jvm chaos action. - // Supported action: delay;return;script;cfl;oom;ccf;tce;cpf;tde;tpf - // +kubebuilder:validation:Enum=delay;return;script;cfl;oom;ccf;tce;cpf;tde;tpf + // Supported action: latency;return;exception;stress;gc;ruleData + // +kubebuilder:validation:Enum=latency;return;exception;stress;gc;ruleData;mysql Action JVMChaosAction `json:"action"` // JVMParameter represents the detail about jvm chaos action definition // +optional JVMParameter `json:",inline"` - // Target defines the specific jvm chaos target. - // Supported target: servlet;psql;jvm;jedis;http;dubbo;rocketmq;tars;mysql;druid;redisson;rabbitmq;mongodb - // +kubebuilder:validation:Enum=servlet;psql;jvm;jedis;http;dubbo;rocketmq;tars;mysql;druid;redisson;rabbitmq;mongodb - Target JVMChaosTarget `json:"target"` -} - -// GetSelector is a getter for Selector (for implementing SelectSpec) -func (in *JVMChaosSpec) GetSelector() SelectorSpec { - return in.Selector -} - -// GetMode is a getter for Mode (for implementing SelectSpec) -func (in *JVMChaosSpec) GetMode() PodMode { - return in.Mode -} - -// GetValue is a getter for Value (for implementing SelectSpec) -func (in *JVMChaosSpec) GetValue() string { - return in.Value + // RemoteCluster represents the remote cluster where the chaos will be deployed + // +optional + RemoteCluster string `json:"remoteCluster,omitempty"` } -type JVMChaosTarget string +// JVMChaosAction represents the chaos action about jvm +type JVMChaosAction string const ( - // SERVLET represents servlet as a target of chaos - SERVLET JVMChaosTarget = "servlet" - - // PSQL represents Postgresql JDBC as a target of chaos - PSQL JVMChaosTarget = "psql" - - // JVM represents JVM as a target of chaos - JVM JVMChaosTarget = "jvm" - - // JEDIS represents jedis (a java redis client) as a target of chaos - JEDIS JVMChaosTarget = "jedis" - - // HTTP represents http client as a target of chaos - HTTP JVMChaosTarget = "http" - - // DUBBO represents a Dubbo services as a target of chaos - DUBBO JVMChaosTarget = "dubbo" - - // ROCKETMQ represents Rocketmq java client as a target of chaos - ROCKETMQ JVMChaosTarget = "rocketmq" + // JVMLatencyAction represents the JVM chaos action of invoke latency + JVMLatencyAction JVMChaosAction = "latency" - // MYSQL represents Mysql JDBC as a target of chaos - MYSQL JVMChaosTarget = "mysql" + // JVMReturnAction represents the JVM chaos action of return value + JVMReturnAction JVMChaosAction = "return" - // DRUID represents the Druid database connection pool as a target of chaos - DRUID JVMChaosTarget = "druid" + // JVMExceptionAction represents the JVM chaos action of throwing custom exceptions + JVMExceptionAction JVMChaosAction = "exception" - // TARS represents the Tars service as a target of chaos - TARS JVMChaosTarget = "tars" + // JVMStressAction represents the JVM chaos action of stress like CPU and memory + JVMStressAction JVMChaosAction = "stress" - // REDISSON represents Redisson (a java redis client) as a target of chaos - REDISSON JVMChaosTarget = "redisson" + // JVMGCAction represents the JVM chaos action of trigger garbage collection + JVMGCAction JVMChaosAction = "gc" - // RABBITMQ represents the Rabbitmq java client as a target of chaos - RABBITMQ JVMChaosTarget = "rabbitmq" + // JVMRuleDataAction represents inject fault with byteman's rule + // refer to https://downloads.jboss.org/byteman/4.0.14/byteman-programmers-guide.html#the-byteman-rule-language + JVMRuleDataAction JVMChaosAction = "ruleData" - // MONGODB represents the Mongodb java client as a target of chaos - MONGODB JVMChaosTarget = "mongodb" + // JVMMySQLAction represents the JVM chaos action of mysql java client fault injection + JVMMySQLAction JVMChaosAction = "mysql" ) -// JVMChaosAction represents the chaos action about jvm -type JVMChaosAction string +// JVMParameter represents the detail about jvm chaos action definition +type JVMParameter struct { + JVMCommonSpec `json:",inline"` -const ( - // JVMDelayAction represents the JVM chaos action of invoke delay - JVMDelayAction JVMChaosAction = "delay" + JVMClassMethodSpec `json:",inline"` - // JVMReturnAction represents the JVM chaos action of return value - JVMReturnAction JVMChaosAction = "return" + JVMStressCfgSpec `json:",inline"` - // JVMReturnAction represents the JVM chaos action for complex failure scenarios. - // Write Java or Groovy scripts, such as tampering with parameters, modifying return values, - // throwing custom exceptions, and so on - JVMScriptAction JVMChaosAction = "script" + JVMMySQLSpec `json:",inline"` - // JVMCpuFullloadAction represents the JVM chaos action of CPU is full - JVMCpuFullloadAction JVMChaosAction = "cfl" + // +optional + // byteman rule name, should be unique, and will generate one if not set + Name string `json:"name"` - // JVMOOMAction represents the JVM chaos action of OOM exception - JVMOOMAction JVMChaosAction = "oom" + // +optional + // the return value for action 'return' + ReturnValue string `json:"value"` - // JVMCodeCacheFillingAction represents the JVM chaos action of code cache filling - JVMCodeCacheFillingAction JVMChaosAction = "ccf" + // +optional + // the exception which needs to throw for action `exception` + // or the exception message needs to throw in action `mysql` + ThrowException string `json:"exception"` - // JVMExceptionAction represents the JVM chaos action of throwing custom exceptions - JVMExceptionAction JVMChaosAction = "tce" + // +optional + // the latency duration for action 'latency', unit ms + // or the latency duration in action `mysql` + LatencyDuration int `json:"latency"` - // JVMConnectionPoolFullAction represents the JVM chaos action of Connection Pool Full - JVMConnectionPoolFullAction JVMChaosAction = "cpf" + // +optional + // the byteman rule's data for action 'ruleData' + RuleData string `json:"ruleData"` +} - // JVMThrowDeclaredExceptionAction represents the JVM chaos action of throwing declared exception - JVMThrowDeclaredExceptionAction JVMChaosAction = "tde" +// JVMCommonSpec is the common specification for JVMChaos +type JVMCommonSpec struct { + // +optional + // the port of agent server, default 9277 + Port int32 `json:"port,omitempty"` - // JVMThreadPoolFullAction represents the JVM chaos action of thread pool full - JVMThreadPoolFullAction JVMChaosAction = "tpf" -) + // the pid of Java process which needs to attach + Pid int `json:"pid,omitempty"` +} -// JVMParameter represents the detail about jvm chaos action definition -type JVMParameter struct { +// JVMClassMethodSpec is the specification for class and method +type JVMClassMethodSpec struct { + // +optional + // Java class + Class string `json:"class,omitempty"` + + // +optional + // the method in Java class + Method string `json:"method,omitempty"` +} - // Flags represents the flags of action +// JVMStressSpec is the specification for stress +type JVMStressCfgSpec struct { // +optional - Flags map[string]string `json:"flags,omitempty"` + // the CPU core number needs to use, only set it when action is stress + CPUCount int `json:"cpuCount,omitempty"` - // Matchers represents the matching rules for the target // +optional - Matchers map[string]string `json:"matchers,omitempty"` + // the memory type needs to locate, only set it when action is stress, the value can be 'stack' or 'heap' + MemoryType string `json:"memType,omitempty"` +} + +// JVMMySQLSpec is the specification of MySQL fault injection in JVM +// only when SQL match the Database, Table and SQLType, JVMChaos mesh will inject fault +// for examle: +// +// SQL is "select * from test.t1", +// only when ((Database == "test" || Database == "") && (Table == "t1" || Table == "") && (SQLType == "select" || SQLType == "")) is true, JVMChaos will inject fault +type JVMMySQLSpec struct { + // the version of mysql-connector-java, only support 5.X.X(set to "5") and 8.X.X(set to "8") now + MySQLConnectorVersion string `json:"mysqlConnectorVersion,omitempty"` + + // the match database + // default value is "", means match all database + Database string `json:"database,omitempty"` + + // the match table + // default value is "", means match all table + Table string `json:"table,omitempty"` + + // the match sql type + // default value is "", means match all SQL type. + // The value can be 'select', 'insert', 'update', 'delete', 'replace'. + SQLType string `json:"sqlType,omitempty"` } // JVMChaosStatus defines the observed state of JVMChaos @@ -169,7 +163,9 @@ type JVMChaosStatus struct { } // +kubebuilder:object:root=true -// +chaos-mesh:base +// +kubebuilder:printcolumn:name="action",type=string,JSONPath=`.spec.action` +// +kubebuilder:printcolumn:name="duration",type=string,JSONPath=`.spec.duration` +// +chaos-mesh:experiment // JVMChaos is the Schema for the jvmchaos API type JVMChaos struct { @@ -180,6 +176,15 @@ type JVMChaos struct { Status JVMChaosStatus `json:"status,omitempty"` } +var _ InnerObjectWithSelector = (*JVMChaos)(nil) +var _ InnerObject = (*JVMChaos)(nil) + func init() { SchemeBuilder.Register(&JVMChaos{}, &JVMChaosList{}) } + +func (obj *JVMChaos) GetSelectorSpecs() map[string]interface{} { + return map[string]interface{}{ + ".": &obj.Spec.ContainerSelector, + } +} diff --git a/api/v1alpha1/jvmchaos_types_test.go b/api/v1alpha1/jvmchaos_types_test.go index 2fd19b7663..588bd4d248 100644 --- a/api/v1alpha1/jvmchaos_types_test.go +++ b/api/v1alpha1/jvmchaos_types_test.go @@ -1,25 +1,25 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "context" - "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) @@ -54,9 +54,19 @@ var _ = Describe("JVMChaos", func() { Namespace: "default", }, Spec: JVMChaosSpec{ - Action: JVMDelayAction, - Target: SERVLET, - Mode: OnePodMode, + Action: JVMLatencyAction, + JVMParameter: JVMParameter{ + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "print", + }, + LatencyDuration: 1000, + }, + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Mode: OneMode, + }, + }, }, } @@ -71,19 +81,5 @@ var _ = Describe("JVMChaos", func() { Expect(k8sClient.Delete(context.TODO(), created)).To(Succeed()) Expect(k8sClient.Get(context.TODO(), key, created)).ToNot(Succeed()) }) - - It("should set next start time successfully", func() { - jvmchaos := &JVMChaos{} - nTime := time.Now() - jvmchaos.SetNextStart(nTime) - Expect(jvmchaos.GetNextStart()).To(Equal(nTime)) - }) - - It("should set recover time successfully", func() { - jvmchaos := &JVMChaos{} - nTime := time.Now() - jvmchaos.SetNextRecover(nTime) - Expect(jvmchaos.GetNextRecover()).To(Equal(nTime)) - }) }) }) diff --git a/api/v1alpha1/jvmchaos_webhook.go b/api/v1alpha1/jvmchaos_webhook.go index 21bd21169e..b4c1139c23 100644 --- a/api/v1alpha1/jvmchaos_webhook.go +++ b/api/v1alpha1/jvmchaos_webhook.go @@ -1,646 +1,98 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "fmt" - "strconv" + "reflect" + "time" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/webhook" ) -// log is for logging in this package. -var jvmchaoslog = logf.Log.WithName("jvmchaos-resource") - -// +kubebuilder:webhook:path=/mutate-chaos-mesh-org-v1alpha1-jvmchaos,mutating=true,failurePolicy=fail,groups=chaos-mesh.org,resources=jvmchaos,verbs=create;update,versions=v1alpha1,name=mjvmchaos.kb.io - -var _ webhook.Defaulter = &JVMChaos{} - -// Default implements webhook.Defaulter so a webhook will be registered for the type -func (in *JVMChaos) Default() { - jvmchaoslog.Info("default", "name", in.Name) - - in.Spec.Selector.DefaultNamespace(in.GetNamespace()) -} - -// +kubebuilder:webhook:verbs=create;update,path=/validate-chaos-mesh-org-v1alpha1-jvmchaos,mutating=false,failurePolicy=fail,groups=chaos-mesh.org,resources=jvmchaos,versions=v1alpha1,name=vjvmchaos.kb.io - -var _ ChaosValidator = &JVMChaos{} - -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (in *JVMChaos) ValidateCreate() error { - jvmchaoslog.Info("validate create", "name", in.Name) - - return in.Validate() -} - -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (in *JVMChaos) ValidateUpdate(old runtime.Object) error { - jvmchaoslog.Info("validate update", "name", in.Name) - - return in.Validate() -} - -// ValidateDelete implements webhook.Validator so a webhook will be registered for the type -func (in *JVMChaos) ValidateDelete() error { - jvmchaoslog.Info("validate delete", "name", in.Name) +const DefaultJVMAgentPort int32 = 9277 - // Nothing to do? - return nil -} - -// Validate validates chaos object -func (in *JVMChaos) Validate() error { - specField := field.NewPath("spec") - allErrs := in.ValidateScheduler(specField) - allErrs = append(allErrs, in.ValidatePodMode(specField)...) - allErrs = append(allErrs, in.validateJvmChaos(specField)...) - if len(allErrs) > 0 { - return fmt.Errorf(allErrs.ToAggregate().Error()) +func (in *JVMChaosSpec) Default(root interface{}, field *reflect.StructField) { + if in == nil { + return } - return nil -} - -// ValidateScheduler validates the scheduler and duration -func (in *JVMChaos) ValidateScheduler(spec *field.Path) field.ErrorList { - return ValidateScheduler(in, spec) -} - -// ValidatePodMode validates the value with podmode -func (in *JVMChaos) ValidatePodMode(spec *field.Path) field.ErrorList { - return ValidatePodMode(in.Spec.Value, in.Spec.Mode, spec.Child("value")) -} - -// SelectSpec returns the selector config for authority validate -func (in *JVMChaos) GetSelectSpec() []SelectSpec { - return []SelectSpec{&in.Spec} -} - -func (in *JVMChaos) validateJvmChaos(spec *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - targetField := spec.Child("target") - actionField := spec.Child("action") - flagsField := spec.Child("flags") - matcherField := spec.Child("matcher") - if actions, ok := JvmSpec[in.Spec.Target]; ok { - - if actionPR, actionOK := actions[in.Spec.Action]; actionOK { - if actionPR.Flags != nil { - allErrs = append(allErrs, in.validateParameterRules(in.Spec.Flags, actionPR.Flags, flagsField, targetField, actionField)...) - } - - if actionPR.Matchers != nil { - allErrs = append(allErrs, in.validateParameterRules(in.Spec.Matchers, actionPR.Matchers, matcherField, targetField, actionField)...) - } - - } else { - supportActions := make([]JVMChaosAction, 0) - for k := range actions { - supportActions = append(supportActions, k) - } - - notSupportedError := field.NotSupported(actionField, in.Spec.Action, toString(supportActions)) - errorMsg := fmt.Sprintf("target: %s does not match action: %s, action detail error: %s", - in.Spec.Target, in.Spec.Action, notSupportedError) - allErrs = append(allErrs, field.Invalid(targetField, in.Spec.Target, errorMsg)) - } - } else { - allErrs = append(allErrs, field.Invalid(targetField, in.Spec.Target, "unknown JVM chaos target")) + if len(in.Name) == 0 { + in.Name = fmt.Sprintf("%s-%s-%s-%d", in.Class, in.Method, in.Action, time.Now().Unix()) } - return allErrs -} - -func toString(actions []JVMChaosAction) []string { - ret := make([]string, 0) - for _, act := range actions { - ret = append(ret, string(act)) + if in.Port == 0 { + in.Port = DefaultJVMAgentPort } - return ret } -func (in *JVMChaos) validateParameterRules(parameters map[string]string, rules []ParameterRules, parent *field.Path, target *field.Path, action *field.Path) field.ErrorList { +func (in *JVMChaosSpec) Validate(root interface{}, path *field.Path) field.ErrorList { allErrs := field.ErrorList{} - for _, rule := range rules { - innerField := parent.Child(rule.Name) - var value = "" - var exist = false - if parameters != nil { - value, exist = parameters[rule.Name] + switch in.Action { + case JVMStressAction: + if in.CPUCount == 0 && len(in.MemoryType) == 0 { + allErrs = append(allErrs, field.Invalid(path, in, "must set one of cpu-count and mem-type when action is 'stress'")) } - if rule.Required && !exist { - errorMsg := fmt.Sprintf("with %s: %s, %s: %s", target, in.Spec.Target, action, in.Spec.Action) - allErrs = append(allErrs, field.Required(innerField, errorMsg)) + + if in.CPUCount > 0 && len(in.MemoryType) > 0 { + allErrs = append(allErrs, field.Invalid(path, in, "inject stress on both CPU and memory is not support now")) } - if exist && rule.Required && rule.ParameterType == StringType { - if len(value) == 0 { - errorMsg := fmt.Sprintf("%s:%s cannot be empty", innerField, value) - allErrs = append(allErrs, field.Invalid(innerField, value, errorMsg)) + if len(in.MemoryType) != 0 { + if in.MemoryType != "stack" && in.MemoryType != "heap" { + allErrs = append(allErrs, field.Invalid(path, in, "value should be 'stack' or 'heap'")) } } + case JVMGCAction: + // do nothing + case JVMExceptionAction, JVMReturnAction, JVMLatencyAction: + if len(in.Class) == 0 { + allErrs = append(allErrs, field.Invalid(path, in, "class not provided")) + } - if exist && rule.ParameterType == IntType { - _, err := strconv.Atoi(value) - if err != nil { - errorMsg := fmt.Sprintf("%s:%s cannot parse as Int", innerField, value) - allErrs = append(allErrs, field.Invalid(innerField, value, errorMsg)) - } + if len(in.Method) == 0 { + allErrs = append(allErrs, field.Invalid(path, in, "method not provided")) + } + if in.Action == JVMExceptionAction && len(in.ThrowException) == 0 { + allErrs = append(allErrs, field.Invalid(path, in, "exception not provided")) + } else if in.Action == JVMReturnAction && len(in.ReturnValue) == 0 { + allErrs = append(allErrs, field.Invalid(path, in, "value not provided")) + } else if in.Action == JVMLatencyAction && in.LatencyDuration == 0 { + allErrs = append(allErrs, field.Invalid(path, in, "latency not provided")) } - if exist && rule.ParameterType == BoolType { - _, err := strconv.ParseBool(value) - if err != nil { - errorMsg := fmt.Sprintf("%s:%s cannot parse as boolean", innerField, value) - allErrs = append(allErrs, field.Invalid(innerField, value, errorMsg)) - } + case JVMRuleDataAction: + if len(in.RuleData) == 0 { + allErrs = append(allErrs, field.Invalid(path, in, "rule data not provide")) } + case JVMMySQLAction: + if len(in.MySQLConnectorVersion) == 0 { + allErrs = append(allErrs, field.Invalid(path, in, "MySQL connector version not provided")) + } else if in.MySQLConnectorVersion != "5" && in.MySQLConnectorVersion != "8" { + allErrs = append(allErrs, field.Invalid(path, in, "MySQL connector version only support 5.X.X(set to 5) and 8.X.X(set to 8)")) + } + if len(in.ThrowException) == 0 && in.LatencyDuration == 0 { + allErrs = append(allErrs, field.Invalid(path, in, "must set one of exception or latency")) + } + case "": + allErrs = append(allErrs, field.Invalid(path, in, "action not provided")) + default: + allErrs = append(allErrs, field.Invalid(path, in, fmt.Sprintf("action %s not supported, action can be 'latency', 'exception', 'return', 'stress', 'gc' or 'ruleData'", in.Action))) } - return allErrs -} - -// +kubebuilder:object:generate=false - -// JvmSpec from chaosblade-jvm-spec.yaml -// chaosblade-jvm-spec.yaml file generated by -// https://github.com/chaosblade-io/chaosblade-exec-jvm/blob/master/chaosblade-exec-service/src/main/java/com/alibaba/chaosblade/exec/service/build/SpecMain.java -var JvmSpec = map[JVMChaosTarget]map[JVMChaosAction]ActionParameterRules{ - SERVLET: { - JVMDelayAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "time", ParameterType: IntType, Required: true}, - {Name: "offset", ParameterType: IntType}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "method"}, - {Name: "querystring"}, - {Name: "requestpath"}, - }, - }, - JVMExceptionAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "exception", Required: true}, - {Name: "exception-message"}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "method"}, - {Name: "querystring"}, - {Name: "requestpath"}, - }, - }, - }, - PSQL: { - JVMDelayAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "time", ParameterType: IntType, Required: true}, - {Name: "offset", ParameterType: IntType}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "sqltype"}, - {Name: "database"}, - {Name: "port", ParameterType: IntType}, - {Name: "host"}, - {Name: "table"}, - }, - }, - JVMExceptionAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "exception", Required: true}, - {Name: "exception-message"}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "sqltype"}, - {Name: "database"}, - {Name: "port", ParameterType: IntType}, - {Name: "host"}, - {Name: "table"}, - }, - }, - }, - MYSQL: { - JVMDelayAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "time", ParameterType: IntType, Required: true}, - {Name: "offset", ParameterType: IntType}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "sqltype"}, - {Name: "database"}, - {Name: "port", ParameterType: IntType}, - {Name: "host"}, - {Name: "table"}, - }, - }, - JVMExceptionAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "exception", Required: true}, - {Name: "exception-message"}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "sqltype"}, - {Name: "database"}, - {Name: "port", ParameterType: IntType}, - {Name: "host"}, - {Name: "table"}, - }, - }, - }, - JEDIS: { - JVMDelayAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "time", ParameterType: IntType, Required: true}, - {Name: "offset", ParameterType: IntType}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "cmd"}, - {Name: "key"}, - }, - }, - JVMExceptionAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "exception", Required: true}, - {Name: "exception-message"}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "cmd"}, - {Name: "key"}, - }, - }, - }, - HTTP: { - JVMDelayAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "time", ParameterType: IntType, Required: true}, - {Name: "offset", ParameterType: IntType}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "httpclient4", ParameterType: BoolType}, - {Name: "rest", ParameterType: BoolType}, - {Name: "httpclient3", ParameterType: BoolType}, - {Name: "okhttp3", ParameterType: BoolType}, - {Name: "uri", Required: true}, - }, - }, - JVMExceptionAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "exception", Required: true}, - {Name: "exception-message"}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "httpclient4", ParameterType: BoolType}, - {Name: "rest", ParameterType: BoolType}, - {Name: "httpclient3", ParameterType: BoolType}, - {Name: "okhttp3", ParameterType: BoolType}, - {Name: "uri", Required: true}, - }, - }, - }, - RABBITMQ: { - JVMDelayAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "time", ParameterType: IntType, Required: true}, - {Name: "offset", ParameterType: IntType}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "routingkey"}, - {Name: "producer", ParameterType: BoolType}, - {Name: "topic"}, - {Name: "exchange"}, - {Name: "consumer", ParameterType: BoolType}, - }, - }, - JVMExceptionAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "exception", Required: true}, - {Name: "exception-message"}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "routingkey"}, - {Name: "producer", ParameterType: BoolType}, - {Name: "topic"}, - {Name: "exchange"}, - {Name: "consumer", ParameterType: BoolType}, - }, - }, - }, - TARS: { - JVMDelayAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "time", ParameterType: IntType, Required: true}, - {Name: "offset", ParameterType: IntType}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "servant", ParameterType: BoolType}, - {Name: "functionname"}, - {Name: "client", ParameterType: BoolType}, - {Name: "servantname", Required: true}, - }, - }, - JVMExceptionAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "exception", Required: true}, - {Name: "exception-message"}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "servant", ParameterType: BoolType}, - {Name: "functionname"}, - {Name: "client", ParameterType: BoolType}, - {Name: "servantname", Required: true}, - }, - }, - }, - DUBBO: { - JVMDelayAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "time", ParameterType: IntType, Required: true}, - {Name: "offset", ParameterType: IntType}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "appname"}, - {Name: "provider", ParameterType: BoolType}, - {Name: "service"}, - {Name: "version"}, - {Name: "consumer", ParameterType: BoolType}, - {Name: "methodname"}, - {Name: "group"}, - }, - }, - JVMExceptionAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "exception", Required: true}, - {Name: "exception-message"}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "appname"}, - {Name: "provider", ParameterType: BoolType}, - {Name: "service"}, - {Name: "version"}, - {Name: "consumer", ParameterType: BoolType}, - {Name: "methodname"}, - {Name: "group"}, - }, - }, - JVMThreadPoolFullAction: ActionParameterRules{ - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "provider", ParameterType: BoolType}, - }, - }, - }, - JVM: { - JVMDelayAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "time", ParameterType: IntType, Required: true}, - {Name: "offset", ParameterType: IntType}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "classname", Required: true}, - {Name: "after", ParameterType: BoolType}, - {Name: "methodname", Required: true}, - }, - }, - JVMExceptionAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "exception", Required: true}, - {Name: "exception-message"}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "classname", Required: true}, - {Name: "after", ParameterType: BoolType}, - {Name: "methodname", Required: true}, - }, - }, - JVMCodeCacheFillingAction: ActionParameterRules{}, - JVMCpuFullloadAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "cpu-count", ParameterType: IntType}, - }, - }, - JVMThrowDeclaredExceptionAction: ActionParameterRules{ - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "classname", Required: true}, - {Name: "after", ParameterType: BoolType}, - {Name: "methodname", Required: true}, - }, - }, - JVMReturnAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "value", Required: true}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "classname", Required: true}, - {Name: "after", ParameterType: BoolType}, - {Name: "methodname", Required: true}, - }, - }, - JVMScriptAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "script-file"}, - {Name: "script-type"}, - {Name: "script-content"}, - {Name: "script-name"}, - {Name: "external-jar"}, - {Name: "external-jar-path"}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "classname", Required: true}, - {Name: "after", ParameterType: BoolType}, - {Name: "methodname", Required: true}, - }, - }, - JVMOOMAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "area", Required: true}, - {Name: "wild-mode", ParameterType: BoolType}, - {Name: "interval", ParameterType: IntType}, - {Name: "block", ParameterType: IntType}, - }, - }, - }, - DRUID: { - JVMConnectionPoolFullAction: ActionParameterRules{ - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - }, - }, - }, - REDISSON: { - JVMDelayAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "time", ParameterType: IntType, Required: true}, - {Name: "offset", ParameterType: IntType}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "cmd"}, - {Name: "key"}, - }, - }, - JVMExceptionAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "exception", Required: true}, - {Name: "exception-message"}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "cmd"}, - {Name: "key"}, - }, - }, - }, - ROCKETMQ: { - JVMDelayAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "time", ParameterType: IntType, Required: true}, - {Name: "offset", ParameterType: IntType}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "producerGroup"}, - {Name: "producer"}, - {Name: "topic", Required: true}, - {Name: "consumerGroup"}, - }, - }, - JVMExceptionAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "exception", Required: true}, - {Name: "exception-message"}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "producerGroup"}, - {Name: "producer"}, - {Name: "topic", Required: true}, - {Name: "consumerGroup"}, - }, - }, - }, - MONGODB: { - JVMDelayAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "time", ParameterType: IntType, Required: true}, - {Name: "offset", ParameterType: IntType}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "sqltype"}, - {Name: "database"}, - {Name: "false"}, - }, - }, - JVMExceptionAction: ActionParameterRules{ - Flags: []ParameterRules{ - {Name: "exception", Required: true}, - {Name: "exception-message"}, - }, - Matchers: []ParameterRules{ - {Name: "effect-count", ParameterType: IntType}, - {Name: "effect-percent", ParameterType: IntType}, - {Name: "sqltype"}, - {Name: "database"}, - {Name: "false"}, - }, - }, - }, -} - -// ActionParameterRules defines the parameter validation rules for action -type ActionParameterRules struct { - // Flags represents the parameter validation rules for flags - Flags []ParameterRules - - // Matchers represents the parameter validation rules for Matcher - Matchers []ParameterRules -} - -// ParameterType defines the parameter type -type ParameterType string -const ( - // IntType a int type parameter - IntType ParameterType = "int" - - // BoolType a boolean type parameter - BoolType ParameterType = "bool" - - // StringType a string type parameter - StringType ParameterType = "string" -) - -// ParameterRules defines the parameter validation rules -type ParameterRules struct { - // Name represents the name of parameter - Name string - - // ParameterType represents the parameter type - ParameterType ParameterType - - // Required defines whether it is a required parameter - Required bool + return allErrs } diff --git a/api/v1alpha1/jvmchaos_webhook_test.go b/api/v1alpha1/jvmchaos_webhook_test.go new file mode 100644 index 0000000000..6b11ed6fe9 --- /dev/null +++ b/api/v1alpha1/jvmchaos_webhook_test.go @@ -0,0 +1,278 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("jvmchaos_webhook", func() { + Context("Defaulter", func() { + It("set default namespace selector", func() { + jvmchaos := &JVMChaos{ + ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault}, + } + jvmchaos.Default() + Expect(jvmchaos.Spec.Selector.Namespaces[0]).To(Equal(metav1.NamespaceDefault)) + }) + }) + Context("webhook.Validator of jvmchaos", func() { + It("Validate JVMChaos", func() { + + type TestCase struct { + name string + chaos JVMChaos + execute func(chaos *JVMChaos) error + expect string + } + + tcs := []TestCase{ + { + name: "simple ValidateCreate", + chaos: JVMChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo1", + }, + Spec: JVMChaosSpec{ + Action: JVMLatencyAction, + JVMParameter: JVMParameter{ + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "print", + }, + LatencyDuration: 1000, + }, + }, + }, + execute: func(chaos *JVMChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "", + }, + { + name: "simple ValidateUpdate", + chaos: JVMChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo2", + }, + Spec: JVMChaosSpec{ + Action: JVMLatencyAction, + JVMParameter: JVMParameter{ + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "print", + }, + LatencyDuration: 1000, + }, + }, + }, + execute: func(chaos *JVMChaos) error { + _, err := chaos.ValidateUpdate(chaos) + return err + }, + expect: "", + }, + { + name: "simple ValidateDelete", + chaos: JVMChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo3", + }, + Spec: JVMChaosSpec{ + Action: JVMLatencyAction, + JVMParameter: JVMParameter{ + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "print", + }, + LatencyDuration: 1000, + }, + }, + }, + execute: func(chaos *JVMChaos) error { + _, err := chaos.ValidateDelete() + return err + }, + expect: "", + }, + { + name: "missing latency", + chaos: JVMChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo4", + }, + Spec: JVMChaosSpec{ + Action: JVMLatencyAction, + JVMParameter: JVMParameter{ + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "print", + }, + }, + }, + }, + execute: func(chaos *JVMChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "missing value", + chaos: JVMChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo5", + }, + Spec: JVMChaosSpec{ + Action: JVMReturnAction, + JVMParameter: JVMParameter{ + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "print", + }, + }, + }, + }, + execute: func(chaos *JVMChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "missing exception", + chaos: JVMChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo6", + }, + Spec: JVMChaosSpec{ + Action: JVMExceptionAction, + JVMParameter: JVMParameter{ + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "print", + }, + }, + }, + }, + execute: func(chaos *JVMChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "missing class", + chaos: JVMChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo7", + }, + Spec: JVMChaosSpec{ + Action: JVMLatencyAction, + JVMParameter: JVMParameter{ + JVMClassMethodSpec: JVMClassMethodSpec{ + Method: "print", + }, + LatencyDuration: 1000, + }, + }, + }, + execute: func(chaos *JVMChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "missing method", + chaos: JVMChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo8", + }, + Spec: JVMChaosSpec{ + Action: JVMLatencyAction, + JVMParameter: JVMParameter{ + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + }, + LatencyDuration: 1000, + }, + }, + }, + execute: func(chaos *JVMChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "missing rule data", + chaos: JVMChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo9", + }, + Spec: JVMChaosSpec{ + Action: JVMRuleDataAction, + }, + }, + execute: func(chaos *JVMChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "missing cpu-count and memory type", + chaos: JVMChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo10", + }, + Spec: JVMChaosSpec{ + Action: JVMStressAction, + }, + }, + execute: func(chaos *JVMChaos) error { + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + } + + for _, tc := range tcs { + err := tc.execute(&tc.chaos) + if tc.expect == "error" { + Expect(err).To(HaveOccurred()) + } else { + Expect(err).NotTo(HaveOccurred()) + } + } + }) + }) +}) diff --git a/api/v1alpha1/kernelchaos_types.go b/api/v1alpha1/kernelchaos_types.go index ae3db33cea..ddb6b6bbd4 100644 --- a/api/v1alpha1/kernelchaos_types.go +++ b/api/v1alpha1/kernelchaos_types.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 @@ -18,7 +20,8 @@ import ( ) // +kubebuilder:object:root=true -// +chaos-mesh:base +// +kubebuilder:printcolumn:name="duration",type=string,JSONPath=`.spec.duration` +// +chaos-mesh:experiment // KernelChaos is the Schema for the kernelchaos API type KernelChaos struct { @@ -33,46 +36,22 @@ type KernelChaos struct { Status KernelChaosStatus `json:"status"` } +var _ InnerObjectWithSelector = (*KernelChaos)(nil) +var _ InnerObject = (*KernelChaos)(nil) + // KernelChaosSpec defines the desired state of KernelChaos type KernelChaosSpec struct { - // Mode defines the mode to run chaos action. - // Supported mode: one / all / fixed / fixed-percent / random-max-percent - // +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent - Mode PodMode `json:"mode"` - - // Value is required when the mode is set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - // If `FixedPodMode`, provide an integer of pods to do chaos action. - // If `FixedPercentPodMod`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. - // If `RandomMaxPercentPodMod`, provide a number from 0-100 to specify the max percent of pods to do chaos action - // +optional - Value string `json:"value"` - - // Selector is used to select pods that are used to inject chaos action. - Selector SelectorSpec `json:"selector"` + ContainerSelector `json:",inline"` // FailKernRequest defines the request of kernel injection FailKernRequest FailKernRequest `json:"failKernRequest"` // Duration represents the duration of the chaos action - Duration *string `json:"duration,omitempty"` + Duration *string `json:"duration,omitempty" webhook:"Duration"` - // Scheduler defines some schedule rules to control the running time of the chaos experiment about time. - Scheduler *SchedulerSpec `json:"scheduler,omitempty"` -} - -// GetSelector is a getter for Selector (for implementing SelectSpec) -func (in *KernelChaosSpec) GetSelector() SelectorSpec { - return in.Selector -} - -// GetMode is a getter for Mode (for implementing SelectSpec) -func (in *KernelChaosSpec) GetMode() PodMode { - return in.Mode -} - -// GetValue is a getter for Value (for implementing SelectSpec) -func (in *KernelChaosSpec) GetValue() string { - return in.Value + // RemoteCluster represents the remote cluster where the chaos will be deployed + // +optional + RemoteCluster string `json:"remoteCluster,omitempty"` } // FailKernRequest defines the injection conditions @@ -138,3 +117,9 @@ type Frame struct { type KernelChaosStatus struct { ChaosStatus `json:",inline"` } + +func (obj *KernelChaos) GetSelectorSpecs() map[string]interface{} { + return map[string]interface{}{ + ".": &obj.Spec.PodSelector, + } +} diff --git a/api/v1alpha1/kernelchaos_webhook.go b/api/v1alpha1/kernelchaos_webhook.go deleted file mode 100644 index 493fe823da..0000000000 --- a/api/v1alpha1/kernelchaos_webhook.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package v1alpha1 - -import ( - "fmt" - - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/validation/field" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/webhook" -) - -// log is for logging in this package. -var kernelchaoslog = logf.Log.WithName("kernelchaos-resource") - -// +kubebuilder:webhook:path=/mutate-chaos-mesh-org-v1alpha1-kernelchaos,mutating=true,failurePolicy=fail,groups=chaos-mesh.org,resources=kernelchaos,verbs=create;update,versions=v1alpha1,name=mkernelchaos.kb.io - -var _ webhook.Defaulter = &KernelChaos{} - -// Default implements webhook.Defaulter so a webhook will be registered for the type -func (in *KernelChaos) Default() { - kernelchaoslog.Info("default", "name", in.Name) - - in.Spec.Selector.DefaultNamespace(in.GetNamespace()) -} - -// +kubebuilder:webhook:verbs=create;update,path=/validate-chaos-mesh-org-v1alpha1-kernelchaos,mutating=false,failurePolicy=fail,groups=chaos-mesh.org,resources=kernelchaos,versions=v1alpha1,name=vkernelchaos.kb.io - -var _ ChaosValidator = &KernelChaos{} - -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (in *KernelChaos) ValidateCreate() error { - kernelchaoslog.Info("validate create", "name", in.Name) - return in.Validate() -} - -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (in *KernelChaos) ValidateUpdate(old runtime.Object) error { - kernelchaoslog.Info("validate update", "name", in.Name) - return in.Validate() -} - -// ValidateDelete implements webhook.Validator so a webhook will be registered for the type -func (in *KernelChaos) ValidateDelete() error { - kernelchaoslog.Info("validate delete", "name", in.Name) - - // Nothing to do? - return nil -} - -// Validate validates chaos object -func (in *KernelChaos) Validate() error { - specField := field.NewPath("spec") - allErrs := in.ValidateScheduler(specField) - allErrs = append(allErrs, in.ValidatePodMode(specField)...) - - if len(allErrs) > 0 { - return fmt.Errorf(allErrs.ToAggregate().Error()) - } - return nil -} - -// ValidateScheduler validates the scheduler and duration -func (in *KernelChaos) ValidateScheduler(spec *field.Path) field.ErrorList { - return ValidateScheduler(in, spec) -} - -// ValidatePodMode validates the value with podmode -func (in *KernelChaos) ValidatePodMode(spec *field.Path) field.ErrorList { - return ValidatePodMode(in.Spec.Value, in.Spec.Mode, spec.Child("value")) -} - -// SelectSpec returns the selector config for authority validate -func (in *KernelChaos) GetSelectSpec() []SelectSpec { - return []SelectSpec{&in.Spec} -} diff --git a/api/v1alpha1/kernelchaos_webhook_test.go b/api/v1alpha1/kernelchaos_webhook_test.go index 285f364c61..32265cce3a 100644 --- a/api/v1alpha1/kernelchaos_webhook_test.go +++ b/api/v1alpha1/kernelchaos_webhook_test.go @@ -1,20 +1,22 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -29,7 +31,7 @@ var _ = Describe("kernelchaos_webhook", func() { Expect(kernelchaos.Spec.Selector.Namespaces[0]).To(Equal(metav1.NamespaceDefault)) }) }) - Context("ChaosValidator of kernelchaos", func() { + Context("webhook.Validator of kernelchaos", func() { It("Validate", func() { type TestCase struct { @@ -38,7 +40,6 @@ var _ = Describe("kernelchaos_webhook", func() { execute func(chaos *KernelChaos) error expect string } - duration := "400s" tcs := []TestCase{ { name: "simple ValidateCreate", @@ -49,7 +50,8 @@ var _ = Describe("kernelchaos_webhook", func() { }, }, execute: func(chaos *KernelChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err }, expect: "", }, @@ -62,7 +64,8 @@ var _ = Describe("kernelchaos_webhook", func() { }, }, execute: func(chaos *KernelChaos) error { - return chaos.ValidateUpdate(chaos) + _, err := chaos.ValidateUpdate(chaos) + return err }, expect: "", }, @@ -75,44 +78,11 @@ var _ = Describe("kernelchaos_webhook", func() { }, }, execute: func(chaos *KernelChaos) error { - return chaos.ValidateDelete() + _, err := chaos.ValidateDelete() + return err }, expect: "", }, - { - name: "only define the Scheduler", - chaos: KernelChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo4", - }, - Spec: KernelChaosSpec{ - Scheduler: &SchedulerSpec{ - Cron: "@every 10m", - }, - }, - }, - execute: func(chaos *KernelChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "only define the Duration", - chaos: KernelChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo5", - }, - Spec: KernelChaosSpec{ - Duration: &duration, - }, - }, - execute: func(chaos *KernelChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, } for _, tc := range tcs { diff --git a/api/v1alpha1/kinds.go b/api/v1alpha1/kinds.go index 276b5f0de0..4924849ae0 100644 --- a/api/v1alpha1/kinds.go +++ b/api/v1alpha1/kinds.go @@ -1,22 +1,24 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "sync" - "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" ) // +kubebuilder:object:generate=false @@ -33,6 +35,7 @@ func (c *chaosKindMap) register(name string, kind *ChaosKind) { c.kinds[name] = kind } +// clone will build a new map with kinds, so if user add or delete entries of the map, the origin global map will not be affected. func (c *chaosKindMap) clone() map[string]*ChaosKind { c.RLock() defer c.RUnlock() @@ -40,19 +43,35 @@ func (c *chaosKindMap) clone() map[string]*ChaosKind { out := make(map[string]*ChaosKind) for key, kind := range c.kinds { out[key] = &ChaosKind{ - Chaos: kind.Chaos, - ChaosList: kind.ChaosList, + chaos: kind.chaos, + list: kind.list, } } return out } -// AllKinds returns all chaos kinds. +// AllKinds returns all chaos kinds, key is name of Kind, value is an accessor for spawning Object and List func AllKinds() map[string]*ChaosKind { return all.clone() } +func AllKindsIncludeScheduleAndWorkflow() map[string]*ChaosKind { + all := chaosKindMap{ + kinds: all.clone(), + } + all.register(KindSchedule, &ChaosKind{ + chaos: &Schedule{}, + list: &ScheduleList{}, + }) + all.register(KindWorkflow, &ChaosKind{ + chaos: &Workflow{}, + list: &WorkflowList{}, + }) + + return all.kinds +} + // all is a ChaosKindMap instance. var all = &chaosKindMap{ kinds: make(map[string]*ChaosKind), @@ -62,6 +81,26 @@ var all = &chaosKindMap{ // ChaosKind includes one kind of chaos and its list type type ChaosKind struct { - Chaos runtime.Object - ChaosList + chaos client.Object + list GenericChaosList +} + +// SpawnObject will deepcopy a clean struct for the acquired kind as placeholder +func (it *ChaosKind) SpawnObject() client.Object { + return it.chaos.DeepCopyObject().(client.Object) +} + +// SpawnList will deepcopy a clean list for the acquired kind of chaos as placeholder +func (it *ChaosKind) SpawnList() GenericChaosList { + return it.list.DeepCopyList() +} + +// AllKinds returns all chaos kinds. +func AllScheduleItemKinds() map[string]*ChaosKind { + return allScheduleItem.clone() +} + +// allScheduleItem is a ChaosKindMap instance. +var allScheduleItem = &chaosKindMap{ + kinds: make(map[string]*ChaosKind), } diff --git a/api/v1alpha1/networkchaos_types.go b/api/v1alpha1/networkchaos_types.go index 857141a844..a0677e1474 100644 --- a/api/v1alpha1/networkchaos_types.go +++ b/api/v1alpha1/networkchaos_types.go @@ -1,15 +1,17 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 @@ -21,7 +23,9 @@ import ( // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. // +kubebuilder:object:root=true -// +chaos-mesh:base +// +kubebuilder:printcolumn:name="action",type=string,JSONPath=`.spec.action` +// +kubebuilder:printcolumn:name="duration",type=string,JSONPath=`.spec.duration` +// +chaos-mesh:experiment // NetworkChaos is the Schema for the networkchaos API type NetworkChaos struct { @@ -33,9 +37,13 @@ type NetworkChaos struct { // +optional // Most recently observed status of the chaos experiment about pods - Status NetworkChaosStatus `json:"status"` + Status NetworkChaosStatus `json:"status,omitempty"` } +var _ InnerObjectWithCustomStatus = (*NetworkChaos)(nil) +var _ InnerObjectWithSelector = (*NetworkChaos)(nil) +var _ InnerObject = (*NetworkChaos)(nil) + // NetworkChaosAction represents the chaos action about network. type NetworkChaosAction string @@ -79,134 +87,93 @@ const ( Both Direction = "both" ) -// Target represents network partition and netem action target. -type Target struct { - // TargetSelector defines the target selector - TargetSelector SelectorSpec `json:"selector" mapstructure:"selector"` - - // TargetMode defines the target selector mode - // +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent;"" - TargetMode PodMode `json:"mode" mapstructure:"mode"` - - // TargetValue is required when the mode is set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - // If `FixedPodMode`, provide an integer of pods to do chaos action. - // If `FixedPercentPodMod`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. - // If `RandomMaxPercentPodMod`, provide a number from 0-100 to specify the max percent of pods to do chaos action - // +optional - TargetValue string `json:"value" mapstructure:"value"` -} - -// GetSelector is a getter for Selector (for implementing SelectSpec) -func (in *Target) GetSelector() SelectorSpec { - return in.TargetSelector -} - -// GetMode is a getter for Mode (for implementing SelectSpec) -func (in *Target) GetMode() PodMode { - return in.TargetMode -} - -// GetValue is a getter for Value (for implementing SelectSpec) -func (in *Target) GetValue() string { - return in.TargetValue -} - // NetworkChaosSpec defines the desired state of NetworkChaos type NetworkChaosSpec struct { + PodSelector `json:",inline"` + // Action defines the specific network chaos action. // Supported action: partition, netem, delay, loss, duplicate, corrupt // Default action: delay // +kubebuilder:validation:Enum=netem;delay;loss;duplicate;corrupt;partition;bandwidth Action NetworkChaosAction `json:"action"` - // Mode defines the mode to run chaos action. - // Supported mode: one / all / fixed / fixed-percent / random-max-percent - // +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent - Mode PodMode `json:"mode"` - - // Value is required when the mode is set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - // If `FixedPodMode`, provide an integer of pods to do chaos action. - // If `FixedPercentPodMod`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. - // If `RandomMaxPercentPodMod`, provide a number from 0-100 to specify the max percent of pods to do chaos action + // Device represents the network device to be affected. // +optional - Value string `json:"value"` - - // Selector is used to select pods that are used to inject chaos action. - Selector SelectorSpec `json:"selector"` + Device string `json:"device,omitempty"` // Duration represents the duration of the chaos action - Duration *string `json:"duration,omitempty"` - - // Scheduler defines some schedule rules to control the running time of the chaos experiment about network. - Scheduler *SchedulerSpec `json:"scheduler,omitempty"` + Duration *string `json:"duration,omitempty" webhook:"Duration"` // TcParameter represents the traffic control definition TcParameter `json:",inline"` // Direction represents the direction, this applies on netem and network partition action // +optional - // +kubebuilder:validation:Enum=to;from;both;"" + // +kubebuilder:validation:Enum=to;from;both + // +kubebuilder:default=to Direction Direction `json:"direction,omitempty"` // Target represents network target, this applies on netem and network partition action // +optional - Target *Target `json:"target,omitempty"` + Target *PodSelector `json:"target,omitempty" webhook:",nilable"` + + // TargetDevice represents the network device to be affected in target scope. + // +optional + TargetDevice string `json:"targetDevice,omitempty"` // ExternalTargets represents network targets outside k8s // +optional ExternalTargets []string `json:"externalTargets,omitempty"` -} -// GetSelector is a getter for Selector (for implementing SelectSpec) -func (in *NetworkChaosSpec) GetSelector() SelectorSpec { - return in.Selector -} - -// GetMode is a getter for Mode (for implementing SelectSpec) -func (in *NetworkChaosSpec) GetMode() PodMode { - return in.Mode -} - -// GetValue is a getter for Value (for implementing SelectSpec) -func (in *NetworkChaosSpec) GetValue() string { - return in.Value + // RemoteCluster represents the remote cluster where the chaos will be deployed + // +optional + RemoteCluster string `json:"remoteCluster,omitempty"` } // NetworkChaosStatus defines the observed state of NetworkChaos type NetworkChaosStatus struct { ChaosStatus `json:",inline"` + // Instances always specifies podnetworkchaos generation or empty + // +optional + Instances map[string]int64 `json:"instances,omitempty"` } // DelaySpec defines detail of a delay action type DelaySpec struct { - Latency string `json:"latency"` - Correlation string `json:"correlation,omitempty"` - Jitter string `json:"jitter,omitempty"` - Reorder *ReorderSpec `json:"reorder,omitempty"` + Latency string `json:"latency" webhook:"Duration"` + // +optional + Correlation string `json:"correlation,omitempty" default:"0" webhook:"FloatStr"` + // +optional + Jitter string `json:"jitter,omitempty" default:"0ms" webhook:"Duration"` + // +optional + Reorder *ReorderSpec `json:"reorder,omitempty"` } // LossSpec defines detail of a loss action type LossSpec struct { - Loss string `json:"loss"` - Correlation string `json:"correlation"` + Loss string `json:"loss" webhook:"FloatStr"` + // +optional + Correlation string `json:"correlation,omitempty" default:"0" webhook:"FloatStr"` } // DuplicateSpec defines detail of a duplicate action type DuplicateSpec struct { - Duplicate string `json:"duplicate"` - Correlation string `json:"correlation"` + Duplicate string `json:"duplicate" webhook:"FloatStr"` + // +optional + Correlation string `json:"correlation,omitempty" default:"0" webhook:"FloatStr"` } // CorruptSpec defines detail of a corrupt action type CorruptSpec struct { - Corrupt string `json:"corrupt"` - Correlation string `json:"correlation"` + Corrupt string `json:"corrupt" webhook:"FloatStr"` + // +optional + Correlation string `json:"correlation,omitempty" default:"0" webhook:"FloatStr"` } // BandwidthSpec defines detail of bandwidth limit. type BandwidthSpec struct { - // Rate is the speed knob. Allows bps, kbps, mbps, gbps, tbps unit. bps means bytes per second. - Rate string `json:"rate"` + // Rate is the speed knob. Allows bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means bytes per second. + Rate string `json:"rate" webhook:"Rate"` // Limit is the number of bytes that can be queued waiting for tokens to become available. // +kubebuilder:validation:Minimum=1 Limit uint32 `json:"limit"` @@ -231,7 +198,28 @@ type BandwidthSpec struct { // ReorderSpec defines details of packet reorder. type ReorderSpec struct { - Reorder string `json:"reorder"` - Correlation string `json:"correlation"` + Reorder string `json:"reorder" webhook:"FloatStr"` + // +optional + Correlation string `json:"correlation,omitempty" default:"0" webhook:"FloatStr"` Gap int `json:"gap"` } + +// RateSpec defines details of rate limit. +type RateSpec struct { + // Rate is the speed knob. Allows bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means bytes per second. + Rate string `json:"rate" webhook:"Rate"` +} + +func (obj *NetworkChaos) GetSelectorSpecs() map[string]interface{} { + selectors := map[string]interface{}{ + ".": &obj.Spec.PodSelector, + } + if obj.Spec.Target != nil { + selectors[".Target"] = obj.Spec.Target + } + return selectors +} + +func (obj *NetworkChaos) GetCustomStatus() interface{} { + return &obj.Status.Instances +} diff --git a/api/v1alpha1/networkchaos_types_test.go b/api/v1alpha1/networkchaos_types_test.go index c68ecc13e5..a652067c9c 100644 --- a/api/v1alpha1/networkchaos_types_test.go +++ b/api/v1alpha1/networkchaos_types_test.go @@ -1,25 +1,25 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "context" - "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) @@ -54,7 +54,9 @@ var _ = Describe("NetworkChaos", func() { Namespace: "default", }, Spec: NetworkChaosSpec{ - Mode: OnePodMode, + PodSelector: PodSelector{ + Mode: OneMode, + }, Action: DelayAction, }, } @@ -70,19 +72,5 @@ var _ = Describe("NetworkChaos", func() { Expect(k8sClient.Delete(context.TODO(), created)).To(Succeed()) Expect(k8sClient.Get(context.TODO(), key, created)).ToNot(Succeed()) }) - - It("should set next start time successfully", func() { - nwChaos := &NetworkChaos{} - nTime := time.Now() - nwChaos.SetNextStart(nTime) - Expect(nwChaos.GetNextStart()).To(Equal(nTime)) - }) - - It("should set recover time successfully", func() { - nwChaos := &NetworkChaos{} - nTime := time.Now() - nwChaos.SetNextRecover(nTime) - Expect(nwChaos.GetNextRecover()).To(Equal(nTime)) - }) }) }) diff --git a/api/v1alpha1/networkchaos_webhook.go b/api/v1alpha1/networkchaos_webhook.go index af55719093..fdf0f6bd7f 100644 --- a/api/v1alpha1/networkchaos_webhook.go +++ b/api/v1alpha1/networkchaos_webhook.go @@ -1,29 +1,30 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - "errors" "fmt" + "reflect" "strconv" "strings" - "time" - "k8s.io/apimachinery/pkg/runtime" + "github.com/pkg/errors" "k8s.io/apimachinery/pkg/util/validation/field" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/webhook" + + "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" ) const ( @@ -34,305 +35,87 @@ const ( DefaultCorrelation = "0" ) -// log is for logging in this package. -var networkchaoslog = logf.Log.WithName("networkchaos-resource") - -// +kubebuilder:webhook:path=/mutate-chaos-mesh-org-v1alpha1-networkchaos,mutating=true,failurePolicy=fail,groups=chaos-mesh.org,resources=networkchaos,verbs=create;update,versions=v1alpha1,name=mnetworkchaos.kb.io - -var _ webhook.Defaulter = &NetworkChaos{} - -// Default implements webhook.Defaulter so a webhook will be registered for the type -func (in *NetworkChaos) Default() { - networkchaoslog.Info("default", "name", in.Name) - - in.Spec.Selector.DefaultNamespace(in.GetNamespace()) - // the target's namespace selector - if in.Spec.Target != nil { - in.Spec.Target.TargetSelector.DefaultNamespace(in.GetNamespace()) - } - - // set default direction - if in.Spec.Direction == "" { - in.Spec.Direction = To - } - - in.Spec.DefaultDelay() -} - -// DefaultDelay set the default value if Jitter or Correlation is not set -func (in *NetworkChaosSpec) DefaultDelay() { - if in.Delay != nil { - if in.Delay.Jitter == "" { - in.Delay.Jitter = DefaultJitter - } - if in.Delay.Correlation == "" { - in.Delay.Correlation = DefaultCorrelation - } - } -} - -// +kubebuilder:webhook:verbs=create;update,path=/validate-chaos-mesh-org-v1alpha1-networkchaos,mutating=false,failurePolicy=fail,groups=chaos-mesh.org,resources=networkchaos,versions=v1alpha1,name=vnetworkchaos.kb.io - -var _ ChaosValidator = &NetworkChaos{} - -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (in *NetworkChaos) ValidateCreate() error { - networkchaoslog.Info("validate create", "name", in.Name) - return in.Validate() -} - -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (in *NetworkChaos) ValidateUpdate(old runtime.Object) error { - networkchaoslog.Info("validate update", "name", in.Name) - return in.Validate() -} - -// ValidateDelete implements webhook.Validator so a webhook will be registered for the type -func (in *NetworkChaos) ValidateDelete() error { - networkchaoslog.Info("validate delete", "name", in.Name) - - // Nothing to do? - return nil -} - -// Validate validates chaos object -func (in *NetworkChaos) Validate() error { - specField := field.NewPath("spec") - allErrs := in.ValidateScheduler(specField) - allErrs = append(allErrs, in.ValidatePodMode(specField)...) - allErrs = append(allErrs, in.ValidateTargets(specField)...) - - if in.Spec.Delay != nil { - allErrs = append(allErrs, in.Spec.Delay.validateDelay(specField.Child("delay"))...) - } - if in.Spec.Loss != nil { - allErrs = append(allErrs, in.Spec.Loss.validateLoss(specField.Child("loss"))...) - } - if in.Spec.Duplicate != nil { - allErrs = append(allErrs, in.Spec.Duplicate.validateDuplicate(specField.Child("duplicate"))...) - } - if in.Spec.Corrupt != nil { - allErrs = append(allErrs, in.Spec.Corrupt.validateCorrupt(specField.Child("corrupt"))...) - } - if in.Spec.Bandwidth != nil { - allErrs = append(allErrs, in.Spec.Bandwidth.validateBandwidth(specField.Child("bandwidth"))...) - } - - if in.Spec.Target != nil { - allErrs = append(allErrs, in.Spec.Target.validateTarget(specField.Child("target"))...) - } - - if len(allErrs) > 0 { - return fmt.Errorf(allErrs.ToAggregate().Error()) +func (in *Direction) Default(root interface{}, field *reflect.StructField) { + if *in == "" { + *in = To } - return nil -} - -// ValidateScheduler validates the scheduler and duration -func (in *NetworkChaos) ValidateScheduler(spec *field.Path) field.ErrorList { - return ValidateScheduler(in, spec) -} - -// ValidatePodMode validates the value with podmode -func (in *NetworkChaos) ValidatePodMode(spec *field.Path) field.ErrorList { - return ValidatePodMode(in.Spec.Value, in.Spec.Mode, spec.Child("value")) } -// SelectSpec returns the selector config for authority validate -func (in *NetworkChaos) GetSelectSpec() []SelectSpec { - selectSpecs := []SelectSpec{&in.Spec} - // when direction is both or from, will need to update target Pods - if in.Spec.Direction != To { - selectSpecs = append(selectSpecs, in.Spec.Target) - } - return selectSpecs -} - -// ValidateTargets validates externalTargets and Targets -func (in *NetworkChaos) ValidateTargets(target *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - - if (in.Spec.Direction == From || in.Spec.Direction == Both) && - in.Spec.ExternalTargets != nil && in.Spec.Action != PartitionAction { - allErrs = append(allErrs, - field.Invalid(target.Child("direction"), in.Spec.Direction, - fmt.Sprintf("external targets cannot be used with `from` and `both` direction in netem action yet"))) - } - - if (in.Spec.Direction == From || in.Spec.Direction == Both) && in.Spec.Target == nil { - if in.Spec.Action != PartitionAction { - allErrs = append(allErrs, - field.Invalid(target.Child("direction"), in.Spec.Direction, - fmt.Sprintf("`from` and `both` direction cannot be used when targets is empty in netem action"))) - } else if in.Spec.ExternalTargets == nil { - allErrs = append(allErrs, - field.Invalid(target.Child("direction"), in.Spec.Direction, - fmt.Sprintf("`from` and `both` direction cannot be used when targets and external targets are both empty"))) - } +func (in *NetworkChaosSpec) Default(root interface{}, field *reflect.StructField) { + x := in.Device + if idx := strings.Index(x, "@"); idx != -1 { + in.Device = x[:idx] } - - // TODO: validate externalTargets are in ip or domain form - - return allErrs } -// validateDelay validates the delay -func (in *DelaySpec) validateDelay(delay *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - _, err := time.ParseDuration(in.Latency) - if err != nil { - allErrs = append(allErrs, - field.Invalid(delay.Child("latency"), in.Latency, - fmt.Sprintf("parse latency field error:%s", err))) - } - _, err = time.ParseDuration(in.Jitter) - if err != nil { - allErrs = append(allErrs, - field.Invalid(delay.Child("jitter"), in.Jitter, - fmt.Sprintf("parse jitter field error:%s", err))) - } - - _, err = strconv.ParseFloat(in.Correlation, 32) - if err != nil { - allErrs = append(allErrs, - field.Invalid(delay.Child("correlation"), in.Correlation, - fmt.Sprintf("parse correlation field error:%s", err))) - } - - if in.Reorder != nil { - allErrs = append(allErrs, in.Reorder.validateReorder(delay.Child("reorder"))...) - } - return allErrs -} +type Rate string -// validateReorder validates the reorder -func (in *ReorderSpec) validateReorder(reorder *field.Path) field.ErrorList { +// validateBandwidth validates the bandwidth +func (in *Rate) Validate(root interface{}, path *field.Path) field.ErrorList { allErrs := field.ErrorList{} - _, err := strconv.ParseFloat(in.Reorder, 32) - if err != nil { - allErrs = append(allErrs, - field.Invalid(reorder.Child("reorder"), in.Reorder, - fmt.Sprintf("parse reorder field error:%s", err))) - } + // in cannot be nil + _, err := isValidRateUnit(string(*in)) - _, err = strconv.ParseFloat(in.Correlation, 32) if err != nil { allErrs = append(allErrs, - field.Invalid(reorder.Child("correlation"), in.Correlation, - fmt.Sprintf("parse correlation field error:%s", err))) + field.Invalid(path, in, + fmt.Sprintf("parse rate field error:%s", err))) } return allErrs } -// validateLoss validates the loss -func (in *LossSpec) validateLoss(loss *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - - _, err := strconv.ParseFloat(in.Loss, 32) - if err != nil { - allErrs = append(allErrs, - field.Invalid(loss.Child("loss"), in.Loss, - fmt.Sprintf("parse loss field error:%s", err))) - } +func isValidRateUnit(nu string) (bool, error) { + // normalize input + s := strings.ToLower(strings.TrimSpace(nu)) - _, err = strconv.ParseFloat(in.Correlation, 32) - if err != nil { - allErrs = append(allErrs, - field.Invalid(loss.Child("correlation"), in.Correlation, - fmt.Sprintf("parse correlation field error:%s", err))) - } + for _, u := range []string{"kbit", "mbit", "gbit", "tbit", "tbps", "gbps", "mbps", "kbps", "bps", "bit"} { + if strings.HasSuffix(s, u) { + ts := strings.TrimSuffix(s, u) + s := strings.TrimSpace(ts) - return allErrs -} + _, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return false, err + } -// validateDuplicate validates the duplicate -func (in *DuplicateSpec) validateDuplicate(duplicate *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - _, err := strconv.ParseFloat(in.Duplicate, 32) - if err != nil { - allErrs = append(allErrs, - field.Invalid(duplicate.Child("duplicate"), in.Duplicate, - fmt.Sprintf("parse duplicate field error:%s", err))) + return true, nil + } } - _, err = strconv.ParseFloat(in.Correlation, 32) - if err != nil { - allErrs = append(allErrs, - field.Invalid(duplicate.Child("correlation"), in.Correlation, - fmt.Sprintf("parse correlation field error:%s", err))) - } - return allErrs + return false, errors.New("invalid unit") } -// validateCorrupt validates the corrupt -func (in *CorruptSpec) validateCorrupt(corrupt *field.Path) field.ErrorList { +// ValidateTargets validates externalTargets and Targets +func (in *NetworkChaosSpec) Validate(root interface{}, path *field.Path) field.ErrorList { allErrs := field.ErrorList{} - _, err := strconv.ParseFloat(in.Corrupt, 32) - if err != nil { - allErrs = append(allErrs, - field.Invalid(corrupt.Child("corrupt"), in.Corrupt, - fmt.Sprintf("parse corrupt field error:%s", err))) - } - _, err = strconv.ParseFloat(in.Correlation, 32) - if err != nil { - allErrs = append(allErrs, - field.Invalid(corrupt.Child("correlation"), in.Correlation, - fmt.Sprintf("parse correlation field error:%s", err))) + if in.Action == PartitionAction { + return nil } - return allErrs -} - -// validateBandwidth validates the bandwidth -func (in *BandwidthSpec) validateBandwidth(bandwidth *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - _, err := ConvertUnitToBytes(in.Rate) - if err != nil { + if (in.Direction == From || in.Direction == Both) && + in.ExternalTargets != nil && in.Action != PartitionAction { allErrs = append(allErrs, - field.Invalid(bandwidth.Child("rate"), in.Rate, - fmt.Sprintf("parse rate field error:%s", err))) + field.Invalid(path.Child("direction"), in.Direction, + "external targets cannot be used with `from` and `both` direction in netem action yet")) } - return allErrs -} -// validateTarget validates the target -func (in *Target) validateTarget(target *field.Path) field.ErrorList { - modes := []PodMode{OnePodMode, AllPodMode, FixedPodMode, FixedPercentPodMode, RandomMaxPercentPodMode} - - for _, mode := range modes { - if in.TargetMode == mode { - return ValidatePodMode(in.TargetValue, in.TargetMode, target.Child("value")) + if (in.Direction == From || in.Direction == Both) && in.Target == nil { + if in.Action != PartitionAction { + allErrs = append(allErrs, + field.Invalid(path.Child("direction"), in.Direction, + "`from` and `both` direction cannot be used when targets is empty in netem action")) + } else if in.ExternalTargets == nil { + allErrs = append(allErrs, + field.Invalid(path.Child("direction"), in.Direction, + "`from` and `both` direction cannot be used when targets and external targets are both empty")) } } - return field.ErrorList{field.Invalid(target.Child("mode"), in.TargetMode, - fmt.Sprintf("mode %s not supported", in.TargetMode))} + // TODO: validate externalTargets are in ip or domain form + return allErrs } -func ConvertUnitToBytes(nu string) (uint64, error) { - // normalize input - s := strings.ToLower(strings.TrimSpace(nu)) - - for i, u := range []string{"tbps", "gbps", "mbps", "kbps", "bps"} { - if strings.HasSuffix(s, u) { - ts := strings.TrimSuffix(s, u) - s := strings.TrimSpace(ts) - - n, err := strconv.ParseUint(s, 10, 64) - - if err != nil { - return 0, err - } - - // convert unit to bytes - for j := 4 - i; j > 0; j-- { - n = n * 1024 - } - - return n, nil - } - } - - return 0, errors.New("invalid unit") +func init() { + genericwebhook.Register("Rate", reflect.PtrTo(reflect.TypeOf(Rate("")))) } diff --git a/api/v1alpha1/networkchaos_webhook_test.go b/api/v1alpha1/networkchaos_webhook_test.go index e0cee35dbc..5d168a7bcc 100644 --- a/api/v1alpha1/networkchaos_webhook_test.go +++ b/api/v1alpha1/networkchaos_webhook_test.go @@ -1,20 +1,22 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -41,11 +43,11 @@ var _ = Describe("networkchaos_webhook", func() { }, } networkchaos.Default() - Expect(networkchaos.Spec.Delay.Correlation).To(Equal(DefaultCorrelation)) - Expect(networkchaos.Spec.Delay.Jitter).To(Equal(DefaultJitter)) + Expect(string(networkchaos.Spec.Delay.Correlation)).To(Equal(DefaultCorrelation)) + Expect(string(networkchaos.Spec.Delay.Jitter)).To(Equal(DefaultJitter)) }) }) - Context("ChaosValidator of networkchaos", func() { + Context("webhook.Validator of networkchaos", func() { It("Validate", func() { type TestCase struct { @@ -54,7 +56,6 @@ var _ = Describe("networkchaos_webhook", func() { execute func(chaos *NetworkChaos) error expect string } - duration := "400s" tcs := []TestCase{ { name: "simple ValidateCreate", @@ -65,7 +66,8 @@ var _ = Describe("networkchaos_webhook", func() { }, }, execute: func(chaos *NetworkChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err }, expect: "", }, @@ -78,7 +80,8 @@ var _ = Describe("networkchaos_webhook", func() { }, }, execute: func(chaos *NetworkChaos) error { - return chaos.ValidateUpdate(chaos) + _, err := chaos.ValidateUpdate(chaos) + return err }, expect: "", }, @@ -91,44 +94,11 @@ var _ = Describe("networkchaos_webhook", func() { }, }, execute: func(chaos *NetworkChaos) error { - return chaos.ValidateDelete() + _, err := chaos.ValidateDelete() + return err }, expect: "", }, - { - name: "only define the Scheduler", - chaos: NetworkChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo4", - }, - Spec: NetworkChaosSpec{ - Scheduler: &SchedulerSpec{ - Cron: "@every 10m", - }, - }, - }, - execute: func(chaos *NetworkChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "only define the Duration", - chaos: NetworkChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo5", - }, - Spec: NetworkChaosSpec{ - Duration: &duration, - }, - }, - execute: func(chaos *NetworkChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, { name: "validate the delay", chaos: NetworkChaos{ @@ -147,7 +117,8 @@ var _ = Describe("networkchaos_webhook", func() { }, }, execute: func(chaos *NetworkChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, @@ -170,7 +141,8 @@ var _ = Describe("networkchaos_webhook", func() { }, }, execute: func(chaos *NetworkChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, @@ -191,7 +163,8 @@ var _ = Describe("networkchaos_webhook", func() { }, }, execute: func(chaos *NetworkChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, @@ -212,7 +185,8 @@ var _ = Describe("networkchaos_webhook", func() { }, }, execute: func(chaos *NetworkChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, @@ -233,7 +207,8 @@ var _ = Describe("networkchaos_webhook", func() { }, }, execute: func(chaos *NetworkChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, @@ -253,7 +228,29 @@ var _ = Describe("networkchaos_webhook", func() { }, }, execute: func(chaos *NetworkChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validate the rate", + chaos: NetworkChaos{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo11", + }, + Spec: NetworkChaosSpec{ + TcParameter: TcParameter{ + Rate: &RateSpec{ + Rate: "10", + }, + }, + }, + }, + execute: func(chaos *NetworkChaos) error { + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, @@ -265,14 +262,15 @@ var _ = Describe("networkchaos_webhook", func() { Name: "foo12", }, Spec: NetworkChaosSpec{ - Target: &Target{ - TargetMode: FixedPodMode, - TargetValue: "0", + Target: &PodSelector{ + Mode: FixedMode, + Value: "0", }, }, }, execute: func(chaos *NetworkChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, @@ -289,7 +287,8 @@ var _ = Describe("networkchaos_webhook", func() { }, }, execute: func(chaos *NetworkChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, @@ -305,17 +304,23 @@ var _ = Describe("networkchaos_webhook", func() { } }) }) - Context("convertUnitToBytes", func() { - It("should convert number with unit successfully", func() { - n, err := ConvertUnitToBytes(" 10 mbPs ") + Context("isValidRateUnit", func() { + It("mbps unit, should convert number with unit successfully", func() { + isValid, err := isValidRateUnit(" 10 mbPs ") + Expect(err).Should(Succeed()) + Expect(isValid).To(Equal(true)) + }) + + It("kbit unit, should convert number with unit successfully", func() { + isValid, err := isValidRateUnit(" 10 kbit ") Expect(err).Should(Succeed()) - Expect(n).To(Equal(uint64(10 * 1024 * 1024))) + Expect(isValid).To(Equal(true)) }) It("should return error with invalid unit", func() { - n, err := ConvertUnitToBytes(" 10 cpbs") + isValid, err := isValidRateUnit(" 10 cpbs") Expect(err).Should(HaveOccurred()) - Expect(n).To(Equal(uint64(0))) + Expect(isValid).To(Equal(false)) }) }) }) diff --git a/api/v1alpha1/physical_machine_chaos_types.go b/api/v1alpha1/physical_machine_chaos_types.go new file mode 100644 index 0000000000..8be1618eeb --- /dev/null +++ b/api/v1alpha1/physical_machine_chaos_types.go @@ -0,0 +1,772 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// PhysicalMachineChaosAction represents the chaos action about physical machine. +type PhysicalMachineChaosAction string + +var ( + PMStressCPUAction PhysicalMachineChaosAction = "stress-cpu" + PMStressMemAction PhysicalMachineChaosAction = "stress-mem" + PMDiskWritePayloadAction PhysicalMachineChaosAction = "disk-write-payload" + PMDiskReadPayloadAction PhysicalMachineChaosAction = "disk-read-payload" + PMDiskFillAction PhysicalMachineChaosAction = "disk-fill" + PMNetworkCorruptAction PhysicalMachineChaosAction = "network-corrupt" + PMNetworkDuplicateAction PhysicalMachineChaosAction = "network-duplicate" + PMNetworkLossAction PhysicalMachineChaosAction = "network-loss" + PMNetworkDelayAction PhysicalMachineChaosAction = "network-delay" + PMNetworkPartitionAction PhysicalMachineChaosAction = "network-partition" + PMNetworkBandwidthAction PhysicalMachineChaosAction = "network-bandwidth" + PMNetworkDNSAction PhysicalMachineChaosAction = "network-dns" + PMNetworkFloodAction PhysicalMachineChaosAction = "network-flood" + PMNetworkDownAction PhysicalMachineChaosAction = "network-down" + PMProcessAction PhysicalMachineChaosAction = "process" + PMJVMExceptionAction PhysicalMachineChaosAction = "jvm-exception" + PMJVMGCAction PhysicalMachineChaosAction = "jvm-gc" + PMJVMLatencyAction PhysicalMachineChaosAction = "jvm-latency" + PMJVMReturnAction PhysicalMachineChaosAction = "jvm-return" + PMJVMStressAction PhysicalMachineChaosAction = "jvm-stress" + PMJVMRuleDataAction PhysicalMachineChaosAction = "jvm-rule-data" + PMJVMMySQLAction PhysicalMachineChaosAction = "jvm-mysql" + PMClockAction PhysicalMachineChaosAction = "clock" + PMRedisExpirationAction PhysicalMachineChaosAction = "redis-expiration" + PMRedisPenetrationAction PhysicalMachineChaosAction = "redis-penetration" + PMRedisCacheLimitAction PhysicalMachineChaosAction = "redis-cacheLimit" + PMRedisSentinelRestartAction PhysicalMachineChaosAction = "redis-restart" + PMRedisSentinelStopAction PhysicalMachineChaosAction = "redis-stop" + PMKafkaFillAction PhysicalMachineChaosAction = "kafka-fill" + PMKafkaFloodAction PhysicalMachineChaosAction = "kafka-flood" + PMKafkaIOAction PhysicalMachineChaosAction = "kafka-io" + PMHTTPAbortAction PhysicalMachineChaosAction = "http-abort" + PMHTTPDelayAction PhysicalMachineChaosAction = "http-delay" + PMHTTPConfigAction PhysicalMachineChaosAction = "http-config" + PMHTTPRequestAction PhysicalMachineChaosAction = "http-request" + PMFileCreateAction PhysicalMachineChaosAction = "file-create" + PMFileModifyPrivilegeAction PhysicalMachineChaosAction = "file-modify" + PMFileDeleteAction PhysicalMachineChaosAction = "file-delete" + PMFileRenameAction PhysicalMachineChaosAction = "file-rename" + PMFileAppendAction PhysicalMachineChaosAction = "file-append" + PMFileReplaceAction PhysicalMachineChaosAction = "file-replace" + PMVMAction PhysicalMachineChaosAction = "vm" + PMUserDefinedAction PhysicalMachineChaosAction = "user_defined" +) + +// +kubebuilder:object:root=true +// +kubebuilder:printcolumn:name="action",type=string,JSONPath=`.spec.action` +// +kubebuilder:printcolumn:name="duration",type=string,JSONPath=`.spec.duration` +// +chaos-mesh:experiment + +// PhysicalMachineChaos is the Schema for the physical machine chaos API +type PhysicalMachineChaos struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the behavior of a physical machine chaos experiment + Spec PhysicalMachineChaosSpec `json:"spec"` + + // +optional + // Most recently observed status of the chaos experiment + Status PhysicalMachineChaosStatus `json:"status,omitempty"` +} + +// PhysicalMachineChaosSpec defines the desired state of PhysicalMachineChaos +type PhysicalMachineChaosSpec struct { + // +kubebuilder:validation:Enum=stress-cpu;stress-mem;disk-read-payload;disk-write-payload;disk-fill;network-corrupt;network-duplicate;network-loss;network-delay;network-partition;network-dns;network-bandwidth;network-flood;network-down;process;jvm-exception;jvm-gc;jvm-latency;jvm-return;jvm-stress;jvm-rule-data;jvm-mysql;clock;redis-expiration;redis-penetration;redis-cacheLimit;redis-restart;redis-stop;kafka-fill;kafka-flood;kafka-io;file-create;file-modify;file-delete;file-rename;file-append;file-replace;vm;user_defined + Action PhysicalMachineChaosAction `json:"action"` + + PhysicalMachineSelector `json:",inline"` + + // ExpInfo string `json:"expInfo"` + ExpInfo `json:",inline"` + + // Duration represents the duration of the chaos action + // +optional + Duration *string `json:"duration,omitempty" webhook:"Duration"` + + // RemoteCluster represents the remote cluster where the chaos will be deployed + // +optional + RemoteCluster string `json:"remoteCluster,omitempty"` +} + +// PhysicalMachineChaosStatus defines the observed state of PhysicalMachineChaos +type PhysicalMachineChaosStatus struct { + ChaosStatus `json:",inline"` +} + +func (obj *PhysicalMachineChaos) GetSelectorSpecs() map[string]interface{} { + return map[string]interface{}{ + ".": &obj.Spec.PhysicalMachineSelector, + } +} + +type PhysicalMachineSelector struct { + // DEPRECATED: Use Selector instead. + // Only one of Address and Selector could be specified. + // +optional + Address []string `json:"address,omitempty"` + + // Selector is used to select physical machines that are used to inject chaos action. + // +optional + Selector PhysicalMachineSelectorSpec `json:"selector,omitempty"` + + // Mode defines the mode to run chaos action. + // Supported mode: one / all / fixed / fixed-percent / random-max-percent + // +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent + Mode SelectorMode `json:"mode"` + + // Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + // If `FixedMode`, provide an integer of physical machines to do chaos action. + // If `FixedPercentMode`, provide a number from 0-100 to specify the percent of physical machines the server can do chaos action. + // IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action + // +optional + Value string `json:"value,omitempty"` +} + +// PhysicalMachineSelectorSpec defines some selectors to select objects. +// If the all selectors are empty, all objects will be used in chaos experiment. +type PhysicalMachineSelectorSpec struct { + GenericSelectorSpec `json:",inline"` + + // PhysicalMachines is a map of string keys and a set values that used to select physical machines. + // The key defines the namespace which physical machine belong, + // and each value is a set of physical machine names. + // +optional + PhysicalMachines map[string][]string `json:"physicalMachines,omitempty"` +} + +func (spec *PhysicalMachineSelectorSpec) Empty() bool { + if spec == nil { + return true + } + if len(spec.AnnotationSelectors) != 0 || len(spec.FieldSelectors) != 0 || len(spec.LabelSelectors) != 0 || + len(spec.Namespaces) != 0 || len(spec.PhysicalMachines) != 0 || len(spec.ExpressionSelectors) != 0 { + return false + } + return true +} + +type ExpInfo struct { + // the experiment ID + // +optional + UID string `json:"uid,omitempty" swaggerignore:"true"` + + // the subAction, generate automatically + // +optional + Action string `json:"action,omitempty" swaggerignore:"true"` + + // +ui:form:when=action=='stress-cpu' + // +optional + StressCPU *StressCPUSpec `json:"stress-cpu,omitempty"` + + // +ui:form:when=action=='stress-mem' + // +optional + StressMemory *StressMemorySpec `json:"stress-mem,omitempty"` + + // +ui:form:when=action=='disk-read-payload' + // +optional + DiskReadPayload *DiskPayloadSpec `json:"disk-read-payload,omitempty"` + + // +ui:form:when=action=='disk-write-payload' + // +optional + DiskWritePayload *DiskPayloadSpec `json:"disk-write-payload,omitempty"` + + // +ui:form:when=action=='disk-fill' + // +optional + DiskFill *DiskFillSpec `json:"disk-fill,omitempty"` + + // +ui:form:when=action=='network-corrupt' + // +optional + NetworkCorrupt *NetworkCorruptSpec `json:"network-corrupt,omitempty"` + + // +ui:form:when=action=='network-duplicate' + // +optional + NetworkDuplicate *NetworkDuplicateSpec `json:"network-duplicate,omitempty"` + + // +ui:form:when=action=='network-loss' + // +optional + NetworkLoss *NetworkLossSpec `json:"network-loss,omitempty"` + + // +ui:form:when=action=='network-delay' + // +optional + NetworkDelay *NetworkDelaySpec `json:"network-delay,omitempty"` + + // +ui:form:when=action=='network-partition' + // +optional + NetworkPartition *NetworkPartitionSpec `json:"network-partition,omitempty"` + + // +ui:form:when=action=='network-dns' + // +optional + NetworkDNS *NetworkDNSSpec `json:"network-dns,omitempty"` + + // +ui:form:when=action=='network-bandwidth' + // +optional + NetworkBandwidth *NetworkBandwidthSpec `json:"network-bandwidth,omitempty"` + + // +ui:form:when=action=='network-flood' + // +optional + NetworkFlood *NetworkFloodSpec `json:"network-flood,omitempty"` + + // +ui:form:when=action=='network-down' + // +optional + NetworkDown *NetworkDownSpec `json:"network-down,omitempty"` + + // +ui:form:when=action=='process' + // +optional + Process *ProcessSpec `json:"process,omitempty"` + + // +ui:form:when=action=='jvm-exception' + // +optional + JVMException *JVMExceptionSpec `json:"jvm-exception,omitempty"` + + // +ui:form:when=action=='jvm-gc' + // +optional + JVMGC *JVMGCSpec `json:"jvm-gc,omitempty"` + + // +ui:form:when=action=='jvm-latency' + // +optional + JVMLatency *JVMLatencySpec `json:"jvm-latency,omitempty"` + + // +ui:form:when=action=='jvm-return' + // +optional + JVMReturn *JVMReturnSpec `json:"jvm-return,omitempty"` + + // +ui:form:when=action=='jvm-stress' + // +optional + JVMStress *JVMStressSpec `json:"jvm-stress,omitempty"` + + // +ui:form:when=action=='jvm-rule-data' + // +optional + JVMRuleData *JVMRuleDataSpec `json:"jvm-rule-data,omitempty"` + + // +ui:form:when=action=='jvm-mysql' + // +optional + JVMMySQL *PMJVMMySQLSpec `json:"jvm-mysql,omitempty"` + + // +ui:form:when=action=='clock' + // +optional + Clock *ClockSpec `json:"clock,omitempty"` + + // +ui:form:when=action=='redis-expiration' + // +optional + RedisExpiration *RedisExpirationSpec `json:"redis-expiration,omitempty"` + + // +ui:form:when=action=='redis-penetration' + // +optional + RedisPenetration *RedisPenetrationSpec `json:"redis-penetration,omitempty"` + + // +ui:form:when=action=='redis-cacheLimit' + // +optional + RedisCacheLimit *RedisCacheLimitSpec `json:"redis-cacheLimit,omitempty"` + + // +ui:form:when=action=='redis-restart' + // +optional + RedisSentinelRestart *RedisSentinelRestartSpec `json:"redis-restart,omitempty"` + + // +ui:form:when=action=='redis-stop' + // +optional + RedisSentinelStop *RedisSentinelStopSpec `json:"redis-stop,omitempty"` + + // +ui:form:when=action=='kafka-fill' + // +optional + KafkaFill *KafkaFillSpec `json:"kafka-fill,omitempty"` + + // +ui:form:when=action=='kafka-flood' + // +optional + KafkaFlood *KafkaFloodSpec `json:"kafka-flood,omitempty"` + + // +ui:form:when=action=='kafka-io' + // +optional + KafkaIO *KafkaIOSpec `json:"kafka-io,omitempty"` + + // +ui:form:when=action=='http-abort' + // +optional + HTTPAbort *HTTPAbortSpec `json:"http-abort,omitempty"` + + // +ui:form:when=action=='http-delay' + // +optional + HTTPDelay *HTTPDelaySpec `json:"http-delay,omitempty"` + + // +ui:form:when=action=='http-config' + // +optional + HTTPConfig *HTTPConfigSpec `json:"http-config,omitempty"` + + // +ui:form:when=action=='http-request' + // +optional + HTTPRequest *HTTPRequestSpec `json:"http-request,omitempty"` + + // +ui:form:when=action=='file-create' + // +optional + FileCreate *FileCreateSpec `json:"file-create,omitempty"` + + // +ui:form:when=action=='file-modify' + // +optional + FileModifyPrivilege *FileModifyPrivilegeSpec `json:"file-modify,omitempty"` + + // +ui:form:when=action=='file-delete' + // +optional + FileDelete *FileDeleteSpec `json:"file-delete,omitempty"` + + // +ui:form:when=action=='file-create' + // +optional + FileRename *FileRenameSpec `json:"file-rename,omitempty"` + + // +ui:form:when=action=='file-append' + // +optional + FileAppend *FileAppendSpec `json:"file-append,omitempty"` + + // +ui:form:when=action=='file-replace' + // +optional + FileReplace *FileReplaceSpec `json:"file-replace,omitempty"` + + // +ui:form:when=action=='vm' + // +optional + VM *VMSpec `json:"vm,omitempty"` + + // +ui:form:when=action=='user_defined' + // +optional + UserDefined *UserDefinedSpec `json:"user_defined,omitempty"` +} + +type StressCPUSpec struct { + // specifies P percent loading per CPU worker. 0 is effectively a sleep (no load) and 100 is full loading. + Load int `json:"load,omitempty"` + // specifies N workers to apply the stressor. + Workers int `json:"workers,omitempty"` + // extend stress-ng options + Options []string `json:"options,omitempty"` +} + +type StressMemorySpec struct { + // specifies N bytes consumed per vm worker, default is the total available memory. + // One can specify the size as % of total available memory or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + Size string `json:"size,omitempty"` + // extend stress-ng options + Options []string `json:"options,omitempty"` +} + +type DiskFileSpec struct { + // specifies how many units of data will write into the file path. support unit: c=1, w=2, b=512, kB=1000, + // K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 BYTES. example : 1M | 512kB + Size string `json:"size,omitempty"` + // specifies the location to fill data in. if path not provided, + // payload will read/write from/into a temp file, temp file will be deleted after writing + Path string `json:"path,omitempty"` +} + +type DiskPayloadSpec struct { + DiskFileSpec `json:",inline"` + + // specifies the number of process work on writing, default 1, only 1-255 is valid value + PayloadProcessNum uint8 `json:"payload-process-num,omitempty"` +} + +type DiskFillSpec struct { + DiskFileSpec `json:",inline"` + + // fill disk by fallocate + FillByFallocate bool `json:"fill-by-fallocate,omitempty"` +} + +type NetworkCommonSpec struct { + // correlation is percentage (10 is 10%) + Correlation string `json:"correlation,omitempty"` + // the network interface to impact + Device string `json:"device,omitempty"` + // only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. + // it can only be used in conjunction with -p tcp or -p udp + SourcePort string `json:"source-port,omitempty"` + // only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. + // it can only be used in conjunction with -p tcp or -p udp + EgressPort string `json:"egress-port,omitempty"` + // only impact egress traffic to these IP addresses + IPAddress string `json:"ip-address,omitempty"` + // only impact traffic using this IP protocol, supported: tcp, udp, icmp, all + IPProtocol string `json:"ip-protocol,omitempty"` + // only impact traffic to these hostnames + Hostname string `json:"hostname,omitempty"` +} + +type NetworkCorruptSpec struct { + NetworkCommonSpec `json:",inline"` + + // percentage of packets to corrupt (10 is 10%) + Percent string `json:"percent,omitempty"` +} + +type NetworkDuplicateSpec struct { + NetworkCommonSpec `json:",inline"` + + // percentage of packets to duplicate (10 is 10%) + Percent string `json:"percent,omitempty"` +} + +type NetworkLossSpec struct { + NetworkCommonSpec `json:",inline"` + + // percentage of packets to loss (10 is 10%) + Percent string `json:"percent,omitempty"` +} + +type NetworkDelaySpec struct { + NetworkCommonSpec `json:",inline"` + + // jitter time, time units: ns, us (or µs), ms, s, m, h. + Jitter string `json:"jitter,omitempty"` + // delay egress time, time units: ns, us (or µs), ms, s, m, h. + Latency string `json:"latency,omitempty"` + // only the packet which match the tcp flag can be accepted, others will be dropped. + // only set when the IPProtocol is tcp, used for partition. + AcceptTCPFlags string `json:"accept-tcp-flags,omitempty"` +} + +type NetworkPartitionSpec struct { + // the network interface to impact + Device string `json:"device,omitempty"` + // only impact traffic to these hostnames + Hostname string `json:"hostname,omitempty"` + // only impact egress traffic to these IP addresses + IPAddress string `json:"ip-address,omitempty"` + // specifies the partition direction, values can be 'from', 'to'. + // 'from' means packets coming from the 'IPAddress' or 'Hostname' and going to your server, + // 'to' means packets originating from your server and going to the 'IPAddress' or 'Hostname'. + Direction string `json:"direction,omitempty"` + // only impact egress traffic to these IP addresses + IPProtocol string `json:"ip-protocol,omitempty"` + // only the packet which match the tcp flag can be accepted, others will be dropped. + // only set when the IPProtocol is tcp, used for partition. + AcceptTCPFlags string `json:"accept-tcp-flags,omitempty"` +} + +type NetworkDNSSpec struct { + // update the DNS server in /etc/resolv.conf with this value + DNSServer string `json:"dns-server,omitempty"` + // map specified host to this IP address + DNSIp string `json:"dns-ip,omitempty"` + // map this host to specified IP + DNSDomainName string `json:"dns-domain-name,omitempty"` +} + +type NetworkBandwidthSpec struct { + Rate string `json:"rate"` + // +kubebuilder:validation:Minimum=1 + Limit uint32 `json:"limit"` + // +kubebuilder:validation:Minimum=1 + Buffer uint32 `json:"buffer"` + + Peakrate *uint64 `json:"peakrate,omitempty"` + Minburst *uint32 `json:"minburst,omitempty"` + + Device string `json:"device,omitempty"` + IPAddress string `json:"ip-address,omitempty"` + Hostname string `json:"hostname,omitempty"` +} + +type NetworkFloodSpec struct { + // The speed of network traffic, allows bps, kbps, mbps, gbps, tbps unit. bps means bytes per second + Rate string `json:"rate"` + // Generate traffic to this IP address + IPAddress string `json:"ip-address,omitempty"` + // Generate traffic to this port on the IP address + Port string `json:"port,omitempty"` + // The number of iperf parallel client threads to run + Parallel int32 `json:"parallel,omitempty"` + // The number of seconds to run the iperf test + Duration string `json:"duration"` +} + +type NetworkDownSpec struct { + // The network interface to impact + Device string `json:"device,omitempty"` + // NIC down time, time units: ns, us (or µs), ms, s, m, h. + Duration string `json:"duration,omitempty"` +} + +type ProcessSpec struct { + // the process name or the process ID + Process string `json:"process,omitempty"` + // the signal number to send + Signal int `json:"signal,omitempty"` + + // the command to be run when recovering experiment + RecoverCmd string `json:"recoverCmd,omitempty"` +} + +type JVMExceptionSpec struct { + JVMCommonSpec `json:",inline"` + JVMClassMethodSpec `json:",inline"` + + // the exception which needs to throw for action `exception` + ThrowException string `json:"exception,omitempty"` +} + +type JVMStressSpec struct { + JVMCommonSpec `json:",inline"` + + // the CPU core number need to use, only set it when action is stress + CPUCount int `json:"cpu-count,omitempty"` + + // the memory type need to locate, only set it when action is stress, the value can be 'stack' or 'heap' + MemoryType string `json:"mem-type,omitempty"` +} + +type JVMGCSpec struct { + JVMCommonSpec `json:",inline"` +} + +type JVMLatencySpec struct { + JVMCommonSpec `json:",inline"` + JVMClassMethodSpec `json:",inline"` + + // the latency duration for action 'latency', unit ms + LatencyDuration int `json:"latency,omitempty"` +} + +type JVMReturnSpec struct { + JVMCommonSpec `json:",inline"` + JVMClassMethodSpec `json:",inline"` + + // the return value for action 'return' + ReturnValue string `json:"value,omitempty"` +} + +type JVMRuleDataSpec struct { + JVMCommonSpec `json:",inline"` + + // RuleData used to save the rule file's data, will use it when recover + RuleData string `json:"rule-data,omitempty"` +} + +type PMJVMMySQLSpec struct { + JVMCommonSpec `json:",inline"` + + JVMMySQLSpec `json:",inline"` + + // The exception which needs to throw for action `exception` + // or the exception message needs to throw in action `mysql` + ThrowException string `json:"exception,omitempty"` + + // The latency duration for action 'latency' + // or the latency duration in action `mysql` + LatencyDuration int `json:"latency,omitempty"` +} + +type ClockSpec struct { + // the pid of target program. + Pid int `json:"pid,omitempty"` + // specifies the length of time offset. + TimeOffset string `json:"time-offset,omitempty"` + // the identifier of the particular clock on which to act. + // More clock description in linux kernel can be found in man page of clock_getres, clock_gettime, clock_settime. + // Muti clock ids should be split with "," + ClockIdsSlice string `json:"clock-ids-slice,omitempty"` +} + +type RedisCommonSpec struct { + // The adress of Redis server + Addr string `json:"addr,omitempty"` + // The password of Redis server + Password string `json:"password,omitempty"` +} + +type RedisExpirationSpec struct { + RedisCommonSpec `json:",inline"` + // The expiration of the keys + Expiration string `json:"expiration,omitempty"` + // The keys to be expired + Key string `json:"key,omitempty"` + // Additional options for `expiration` + Option string `json:"option,omitempty"` +} + +type RedisPenetrationSpec struct { + RedisCommonSpec `json:",inline"` + // The number of requests to be sent + RequestNum int `json:"requestNum,omitempty"` +} + +type RedisCacheLimitSpec struct { + RedisCommonSpec `json:",inline"` + // The size of `maxmemory` + Size string `json:"cacheSize,omitempty"` + // Specifies maxmemory as a percentage of the original value + Percent string `json:"percent,omitempty"` +} + +type RedisSentinelRestartSpec struct { + RedisCommonSpec `json:",inline"` + // The path of Sentinel conf + Conf string `json:"conf,omitempty"` + // The control flag determines whether to flush config + FlushConfig bool `json:"flushConfig,omitempty"` + // The path of `redis-server` command-line tool + RedisPath bool `json:"redisPath,omitempty"` +} + +type RedisSentinelStopSpec struct { + RedisCommonSpec `json:",inline"` + // The path of Sentinel conf + Conf string `json:"conf,omitempty"` + // The control flag determines whether to flush config + FlushConfig bool `json:"flushConfig,omitempty"` + // The path of `redis-server` command-line tool + RedisPath bool `json:"redisPath,omitempty"` +} + +type KafkaCommonSpec struct { + // The topic to attack + Topic string `json:"topic,omitempty"` + // The host of kafka server + Host string `json:"host,omitempty"` + // The port of kafka server + Port uint16 `json:"port,omitempty"` + // The username of kafka client + Username string `json:"username,omitempty"` + // The password of kafka client + Password string `json:"password,omitempty"` +} + +type KafkaFillSpec struct { + KafkaCommonSpec `json:",inline"` + // The size of each message + MessageSize uint `json:"messageSize,omitempty"` + // The max bytes to fill + MaxBytes uint64 `json:"maxBytes,omitempty"` + // The command to reload kafka config + ReloadCommand string `json:"reloadCommand,omitempty"` +} + +type KafkaFloodSpec struct { + KafkaCommonSpec `json:",inline"` + // The size of each message + MessageSize uint `json:"messageSize,omitempty"` + // The number of worker threads + Threads uint `json:"threads,omitempty"` +} + +type KafkaIOSpec struct { + // The topic to attack + Topic string `json:"topic,omitempty"` + // The path of server config + ConfigFile string `json:"configFile,omitempty"` + // Make kafka cluster non-readable + NonReadable bool `json:"nonReadable,omitempty"` + // Make kafka cluster non-writable + NonWritable bool `json:"nonWritable,omitempty"` +} + +type HTTPCommonSpec struct { + // Composed with one of the port of HTTP connection, we will only attack HTTP connection with port inside proxy_ports + ProxyPorts []uint `json:"proxy_ports"` + // HTTP target: Request or Response + Target string `json:"target"` + // The TCP port that the target service listens on + Port int32 `json:"port,omitempty"` + // Match path of Uri with wildcard matches + Path string `json:"path,omitempty"` + // HTTP method + Method string `json:"method,omitempty"` + // Code is a rule to select target by http status code in response + Code string `json:"code,omitempty"` +} + +type HTTPAbortSpec struct { + HTTPCommonSpec `json:",inline"` +} + +type HTTPDelaySpec struct { + HTTPCommonSpec `json:",inline"` + // Delay represents the delay of the target request/response + Delay string `json:"delay"` +} + +type HTTPConfigSpec struct { + // The config file path + FilePath string `json:"file_path,omitempty"` +} + +// used for HTTP request, now only support GET +type HTTPRequestSpec struct { + // Request to send" + URL string `json:"url,omitempty"` + // Enable connection pool + EnableConnPool bool `json:"enable-conn-pool,omitempty"` + // The number of requests to send + Count int `json:"count,omitempty"` +} + +type FileCreateSpec struct { + // FileName is the name of the file to be created, modified, deleted, renamed, or appended. + FileName string `json:"file-name,omitempty"` + // DirName is the directory name to create or delete. + DirName string `json:"dir-name,omitempty"` +} + +type FileModifyPrivilegeSpec struct { + // FileName is the name of the file to be created, modified, deleted, renamed, or appended. + FileName string `json:"file-name,omitempty"` + // Privilege is the file privilege to be set. + Privilege uint32 `json:"privilege,omitempty"` +} + +type FileDeleteSpec struct { + // FileName is the name of the file to be created, modified, deleted, renamed, or appended. + FileName string `json:"file-name,omitempty"` + // DirName is the directory name to create or delete. + DirName string `json:"dir-name,omitempty"` +} + +type FileRenameSpec struct { + // SourceFile is the name need to be renamed. + SourceFile string `json:"source-file,omitempty"` + // DestFile is the name to be renamed. + DestFile string `json:"dest-file,omitempty"` +} + +type FileAppendSpec struct { + // FileName is the name of the file to be created, modified, deleted, renamed, or appended. + FileName string `json:"file-name,omitempty"` + // Data is the data for append. + Data string `json:"data,omitempty"` + // Count is the number of times to append the data. + Count int `json:"count,omitempty"` +} + +type FileReplaceSpec struct { + // FileName is the name of the file to be created, modified, deleted, renamed, or appended. + FileName string `json:"file-name,omitempty"` + // OriginStr is the origin string of the file. + OriginStr string `json:"origin-string,omitempty"` + // DestStr is the destination string of the file. + DestStr string `json:"dest-string,omitempty"` + // Line is the line number of the file to be replaced. + Line int `json:"line,omitempty"` +} + +type VMSpec struct { + // The name of the VM to be injected + VMName string `json:"vm-name,omitempty"` +} + +type UserDefinedSpec struct { + // The command to be executed when attack + AttackCmd string `json:"attackCmd,omitempty"` + // The command to be executed when recover + RecoverCmd string `json:"recoverCmd,omitempty"` +} diff --git a/api/v1alpha1/physical_machine_chaos_types_test.go b/api/v1alpha1/physical_machine_chaos_types_test.go new file mode 100644 index 0000000000..c474a4c1f8 --- /dev/null +++ b/api/v1alpha1/physical_machine_chaos_types_test.go @@ -0,0 +1,114 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// These tests are written in BDD-style using Ginkgo framework. Refer to +// http://onsi.github.io/ginkgo to learn more. + +var _ = Describe("PhysicalMachineChaos", func() { + BeforeEach(func() { + // Add any setup steps that needs to be executed before each test + }) + + AfterEach(func() { + // Add any teardown steps that needs to be executed after each test + }) + + Context("Create API", func() { + It("should create an object successfully", func() { + testCases := []struct { + physicalMachineChaos *PhysicalMachineChaos + key types.NamespacedName + }{ + { + physicalMachineChaos: &PhysicalMachineChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + }, + Spec: PhysicalMachineChaosSpec{ + Action: "stress-mem", + PhysicalMachineSelector: PhysicalMachineSelector{ + Address: []string{"123.123.123.123.123"}, + Mode: OneMode, + }, + ExpInfo: ExpInfo{ + StressMemory: &StressMemorySpec{ + Size: "10MB", + }, + }, + }, + }, + key: types.NamespacedName{ + Name: "foo", + Namespace: "default", + }, + }, { + physicalMachineChaos: &PhysicalMachineChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo1", + Namespace: "default", + }, + Spec: PhysicalMachineChaosSpec{ + Action: "stress-mem", + PhysicalMachineSelector: PhysicalMachineSelector{ + Selector: PhysicalMachineSelectorSpec{ + GenericSelectorSpec: GenericSelectorSpec{ + LabelSelectors: map[string]string{ + "foo1": "bar", + }, + }, + }, + Mode: OneMode, + }, + ExpInfo: ExpInfo{ + StressMemory: &StressMemorySpec{ + Size: "10MB", + }, + }, + }, + }, + key: types.NamespacedName{ + Name: "foo1", + Namespace: "default", + }, + }, + } + + for _, testCase := range testCases { + By("creating an API obj") + Expect(k8sClient.Create(context.TODO(), testCase.physicalMachineChaos)).To(Succeed()) + + fetched := &PhysicalMachineChaos{} + Expect(k8sClient.Get(context.TODO(), testCase.key, fetched)).To(Succeed()) + Expect(fetched).To(Equal(testCase.physicalMachineChaos)) + + By("deleting the created object") + Expect(k8sClient.Delete(context.TODO(), testCase.physicalMachineChaos)).To(Succeed()) + Expect(k8sClient.Get(context.TODO(), testCase.key, testCase.physicalMachineChaos)).ToNot(Succeed()) + } + }) + }) +}) diff --git a/api/v1alpha1/physical_machine_chaos_webhook.go b/api/v1alpha1/physical_machine_chaos_webhook.go new file mode 100644 index 0000000000..b029183593 --- /dev/null +++ b/api/v1alpha1/physical_machine_chaos_webhook.go @@ -0,0 +1,753 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "encoding/json" + "fmt" + "reflect" + "strconv" + "strings" + + "github.com/alecthomas/units" + "github.com/google/uuid" + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func (in *PhysicalMachineChaosSpec) Default(root interface{}, field *reflect.StructField) { + if in == nil { + return + } + + if len(in.UID) == 0 { + in.UID = uuid.New().String() + } + + for i := range in.Address { + // add http prefix for address + if !strings.HasPrefix(in.Address[i], "http") { + in.Address[i] = fmt.Sprintf("http://%s", in.Address[i]) + } + } +} + +func (in *PhysicalMachineChaosSpec) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + // make sure the configuration corresponding to action is not empty + var inInterface map[string]interface{} + inrec, err := json.Marshal(in) + if err != nil { + allErrs = append(allErrs, + field.Invalid(path.Child("spec"), in, err.Error())) + } + + err = json.Unmarshal(inrec, &inInterface) + if err != nil { + allErrs = append(allErrs, + field.Invalid(path.Child("spec"), in, err.Error())) + } + + skipConfigCheck := false + if _, ok := inInterface[string(in.Action)]; !ok { + skipConfigCheck = true + allErrs = append(allErrs, + field.Invalid(path.Child("spec"), in, + "the configuration corresponding to action is required")) + } + + if len(in.Address) == 0 && in.Selector.Empty() { + allErrs = append(allErrs, + field.Invalid(path.Child("address"), in.Address, "one of address or selector should be specified")) + } + if len(in.Address) != 0 && !in.Selector.Empty() { + allErrs = append(allErrs, + field.Invalid(path.Child("address"), in.Address, "only one of address or selector could be specified")) + } + // make sure address is not empty + for _, address := range in.Address { + if len(address) == 0 { + allErrs = append(allErrs, + field.Invalid(path.Child("address"), in.Address, "the address is required")) + } + } + + if skipConfigCheck { + return allErrs + } + + var validateConfigErr error + switch in.Action { + case PMStressCPUAction: + validateConfigErr = validateStressCPUAction(in.StressCPU) + case PMStressMemAction: + validateConfigErr = validateStressMemAction(in.StressMemory) + case PMDiskWritePayloadAction: + validateConfigErr = validateDiskPayloadAction(in.DiskWritePayload) + case PMDiskReadPayloadAction: + validateConfigErr = validateDiskPayloadAction(in.DiskReadPayload) + case PMDiskFillAction: + validateConfigErr = validateDiskFillAction(in.DiskFill) + case PMNetworkCorruptAction: + validateConfigErr = validateNetworkCorruptAction(in.NetworkCorrupt) + case PMNetworkDuplicateAction: + validateConfigErr = validateNetworkDuplicateAction(in.NetworkDuplicate) + case PMNetworkLossAction: + validateConfigErr = validateNetworkLossAction(in.NetworkLoss) + case PMNetworkDelayAction: + validateConfigErr = validateNetworkDelayAction(in.NetworkDelay) + case PMNetworkPartitionAction: + validateConfigErr = validateNetworkPartitionAction(in.NetworkPartition) + case PMNetworkBandwidthAction: + validateConfigErr = validateNetworkBandwidthAction(in.NetworkBandwidth) + case PMNetworkDNSAction: + validateConfigErr = validateNetworkDNSAction(in.NetworkDNS) + case PMNetworkFloodAction: + validateConfigErr = validateNetworkFlood(in.NetworkFlood) + case PMNetworkDownAction: + validateConfigErr = validateNetworkDownAction(in.NetworkDown) + case PMProcessAction: + validateConfigErr = validateProcessAction(in.Process) + case PMJVMExceptionAction: + validateConfigErr = validateJVMExceptionAction(in.JVMException) + case PMJVMGCAction: + validateConfigErr = validateJVMGCAction(in.JVMGC) + case PMJVMLatencyAction: + validateConfigErr = validateJVMLatencyAction(in.JVMLatency) + case PMJVMReturnAction: + validateConfigErr = validateJVMReturnAction(in.JVMReturn) + case PMJVMStressAction: + validateConfigErr = validateJVMStressAction(in.JVMStress) + case PMJVMRuleDataAction: + validateConfigErr = validateJVMRuleDataAction(in.JVMRuleData) + case PMJVMMySQLAction: + validateConfigErr = validateJVMMySQLAction(in.JVMMySQL) + case PMClockAction: + validateConfigErr = validateClockAction(in.Clock) + case PMRedisExpirationAction: + validateConfigErr = validateRedisExpirationAction(in.RedisExpiration) + case PMRedisCacheLimitAction: + validateConfigErr = validateRedisCacheLimitAction(in.RedisCacheLimit) + case PMRedisPenetrationAction: + validateConfigErr = validateRedisPenetrationAction(in.RedisPenetration) + case PMRedisSentinelStopAction: + validateConfigErr = validateRedisSentinelStopAction(in.RedisSentinelStop) + case PMRedisSentinelRestartAction: + validateConfigErr = validateRedisSentinelRestartAction(in.RedisSentinelRestart) + case PMKafkaFillAction: + validateConfigErr = validateKafkaFillAction(in.KafkaFill) + case PMKafkaFloodAction: + validateConfigErr = validateKafkaFloodAction(in.KafkaFlood) + case PMKafkaIOAction: + validateConfigErr = validateKafkaIOAction(in.KafkaIO) + case PMFileCreateAction: + validateConfigErr = validateFileCreateAction(in.FileCreate) + case PMFileModifyPrivilegeAction: + validateConfigErr = validateFileModifyPrivilegeAction(in.FileModifyPrivilege) + case PMFileDeleteAction: + validateConfigErr = validateFileDeleteAction(in.FileDelete) + case PMFileRenameAction: + validateConfigErr = validateFileRenameAction(in.FileRename) + case PMFileAppendAction: + validateConfigErr = validateFileAppendAction(in.FileAppend) + case PMFileReplaceAction: + validateConfigErr = validateFileReplaceAction(in.FileReplace) + case PMUserDefinedAction: + validateConfigErr = validateUserDefinedAction(in.UserDefined) + default: + } + + if validateConfigErr != nil { + allErrs = append(allErrs, + field.Invalid(path.Child("spec"), in, + validateConfigErr.Error())) + } + + return allErrs +} + +func validateStressCPUAction(spec *StressCPUSpec) error { + if spec.Load == 0 { + return errors.New("load can't be 0") + } + + if spec.Workers == 0 { + return errors.New("workers can't be 0") + } + + return nil +} + +func validateStressMemAction(spec *StressMemorySpec) error { + if len(spec.Size) == 0 { + return errors.New("size is required") + } + + if _, err := ParseUnit(spec.Size); err != nil { + return err + } + + return nil +} + +func validateDiskPayloadAction(spec *DiskPayloadSpec) error { + if spec.PayloadProcessNum == 0 { + return errors.New("payload-process-num can't be 0") + } + + if len(spec.Size) == 0 { + return errors.New("size is required") + } + + if _, err := ParseUnit(spec.Size); err != nil { + return err + } + + return nil +} + +func validateDiskFillAction(spec *DiskFillSpec) error { + if len(spec.Size) == 0 { + return errors.New("size is required") + } + + if _, err := ParseUnit(spec.Size); err != nil { + return err + } + + return nil +} + +func validateNetworkCommon(spec *NetworkCommonSpec) error { + if !CheckPercent(spec.Correlation, true) { + return errors.Errorf("correlation %s is invalid", spec.Correlation) + } + + if len(spec.Device) == 0 { + return errors.New("device is required") + } + + return nil +} + +func validateNetworkCorruptAction(spec *NetworkCorruptSpec) error { + if err := validateNetworkCommon(&spec.NetworkCommonSpec); err != nil { + return err + } + + if !CheckPercent(spec.Percent, false) { + return errors.New("percent is invalid") + } + + return nil +} + +func validateNetworkDuplicateAction(spec *NetworkDuplicateSpec) error { + if err := validateNetworkCommon(&spec.NetworkCommonSpec); err != nil { + return err + } + + if !CheckPercent(spec.Percent, false) { + return errors.New("percent is invalid") + } + + return nil +} + +func validateNetworkLossAction(spec *NetworkLossSpec) error { + if err := validateNetworkCommon(&spec.NetworkCommonSpec); err != nil { + return err + } + + if !CheckPercent(spec.Percent, false) { + return errors.New("percent is invalid") + } + + return nil +} + +func validateNetworkDelayAction(spec *NetworkDelaySpec) error { + if err := validateNetworkCommon(&spec.NetworkCommonSpec); err != nil { + return err + } + + if len(spec.Latency) == 0 { + return errors.New("latency is invalid") + } + + if len(spec.AcceptTCPFlags) > 0 && spec.IPProtocol != "tcp" { + return errors.New("protocol should be 'tcp' when set accept-tcp-flags") + } + + return nil +} + +func validateNetworkPartitionAction(spec *NetworkPartitionSpec) error { + if len(spec.Device) == 0 { + return errors.New("device is required") + } + + if len(spec.IPAddress) == 0 && len(spec.Hostname) == 0 { + return errors.New("one of ip-address and hostname is required") + } + + if spec.Direction != "to" && spec.Direction != "from" { + return errors.New("direction should be one of 'to' and 'from'") + } + + if len(spec.AcceptTCPFlags) > 0 && spec.IPProtocol != "tcp" { + return errors.New("protocol should be 'tcp' when set accept-tcp-flags") + } + + return nil +} + +func validateNetworkBandwidthAction(spec *NetworkBandwidthSpec) error { + if len(spec.Device) == 0 { + return errors.New("device is required") + } + + if len(spec.Rate) == 0 || spec.Limit == 0 || spec.Buffer == 0 { + return errors.Errorf("rate, limit and buffer both are required when action is bandwidth") + } + + return nil +} + +func validateNetworkDNSAction(spec *NetworkDNSSpec) error { + if (len(spec.DNSDomainName) != 0 && len(spec.DNSIp) == 0) || (len(spec.DNSDomainName) == 0 && len(spec.DNSIp) != 0) { + return errors.Errorf("DNS host %s must match a DNS ip %s", spec.DNSDomainName, spec.DNSIp) + } + + return nil +} + +func validateNetworkFlood(spec *NetworkFloodSpec) error { + if len(spec.IPAddress) == 0 { + return errors.New("ip-address is required") + } + + if len(spec.Port) == 0 { + return errors.New("port is required") + } + + if len(spec.Rate) == 0 { + return errors.New("rate is required") + } + + if len(spec.Duration) == 0 { + return errors.New("duration is required") + } + + return nil +} + +func validateNetworkDownAction(spec *NetworkDownSpec) error { + if len(spec.Device) == 0 { + return errors.New("device is required") + } + if len(spec.Duration) == 0 { + return errors.New("duration is required") + } + + return nil +} + +func validateProcessAction(spec *ProcessSpec) error { + if len(spec.Process) == 0 { + return errors.New("process is required") + } + + if spec.Signal == 0 { + return errors.New("signal is required") + } + + return nil +} + +func validateJVMClassMethod(spec *JVMClassMethodSpec) error { + if len(spec.Class) == 0 { + return errors.New("class is required") + } + + if len(spec.Method) == 0 { + return errors.New("method is required") + } + + return nil +} + +func validateJVMExceptionAction(spec *JVMExceptionSpec) error { + if err := CheckPid(spec.Pid); err != nil { + return err + } + + if err := validateJVMClassMethod(&spec.JVMClassMethodSpec); err != nil { + return err + } + + if len(spec.ThrowException) == 0 { + return errors.New("exception is required") + } + + return nil +} + +func validateJVMGCAction(spec *JVMGCSpec) error { + return CheckPid(spec.Pid) +} + +func validateJVMLatencyAction(spec *JVMLatencySpec) error { + if err := CheckPid(spec.Pid); err != nil { + return err + } + + if err := validateJVMClassMethod(&spec.JVMClassMethodSpec); err != nil { + return err + } + + if spec.LatencyDuration == 0 { + return errors.New("latency is required") + } + + return nil +} + +func validateJVMReturnAction(spec *JVMReturnSpec) error { + if err := CheckPid(spec.Pid); err != nil { + return err + } + + if err := validateJVMClassMethod(&spec.JVMClassMethodSpec); err != nil { + return err + } + + if len(spec.ReturnValue) == 0 { + return errors.New("value is required") + } + + return nil +} + +func validateJVMStressAction(spec *JVMStressSpec) error { + if err := CheckPid(spec.Pid); err != nil { + return err + } + + if spec.CPUCount == 0 && len(spec.MemoryType) == 0 { + return errors.New("one of cpu-count and mem-type is required") + } + + if spec.CPUCount > 0 && len(spec.MemoryType) > 0 { + return errors.New("inject stress on both CPU and memory is not support") + } + + return nil +} + +func validateJVMRuleDataAction(spec *JVMRuleDataSpec) error { + if err := CheckPid(spec.Pid); err != nil { + return err + } + + if len(spec.RuleData) == 0 { + return errors.New("rule-data is required") + } + + return nil +} + +func validateJVMMySQLAction(spec *PMJVMMySQLSpec) error { + if err := CheckPid(spec.Pid); err != nil { + return err + } + + if len(spec.MySQLConnectorVersion) == 0 { + return errors.New("MySQL connector version not provided") + } + + if len(spec.ThrowException) == 0 && spec.LatencyDuration == 0 { + return errors.New("must set one of exception or latency") + } + + return nil +} +func validateClockAction(spec *ClockSpec) error { + if err := CheckPid(spec.Pid); err != nil { + return err + } + + if len(spec.TimeOffset) == 0 { + return errors.New("time-offset is required") + } + + return nil +} + +func CheckPid(pid int) error { + if pid == 0 { + return errors.New("pid is required") + } + + if pid < 0 { + return errors.New("pid is invalid") + } + + return nil +} + +func CheckPercent(p string, allowZero bool) bool { + if len(p) == 0 { + return allowZero + } + + v, err := strconv.ParseFloat(p, 32) + if err != nil { + return false + } + + if v == 0 && !allowZero { + return false + } + + if v < 0 || v > 100 { + return false + } + + return true +} + +var ( + // See https://en.wikipedia.org/wiki/Binary_prefix + shortBinaryUnitMap = units.MakeUnitMap("", "c", 1024) + binaryUnitMap = units.MakeUnitMap("iB", "c", 1024) + decimalUnitMap = units.MakeUnitMap("B", "c", 1000) +) + +// ParseUnit parse a digit with unit such as "K" , "KiB", "KB", "c", "MiB", "MB", "M". +// If input string is a digit without unit , +// it will be regarded as a digit with unit M(1024*1024 bytes). +func ParseUnit(s string) (uint64, error) { + if _, err := strconv.Atoi(s); err == nil { + s += "B" + } + if n, err := units.ParseUnit(s, shortBinaryUnitMap); err == nil { + return uint64(n), nil + } + + if n, err := units.ParseUnit(s, binaryUnitMap); err == nil { + return uint64(n), nil + } + + if n, err := units.ParseUnit(s, decimalUnitMap); err == nil { + return uint64(n), nil + } + return 0, errors.Wrapf(errInvalidValue, "unknown unit %s", s) +} + +func (in *NetworkBandwidthSpec) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if len(in.Rate) == 0 { + allErrs = append(allErrs, + field.Invalid(path.Child("rate"), in.Rate, "rate is required")) + } + + return allErrs +} + +var ValidOptions = map[string]bool{"XX": true, "NX": true, "GT": true, "LT": true} + +func validateRedisCommonAction(spec *RedisCommonSpec) error { + if len(spec.Addr) == 0 { + return errors.New("addr of redis server is required") + } + + return nil +} + +func validateRedisExpirationAction(spec *RedisExpirationSpec) error { + if err := validateRedisCommonAction(&spec.RedisCommonSpec); err != nil { + return err + } + + if _, ok := ValidOptions[spec.Option]; ok { + return errors.New("option invalid") + } + + return nil +} + +func validateRedisCacheLimitAction(spec *RedisCacheLimitSpec) error { + if err := validateRedisCommonAction(&spec.RedisCommonSpec); err != nil { + return err + } + + if spec.Size != "0" && spec.Percent != "" { + return errors.New("only one of size and percent can be set") + } + + return nil +} + +func validateRedisPenetrationAction(spec *RedisPenetrationSpec) error { + if err := validateRedisCommonAction(&spec.RedisCommonSpec); err != nil { + return err + } + + if spec.RequestNum == 0 { + return errors.New("requestNum is required") + } + + return nil +} + +func validateRedisSentinelStopAction(spec *RedisSentinelStopSpec) error { + return validateRedisCommonAction(&spec.RedisCommonSpec) +} + +func validateRedisSentinelRestartAction(spec *RedisSentinelRestartSpec) error { + if err := validateRedisCommonAction(&spec.RedisCommonSpec); err != nil { + return err + } + + if len(spec.Conf) == 0 { + return errors.New("conf is required to restart the sentinel") + } + + return nil +} + +func validateKafkaCommonAction(spec *KafkaCommonSpec) error { + if spec.Host == "" { + return errors.New("host is required") + } + + if spec.Port == 0 { + return errors.New("port is required") + } + + return nil +} + +func validateKafkaFillAction(spec *KafkaFillSpec) error { + if err := validateKafkaCommonAction(&spec.KafkaCommonSpec); err != nil { + return err + } + + if spec.MaxBytes == 0 { + return errors.New("max bytes is required") + } + + if spec.ReloadCommand == "" { + return errors.New("reload command is required") + } + + return nil +} + +func validateKafkaFloodAction(spec *KafkaFloodSpec) error { + if err := validateKafkaCommonAction(&spec.KafkaCommonSpec); err != nil { + return err + } + + if spec.Threads == 0 { + return errors.New("threads is required") + } + + return nil +} + +func validateKafkaIOAction(spec *KafkaIOSpec) error { + if !spec.NonReadable && !spec.NonWritable { + return errors.New("at least one of non-readable or non-writable is required") + } + + return nil +} + +func validateFileCreateAction(spec *FileCreateSpec) error { + if len(spec.FileName) == 0 && len(spec.DirName) == 0 { + return errors.New("one of file-name and dir-name is required") + } + + return nil +} + +func validateFileModifyPrivilegeAction(spec *FileModifyPrivilegeSpec) error { + if len(spec.FileName) == 0 { + return errors.New("file name is required") + } + + if spec.Privilege == 0 { + return errors.New("file privilege is required") + } + + return nil +} + +func validateFileDeleteAction(spec *FileDeleteSpec) error { + if len(spec.FileName) == 0 && len(spec.DirName) == 0 { + return errors.New("one of file-name and dir-name is required") + } + + return nil +} + +func validateFileRenameAction(spec *FileRenameSpec) error { + if len(spec.SourceFile) == 0 || len(spec.DestFile) == 0 { + return errors.New("both source file and destination file are required") + } + + return nil +} + +func validateFileAppendAction(spec *FileAppendSpec) error { + if len(spec.FileName) == 0 { + return errors.New("file-name is required") + } + + if len(spec.Data) == 0 { + return errors.New("append data is required") + } + + return nil +} + +func validateFileReplaceAction(spec *FileReplaceSpec) error { + if len(spec.FileName) == 0 { + return errors.New("file-name is required") + } + + if len(spec.OriginStr) == 0 || len(spec.DestStr) == 0 { + return errors.New("both origin and destination string are required") + } + + return nil +} + +func validateUserDefinedAction(spec *UserDefinedSpec) error { + if len(spec.AttackCmd) == 0 { + return errors.New("attack command not provided") + } + + if len(spec.RecoverCmd) == 0 { + return errors.New("recover command not provided") + } + + return nil +} diff --git a/api/v1alpha1/physical_machine_chaos_webhook_test.go b/api/v1alpha1/physical_machine_chaos_webhook_test.go new file mode 100644 index 0000000000..cc9edfcd1a --- /dev/null +++ b/api/v1alpha1/physical_machine_chaos_webhook_test.go @@ -0,0 +1,1091 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("physicalmachinechaos_webhook", func() { + Context("webhook.Defaultor of physicalmachinechaos", func() { + It("Default", func() { + physicalMachineChaos := &PhysicalMachineChaos{ + Spec: PhysicalMachineChaosSpec{ + Action: "stress-cpu", + PhysicalMachineSelector: PhysicalMachineSelector{ + Address: []string{ + "123.123.123.123:123", + "234.234.234.234:234", + }, + }, + ExpInfo: ExpInfo{ + UID: "", + StressCPU: &StressCPUSpec{ + Load: 10, + Workers: 1, + }, + }, + }, + } + physicalMachineChaos.Default() + Expect(physicalMachineChaos.Spec.UID).ToNot(Equal("")) + Expect(physicalMachineChaos.Spec.Address).To(BeEquivalentTo([]string{ + "http://123.123.123.123:123", + "http://234.234.234.234:234", + })) + }) + }) + Context("webhook.Validator of physicalmachinechaos", func() { + It("Validate common", func() { + testCases := []struct { + chaos PhysicalMachineChaos + err string + }{ + { + PhysicalMachineChaos{ + Spec: PhysicalMachineChaosSpec{ + PhysicalMachineSelector: PhysicalMachineSelector{ + Address: []string{ + "123.123.123.123:123", + "234.234.234.234:234", + }, + }, + Action: "stress-cpu", + ExpInfo: ExpInfo{}, + }, + }, + "the configuration corresponding to action is required", + }, + } + + for _, testCase := range testCases { + _, err := testCase.chaos.ValidateCreate() + Expect(strings.Contains(err.Error(), testCase.err)).To(BeTrue()) + } + }) + + It("Validate selector", func() { + testCases := []struct { + chaos PhysicalMachineChaos + err string + }{ + { + PhysicalMachineChaos{ + Spec: PhysicalMachineChaosSpec{ + Action: "stress-cpu", + PhysicalMachineSelector: PhysicalMachineSelector{ + Address: []string{ + "123.123.123.123:123", + "234.234.234.234:234", + }, + Selector: PhysicalMachineSelectorSpec{ + PhysicalMachines: map[string][]string{ + "default": {"physical-machine1"}, + }, + }, + }, + ExpInfo: ExpInfo{ + UID: "", + StressCPU: &StressCPUSpec{ + Load: 10, + Workers: 1, + }, + }, + }, + }, + "only one of address or selector could be specified", + }, + { + PhysicalMachineChaos{ + Spec: PhysicalMachineChaosSpec{ + Action: "stress-cpu", + PhysicalMachineSelector: PhysicalMachineSelector{ + Selector: PhysicalMachineSelectorSpec{ + PhysicalMachines: map[string][]string{ + "default": {"physical-machine1"}, + }, + }, + }, + ExpInfo: ExpInfo{ + UID: "", + StressCPU: &StressCPUSpec{ + Load: 10, + Workers: 1, + }, + }, + }, + }, + "", + }, + { + PhysicalMachineChaos{ + Spec: PhysicalMachineChaosSpec{ + Action: "stress-cpu", + PhysicalMachineSelector: PhysicalMachineSelector{ + Address: []string{ + "123.123.123.123:123", + "234.234.234.234:234", + }, + }, + ExpInfo: ExpInfo{ + UID: "", + StressCPU: &StressCPUSpec{ + Load: 10, + Workers: 1, + }, + }, + }, + }, + "", + }, + { + PhysicalMachineChaos{ + Spec: PhysicalMachineChaosSpec{ + Action: "stress-cpu", + PhysicalMachineSelector: PhysicalMachineSelector{}, + ExpInfo: ExpInfo{ + UID: "", + StressCPU: &StressCPUSpec{ + Load: 10, + Workers: 1, + }, + }, + }, + }, + "one of address or selector should be specified", + }, + } + + for _, testCase := range testCases { + _, err := testCase.chaos.ValidateCreate() + if len(testCase.err) != 0 { + Expect(err).To(HaveOccurred()) + Expect(strings.Contains(err.Error(), testCase.err)).To(BeTrue()) + } else { + Expect(err).ToNot(HaveOccurred()) + } + } + }) + + It("Validate config for specified action", func() { + testCases := []struct { + action PhysicalMachineChaosAction + expInfo ExpInfo + err string + }{ + { + PMStressCPUAction, + ExpInfo{ + StressCPU: &StressCPUSpec{ + Load: 0, + }, + }, + "load can't be 0", + }, + { + PMStressCPUAction, + ExpInfo{ + StressCPU: &StressCPUSpec{ + Load: 1, + Workers: 0, + }, + }, + "workers can't be 0", + }, + { + PMStressCPUAction, + ExpInfo{ + StressCPU: &StressCPUSpec{ + Load: 1, + Workers: 1, + }, + }, + "", + }, + { + PMStressMemAction, + ExpInfo{ + StressMemory: &StressMemorySpec{ + Size: "", + }, + }, + "size is required", + }, + { + PMStressMemAction, + ExpInfo{ + StressMemory: &StressMemorySpec{ + Size: "123HB", + }, + }, + "unknown unit", + }, + { + PMStressMemAction, + ExpInfo{ + StressMemory: &StressMemorySpec{ + Size: "123MB", + }, + }, + "", + }, + { + PMDiskReadPayloadAction, + ExpInfo{ + DiskReadPayload: &DiskPayloadSpec{ + PayloadProcessNum: 0, + }, + }, + "payload-process-num can't be 0", + }, + { + PMDiskReadPayloadAction, + ExpInfo{ + DiskReadPayload: &DiskPayloadSpec{ + PayloadProcessNum: 1, + DiskFileSpec: DiskFileSpec{ + Size: "", + }, + }, + }, + "size is required", + }, + { + PMDiskReadPayloadAction, + ExpInfo{ + DiskReadPayload: &DiskPayloadSpec{ + PayloadProcessNum: 1, + DiskFileSpec: DiskFileSpec{ + Size: "100HB", + }, + }, + }, + "unknown unit", + }, + { + PMDiskReadPayloadAction, + ExpInfo{ + DiskReadPayload: &DiskPayloadSpec{ + PayloadProcessNum: 1, + DiskFileSpec: DiskFileSpec{ + Size: "100MB", + }, + }, + }, + "", + }, + { + PMDiskWritePayloadAction, + ExpInfo{ + DiskWritePayload: &DiskPayloadSpec{ + PayloadProcessNum: 0, + }, + }, + "payload-process-num can't be 0", + }, + { + PMDiskWritePayloadAction, + ExpInfo{ + DiskWritePayload: &DiskPayloadSpec{ + PayloadProcessNum: 1, + DiskFileSpec: DiskFileSpec{ + Size: "", + }, + }, + }, + "size is required", + }, + { + PMDiskWritePayloadAction, + ExpInfo{ + DiskWritePayload: &DiskPayloadSpec{ + PayloadProcessNum: 1, + DiskFileSpec: DiskFileSpec{ + Size: "100HB", + }, + }, + }, + "unknown unit", + }, + { + PMDiskWritePayloadAction, + ExpInfo{ + DiskWritePayload: &DiskPayloadSpec{ + PayloadProcessNum: 1, + DiskFileSpec: DiskFileSpec{ + Size: "100MB", + }, + }, + }, + "", + }, + { + PMDiskFillAction, + ExpInfo{ + DiskFill: &DiskFillSpec{ + DiskFileSpec: DiskFileSpec{ + Size: "", + }, + }, + }, + "size is required", + }, + { + PMDiskFillAction, + ExpInfo{ + DiskFill: &DiskFillSpec{ + DiskFileSpec: DiskFileSpec{ + Size: "100HB", + }, + }, + }, + "unknown unit", + }, + { + PMDiskFillAction, + ExpInfo{ + DiskFill: &DiskFillSpec{ + DiskFileSpec: DiskFileSpec{ + Size: "100MB", + }, + }, + }, + "", + }, + { + PMNetworkCorruptAction, + ExpInfo{ + NetworkCorrupt: &NetworkCorruptSpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "-1", + }, + }, + }, + "correlation -1 is invalid", + }, + { + PMNetworkCorruptAction, + ExpInfo{ + NetworkCorrupt: &NetworkCorruptSpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "100", + Device: "", + }, + }, + }, + "device is required", + }, + { + PMNetworkCorruptAction, + ExpInfo{ + NetworkCorrupt: &NetworkCorruptSpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "100", + Device: "eth0", + IPAddress: "123.123.123.123", + }, + Percent: "0", + }, + }, + "percent is invalid", + }, + { + PMNetworkCorruptAction, + ExpInfo{ + NetworkCorrupt: &NetworkCorruptSpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "100", + Device: "eth0", + IPAddress: "123.123.123.123", + }, + Percent: "10", + }, + }, + "", + }, + { + PMNetworkDuplicateAction, + ExpInfo{ + NetworkDuplicate: &NetworkDuplicateSpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "-1", + }, + }, + }, + "correlation -1 is invalid", + }, + { + PMNetworkDuplicateAction, + ExpInfo{ + NetworkDuplicate: &NetworkDuplicateSpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "100", + Device: "", + }, + }, + }, + "device is required", + }, + { + PMNetworkDuplicateAction, + ExpInfo{ + NetworkDuplicate: &NetworkDuplicateSpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "100", + Device: "eth0", + IPAddress: "123.123.123.123", + }, + Percent: "0", + }, + }, + "percent is invalid", + }, + { + PMNetworkDuplicateAction, + ExpInfo{ + NetworkDuplicate: &NetworkDuplicateSpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "100", + Device: "eth0", + IPAddress: "123.123.123.123", + }, + Percent: "10", + }, + }, + "", + }, + { + PMNetworkLossAction, + ExpInfo{ + NetworkLoss: &NetworkLossSpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "100", + Device: "", + }, + }, + }, + "device is required", + }, + { + PMNetworkLossAction, + ExpInfo{ + NetworkLoss: &NetworkLossSpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "100", + Device: "eth0", + IPAddress: "123.123.123.123", + }, + Percent: "0", + }, + }, + "percent is invalid", + }, + { + PMNetworkLossAction, + ExpInfo{ + NetworkLoss: &NetworkLossSpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "100", + Device: "eth0", + IPAddress: "123.123.123.123", + }, + Percent: "10", + }, + }, + "", + }, + { + PMNetworkDelayAction, + ExpInfo{ + NetworkDelay: &NetworkDelaySpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "-1", + }, + }, + }, + "correlation -1 is invalid", + }, + { + PMNetworkDelayAction, + ExpInfo{ + NetworkDelay: &NetworkDelaySpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "100", + Device: "", + }, + }, + }, + "device is required", + }, + { + PMNetworkDelayAction, + ExpInfo{ + NetworkDelay: &NetworkDelaySpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "100", + Device: "eth0", + Hostname: "chaos-mesh.org", + }, + }, + }, + "latency is invalid", + }, + { + PMNetworkDelayAction, + ExpInfo{ + NetworkDelay: &NetworkDelaySpec{ + NetworkCommonSpec: NetworkCommonSpec{ + Correlation: "100", + Device: "eth0", + Hostname: "chaos-mesh.org", + }, + Latency: "10ms", + }, + }, + "", + }, + { + PMNetworkPartitionAction, + ExpInfo{ + NetworkPartition: &NetworkPartitionSpec{ + + Device: "", + }, + }, + "device is required", + }, + { + PMNetworkPartitionAction, + ExpInfo{ + NetworkPartition: &NetworkPartitionSpec{ + Device: "eth0", + }, + }, + "one of ip-address and hostname is required", + }, + { + PMNetworkPartitionAction, + ExpInfo{ + NetworkPartition: &NetworkPartitionSpec{ + Device: "eth0", + Hostname: "chaos-mesh.org", + Direction: "nil", + }, + }, + "direction should be one of 'to' and 'from'", + }, + { + PMNetworkPartitionAction, + ExpInfo{ + NetworkPartition: &NetworkPartitionSpec{ + Device: "eth0", + Hostname: "chaos-mesh.org", + Direction: "to", + AcceptTCPFlags: "SYN,ACK SYN,ACK", + IPProtocol: "udp", + }, + }, + "protocol should be 'tcp' when set accept-tcp-flags", + }, + { + PMNetworkPartitionAction, + ExpInfo{ + NetworkPartition: &NetworkPartitionSpec{ + Device: "eth0", + Hostname: "chaos-mesh.org", + Direction: "to", + AcceptTCPFlags: "SYN,ACK SYN,ACK", + IPProtocol: "tcp", + }, + }, + "", + }, + { + PMNetworkDNSAction, + ExpInfo{ + NetworkDNS: &NetworkDNSSpec{ + DNSDomainName: "chaos-mesh.org", + DNSIp: "", + }, + }, + "DNS host chaos-mesh.org must match a DNS ip", + }, + { + PMNetworkDNSAction, + ExpInfo{ + NetworkDNS: &NetworkDNSSpec{ + DNSDomainName: "", + DNSIp: "123.123.123.123", + }, + }, + "DNS host must match a DNS ip 123.123.123.123", + }, + { + PMNetworkDNSAction, + ExpInfo{ + NetworkDNS: &NetworkDNSSpec{ + DNSDomainName: "chaos-mesh.org", + DNSIp: "123.123.123.123", + }, + }, + "", + }, + { + PMProcessAction, + ExpInfo{ + Process: &ProcessSpec{ + Process: "", + }, + }, + "process is required", + }, + { + PMProcessAction, + ExpInfo{ + Process: &ProcessSpec{ + Process: "123", + Signal: 0, + }, + }, + "signal is required", + }, + { + PMProcessAction, + ExpInfo{ + Process: &ProcessSpec{ + Process: "123", + Signal: 19, + }, + }, + "", + }, + { + PMJVMExceptionAction, + ExpInfo{ + JVMException: &JVMExceptionSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 0, + }, + }, + }, + "pid is required", + }, + { + PMJVMExceptionAction, + ExpInfo{ + JVMException: &JVMExceptionSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 123, + }, + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "", + }, + }, + }, + "class is required", + }, + { + PMJVMExceptionAction, + ExpInfo{ + JVMException: &JVMExceptionSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 123, + }, + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "", + }, + }, + }, + "method is required", + }, + { + PMJVMExceptionAction, + ExpInfo{ + JVMException: &JVMExceptionSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 123, + }, + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "test", + }, + ThrowException: "", + }, + }, + "exception is required", + }, + { + PMJVMExceptionAction, + ExpInfo{ + JVMException: &JVMExceptionSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 123, + }, + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "test", + }, + ThrowException: "java.io.IOException(\"BOOM\")", + }, + }, + "", + }, + { + PMJVMGCAction, + ExpInfo{ + JVMGC: &JVMGCSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 0, + }, + }, + }, + "pid is required", + }, + { + PMJVMGCAction, + ExpInfo{ + JVMGC: &JVMGCSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 10, + }, + }, + }, + "", + }, + { + PMJVMLatencyAction, + ExpInfo{ + JVMLatency: &JVMLatencySpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 0, + }, + }, + }, + "pid is required", + }, + { + PMJVMLatencyAction, + ExpInfo{ + JVMLatency: &JVMLatencySpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 123, + }, + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "", + }, + }, + }, + "class is required", + }, + { + PMJVMLatencyAction, + ExpInfo{ + JVMLatency: &JVMLatencySpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 123, + }, + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "", + }, + }, + }, + "method is required", + }, + { + PMJVMLatencyAction, + ExpInfo{ + JVMLatency: &JVMLatencySpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 123, + }, + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "test", + }, + LatencyDuration: 0, + }, + }, + "latency is required", + }, + { + PMJVMLatencyAction, + ExpInfo{ + JVMLatency: &JVMLatencySpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 123, + }, + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "test", + }, + LatencyDuration: 1000, + }, + }, + "", + }, + { + PMJVMReturnAction, + ExpInfo{ + JVMReturn: &JVMReturnSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 0, + }, + }, + }, + "pid is required", + }, + { + PMJVMReturnAction, + ExpInfo{ + JVMReturn: &JVMReturnSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 123, + }, + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "", + }, + }, + }, + "class is required", + }, + { + PMJVMReturnAction, + ExpInfo{ + JVMReturn: &JVMReturnSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 123, + }, + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "", + }, + }, + }, + "method is required", + }, + { + PMJVMReturnAction, + ExpInfo{ + JVMReturn: &JVMReturnSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 123, + }, + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "test", + }, + ReturnValue: "", + }, + }, + "value is required", + }, + { + PMJVMReturnAction, + ExpInfo{ + JVMReturn: &JVMReturnSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 123, + }, + JVMClassMethodSpec: JVMClassMethodSpec{ + Class: "Main", + Method: "test", + }, + ReturnValue: "123", + }, + }, + "", + }, + { + PMJVMStressAction, + ExpInfo{ + JVMStress: &JVMStressSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 0, + }, + }, + }, + "pid is required", + }, + { + PMJVMStressAction, + ExpInfo{ + JVMStress: &JVMStressSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 10, + }, + + CPUCount: 0, + MemoryType: "", + }, + }, + "one of cpu-count and mem-type is required", + }, + { + PMJVMStressAction, + ExpInfo{ + JVMStress: &JVMStressSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 10, + }, + CPUCount: 1, + MemoryType: "heap", + }, + }, + "inject stress on both CPU and memory is not support", + }, + { + PMJVMStressAction, + ExpInfo{ + JVMStress: &JVMStressSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 10, + }, + CPUCount: 0, + MemoryType: "heap", + }, + }, + "", + }, + { + PMJVMRuleDataAction, + ExpInfo{ + JVMRuleData: &JVMRuleDataSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 0, + }, + }, + }, + "pid is required", + }, + { + PMJVMRuleDataAction, + ExpInfo{ + JVMRuleData: &JVMRuleDataSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 10, + }, + RuleData: "", + }, + }, + "rule-data is required", + }, + { + PMJVMRuleDataAction, + ExpInfo{ + JVMRuleData: &JVMRuleDataSpec{ + JVMCommonSpec: JVMCommonSpec{ + Pid: 10, + }, + RuleData: "RULE modify return value\nCLASS Main\nMETHOD getnum\nAT ENTRY\nIF true\nDO\n return 9999\nENDRULE", + }, + }, + "", + }, + { + PMClockAction, + ExpInfo{ + Clock: &ClockSpec{ + Pid: 0, + }, + }, + "pid is required", + }, + { + PMClockAction, + ExpInfo{ + Clock: &ClockSpec{ + Pid: 123, + TimeOffset: "", + }, + }, + "time-offset is required", + }, + { + PMClockAction, + ExpInfo{ + Clock: &ClockSpec{ + Pid: 123, + TimeOffset: "10m", + }, + }, + "", + }, + } + + for _, testCase := range testCases { + chaos := PhysicalMachineChaos{ + Spec: PhysicalMachineChaosSpec{ + PhysicalMachineSelector: PhysicalMachineSelector{ + Address: []string{ + "123.123.123.123:123", + "234.234.234.234:234", + }, + }, + Action: testCase.action, + ExpInfo: testCase.expInfo, + }, + } + _, err := chaos.ValidateCreate() + if len(testCase.err) != 0 { + Expect(err).To(HaveOccurred()) + Expect(strings.Contains(err.Error(), testCase.err)).To(BeTrue()) + } else { + Expect(err).ToNot(HaveOccurred()) + } + } + }) + }) + Context("webhook.Validator of bandwidth physicalmachinechaos", func() { + It("Validate", func() { + testCases := []struct { + chaos PhysicalMachineChaos + err string + }{ + { + PhysicalMachineChaos{ + Spec: PhysicalMachineChaosSpec{ + PhysicalMachineSelector: PhysicalMachineSelector{ + Address: []string{ + "123.123.123.123:123", + "234.234.234.234:234", + }, + }, + Action: "network", + ExpInfo: ExpInfo{ + NetworkBandwidth: &NetworkBandwidthSpec{ + Rate: "", + Limit: 0, + Buffer: 0, + }, + }, + }, + }, + "rate is required", + }, + } + + for _, testCase := range testCases { + _, err := testCase.chaos.ValidateCreate() + Expect(strings.Contains(err.Error(), testCase.err)).To(BeTrue()) + } + }) + }) +}) diff --git a/api/v1alpha1/physical_machine_types.go b/api/v1alpha1/physical_machine_types.go new file mode 100644 index 0000000000..eaa171438b --- /dev/null +++ b/api/v1alpha1/physical_machine_types.go @@ -0,0 +1,48 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +// +chaos-mesh:base + +// PhysicalMachine is the Schema for the physical machine API +type PhysicalMachine struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the behavior of a physical machine + Spec PhysicalMachineSpec `json:"spec"` +} + +// PhysicalMachineSpec defines the desired state of PhysicalMachine +type PhysicalMachineSpec struct { + + // Address represents the address of the physical machine + Address string `json:"address"` +} + +// +kubebuilder:object:root=true + +// PhysicalMachineList contains a list of PhysicalMachine +type PhysicalMachineList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []PhysicalMachine `json:"items"` +} diff --git a/api/v1alpha1/physical_machine_types_test.go b/api/v1alpha1/physical_machine_types_test.go new file mode 100644 index 0000000000..67a95d0439 --- /dev/null +++ b/api/v1alpha1/physical_machine_types_test.go @@ -0,0 +1,73 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// These tests are written in BDD-style using Ginkgo framework. Refer to +// http://onsi.github.io/ginkgo to learn more. + +var _ = Describe("PhysicalMachine", func() { + var ( + key types.NamespacedName + created, fetched *PhysicalMachine + ) + + BeforeEach(func() { + // Add any setup steps that needs to be executed before each test + }) + + AfterEach(func() { + // Add any teardown steps that needs to be executed after each test + }) + + Context("Create API", func() { + It("should create an object successfully", func() { + key = types.NamespacedName{ + Name: "foo", + Namespace: "default", + } + + created = &PhysicalMachine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + }, + Spec: PhysicalMachineSpec{ + Address: "http://123.123.123.123:2333", + }, + } + + By("creating an API obj") + Expect(k8sClient.Create(context.TODO(), created)).To(Succeed()) + + fetched = &PhysicalMachine{} + Expect(k8sClient.Get(context.TODO(), key, fetched)).To(Succeed()) + Expect(fetched).To(Equal(created)) + + By("deleting the created object") + Expect(k8sClient.Delete(context.TODO(), created)).To(Succeed()) + Expect(k8sClient.Get(context.TODO(), key, created)).ToNot(Succeed()) + }) + }) +}) diff --git a/api/v1alpha1/physical_machine_webhook.go b/api/v1alpha1/physical_machine_webhook.go new file mode 100644 index 0000000000..20311ca331 --- /dev/null +++ b/api/v1alpha1/physical_machine_webhook.go @@ -0,0 +1,56 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "fmt" + "net/url" + "reflect" + "strings" + + "k8s.io/apimachinery/pkg/util/validation/field" + logf "sigs.k8s.io/controller-runtime/pkg/log" +) + +var physicalMachineLog = logf.Log.WithName("physical-machine-resource") + +func (in *PhysicalMachineSpec) Default(root interface{}, field *reflect.StructField) { + if in == nil { + return + } + + physicalMachineLog.Info("default", "address", in.Address) + // add http prefix for address + if len(in.Address) > 0 && !strings.HasPrefix(in.Address, "http") { + in.Address = fmt.Sprintf("http://%s", in.Address) + } +} + +func (in *PhysicalMachineSpec) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + // make sure address is not empty + if len(in.Address) == 0 { + allErrs = append(allErrs, + field.Invalid(path.Child("address"), in.Address, "the address is required")) + } + + if _, err := url.ParseRequestURI(in.Address); err != nil { + allErrs = append(allErrs, + field.Invalid(path.Child("address"), in.Address, fmt.Sprintf("the address is invalid, %s", err))) + } + return allErrs +} diff --git a/api/v1alpha1/physical_machine_webhook_test.go b/api/v1alpha1/physical_machine_webhook_test.go new file mode 100644 index 0000000000..172f0d1796 --- /dev/null +++ b/api/v1alpha1/physical_machine_webhook_test.go @@ -0,0 +1,78 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("physicalmachine_webhook", func() { + Context("webhook.Defaultor of physicalmachine", func() { + It("Default", func() { + physicalMachine := &PhysicalMachine{ + Spec: PhysicalMachineSpec{ + Address: "123.123.123.123:123", + }, + } + physicalMachine.Default() + Expect(physicalMachine.Spec.Address).To(BeEquivalentTo("http://123.123.123.123:123")) + }) + }) + Context("webhook.Validator of physicalmachine", func() { + It("Validate", func() { + testCases := []struct { + physicalMachine PhysicalMachine + err string + }{ + { + PhysicalMachine{ + Spec: PhysicalMachineSpec{ + Address: "", + }, + }, + "the address is required", + }, { + PhysicalMachine{ + Spec: PhysicalMachineSpec{ + Address: "123", + }, + }, + "the address is invalid", + }, { + PhysicalMachine{ + Spec: PhysicalMachineSpec{ + Address: "http://123.123.123.123:123", + }, + }, + "", + }, + } + + for _, testCase := range testCases { + _, err := testCase.physicalMachine.ValidateCreate() + if len(testCase.err) != 0 { + Expect(err).To(HaveOccurred()) + Expect(strings.Contains(err.Error(), testCase.err)).To(BeTrue()) + } else { + Expect(err).ToNot(HaveOccurred()) + } + } + }) + }) +}) diff --git a/api/v1alpha1/podchaos_types.go b/api/v1alpha1/podchaos_types.go index 2c8bc682b9..72ce077d1b 100644 --- a/api/v1alpha1/podchaos_types.go +++ b/api/v1alpha1/podchaos_types.go @@ -1,15 +1,17 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 @@ -18,7 +20,8 @@ import ( ) // +kubebuilder:object:root=true -// +chaos-mesh:base +// +chaos-mesh:experiment +// +chaos-mesh:oneshot=in.Spec.Action==PodKillAction || in.Spec.Action==ContainerKillAction // PodChaos is the control script`s spec. type PodChaos struct { @@ -30,9 +33,12 @@ type PodChaos struct { // +optional // Most recently observed status of the chaos experiment about pods - Status PodChaosStatus `json:"status"` + Status PodChaosStatus `json:"status,omitempty"` } +var _ InnerObjectWithSelector = (*PodChaos)(nil) +var _ InnerObject = (*PodChaos)(nil) + // PodChaosAction represents the chaos action about pods. type PodChaosAction string @@ -48,12 +54,7 @@ const ( // PodChaosSpec defines the attributes that a user creates on a chaos experiment about pods. type PodChaosSpec struct { - // Selector is used to select pods that are used to inject chaos action. - Selector SelectorSpec `json:"selector"` - - // Scheduler defines some schedule rules to - // control the running time of the chaos experiment about pods. - Scheduler *SchedulerSpec `json:"scheduler,omitempty"` + ContainerSelector `json:",inline"` // Action defines the specific pod chaos action. // Supported action: pod-kill / pod-failure / container-kill @@ -61,18 +62,6 @@ type PodChaosSpec struct { // +kubebuilder:validation:Enum=pod-kill;pod-failure;container-kill Action PodChaosAction `json:"action"` - // Mode defines the mode to run chaos action. - // Supported mode: one / all / fixed / fixed-percent / random-max-percent - // +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent - Mode PodMode `json:"mode"` - - // Value is required when the mode is set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - // If `FixedPodMode`, provide an integer of pods to do chaos action. - // If `FixedPercentPodMod`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. - // IF `RandomMaxPercentPodMod`, provide a number from 0-100 to specify the max percent of pods to do chaos action - // +optional - Value string `json:"value"` - // Duration represents the duration of the chaos action. // It is required when the action is `PodFailureAction`. // A duration string is a possibly signed sequence of @@ -80,30 +69,17 @@ type PodChaosSpec struct { // such as "300ms", "-1.5h" or "2h45m". // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". // +optional - Duration *string `json:"duration,omitempty"` - - // ContainerName indicates the name of the container. - // Needed in container-kill. - // +optional - ContainerName string `json:"containerName"` + Duration *string `json:"duration,omitempty" webhook:"Duration"` // GracePeriod is used in pod-kill action. It represents the duration in seconds before the pod should be deleted. // Value must be non-negative integer. The default value is zero that indicates delete immediately. // +optional // +kubebuilder:validation:Minimum=0 - GracePeriod int64 `json:"gracePeriod"` -} - -func (in *PodChaosSpec) GetSelector() SelectorSpec { - return in.Selector -} - -func (in *PodChaosSpec) GetMode() PodMode { - return in.Mode -} + GracePeriod int64 `json:"gracePeriod,omitempty"` -func (in *PodChaosSpec) GetValue() string { - return in.Value + // RemoteCluster represents the remote cluster where the chaos will be deployed + // +optional + RemoteCluster string `json:"remoteCluster,omitempty"` } // PodChaosStatus represents the current status of the chaos experiment about pods. @@ -111,16 +87,17 @@ type PodChaosStatus struct { ChaosStatus `json:",inline"` } -// PodStatus represents information about the status of a pod in chaos experiment. -type PodStatus struct { - Namespace string `json:"namespace"` - Name string `json:"name"` - Action string `json:"action"` - HostIP string `json:"hostIP"` - PodIP string `json:"podIP"` - - // A brief CamelCase message indicating details about the chaos action. - // e.g. "delete this pod" or "pause this pod duration 5m" - // +optional - Message string `json:"message"` +func (obj *PodChaos) GetSelectorSpecs() map[string]interface{} { + switch obj.Spec.Action { + case PodKillAction, PodFailureAction: + return map[string]interface{}{ + ".": &obj.Spec.PodSelector, + } + case ContainerKillAction: + return map[string]interface{}{ + ".": &obj.Spec.ContainerSelector, + } + } + + return nil } diff --git a/api/v1alpha1/podchaos_types_test.go b/api/v1alpha1/podchaos_types_test.go index 3e7580758b..25a79ba3ae 100644 --- a/api/v1alpha1/podchaos_types_test.go +++ b/api/v1alpha1/podchaos_types_test.go @@ -1,25 +1,25 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "context" - "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) @@ -55,7 +55,11 @@ var _ = Describe("PodChaos", func() { }, Spec: PodChaosSpec{ Action: PodKillAction, - Mode: OnePodMode, + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Mode: OneMode, + }, + }, }, } @@ -70,19 +74,5 @@ var _ = Describe("PodChaos", func() { Expect(k8sClient.Delete(context.TODO(), created)).To(Succeed()) Expect(k8sClient.Get(context.TODO(), key, created)).ToNot(Succeed()) }) - - It("should set next start time successfully", func() { - podchaos := &PodChaos{} - nTime := time.Now() - podchaos.SetNextStart(nTime) - Expect(podchaos.GetNextStart()).To(Equal(nTime)) - }) - - It("should set recover time successfully", func() { - podchaos := &PodChaos{} - nTime := time.Now() - podchaos.SetNextRecover(nTime) - Expect(podchaos.GetNextRecover()).To(Equal(nTime)) - }) }) }) diff --git a/api/v1alpha1/podchaos_webhook.go b/api/v1alpha1/podchaos_webhook.go index 265ede8337..156f3a3c99 100644 --- a/api/v1alpha1/podchaos_webhook.go +++ b/api/v1alpha1/podchaos_webhook.go @@ -1,129 +1,32 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - "fmt" - - "k8s.io/apimachinery/pkg/runtime" + "github.com/pkg/errors" "k8s.io/apimachinery/pkg/util/validation/field" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/webhook" ) -// log is for logging in this package. -var podchaoslog = logf.Log.WithName("podchaos-resource") - -// +kubebuilder:webhook:path=/mutate-chaos-mesh-org-v1alpha1-podchaos,mutating=true,failurePolicy=fail,groups=chaos-mesh.org,resources=podchaos,verbs=create;update,versions=v1alpha1,name=mpodchaos.kb.io - -var _ webhook.Defaulter = &PodChaos{} - -// Default implements webhook.Defaulter so a webhook will be registered for the type -func (in *PodChaos) Default() { - podchaoslog.Info("default", "name", in.Name) - - in.Spec.Selector.DefaultNamespace(in.GetNamespace()) -} - -// +kubebuilder:webhook:verbs=create;update,path=/validate-chaos-mesh-org-v1alpha1-podchaos,mutating=false,failurePolicy=fail,groups=chaos-mesh.org,resources=podchaos,versions=v1alpha1,name=vpodchaos.kb.io - -var _ ChaosValidator = &PodChaos{} - -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (in *PodChaos) ValidateCreate() error { - podchaoslog.Info("validate create", "name", in.Name) - return in.Validate() -} - -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (in *PodChaos) ValidateUpdate(old runtime.Object) error { - podchaoslog.Info("validate update", "name", in.Name) - return in.Validate() -} - -// ValidateDelete implements webhook.Validator so a webhook will be registered for the type -func (in *PodChaos) ValidateDelete() error { - podchaoslog.Info("validate delete", "name", in.Name) - - // Nothing to do? - return nil -} - -// Validate validates chaos object -func (in *PodChaos) Validate() error { - specField := field.NewPath("spec") - allErrs := in.ValidateScheduler(specField) - allErrs = append(allErrs, in.ValidatePodMode(specField)...) - allErrs = append(allErrs, in.Spec.validateContainerName(specField.Child("containerName"))...) - - if len(allErrs) > 0 { - return fmt.Errorf(allErrs.ToAggregate().Error()) - } - return nil -} - -// ValidateScheduler validates the scheduler and duration -func (in *PodChaos) ValidateScheduler(spec *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - schedulerField := spec.Child("scheduler") - - switch in.Spec.Action { - case PodFailureAction: - allErrs = append(allErrs, ValidateScheduler(in, spec)...) - case PodKillAction: - // We choose to ignore the Duration property even user define it - if in.Spec.Scheduler == nil { - allErrs = append(allErrs, field.Invalid(schedulerField, in.Spec.Scheduler, ValidatePodchaosSchedulerError)) - } else { - _, err := ParseCron(in.Spec.Scheduler.Cron, schedulerField.Child("cron")) - allErrs = append(allErrs, err...) - } - case ContainerKillAction: - // We choose to ignore the Duration property even user define it - if in.Spec.Scheduler == nil { - allErrs = append(allErrs, field.Invalid(schedulerField, in.Spec.Scheduler, ValidatePodchaosSchedulerError)) - } else { - _, err := ParseCron(in.Spec.Scheduler.Cron, schedulerField.Child("cron")) - allErrs = append(allErrs, err...) - } - default: - err := fmt.Errorf("podchaos[%s/%s] have unknown action type", in.Namespace, in.Name) - log.Error(err, "Wrong PodChaos Action type") - - actionField := spec.Child("action") - allErrs = append(allErrs, field.Invalid(actionField, in.Spec.Action, err.Error())) - } - return allErrs -} - -// ValidatePodMode validates the value with podmode -func (in *PodChaos) ValidatePodMode(spec *field.Path) field.ErrorList { - return ValidatePodMode(in.Spec.Value, in.Spec.Mode, spec.Child("value")) -} - -// SelectSpec returns the selector config for authority validate -func (in *PodChaos) GetSelectSpec() []SelectSpec { - return []SelectSpec{&in.Spec} -} - -// validateContainerName validates the ContainerName -func (in *PodChaosSpec) validateContainerName(containerField *field.Path) field.ErrorList { +// validateContainerNames validates the ContainerNames +func (in *PodChaosSpec) Validate(root interface{}, path *field.Path) field.ErrorList { allErrs := field.ErrorList{} if in.Action == ContainerKillAction { - if in.ContainerName == "" { - err := fmt.Errorf("the name of container should not be empty on %s action", in.Action) - allErrs = append(allErrs, field.Invalid(containerField, in.ContainerName, err.Error())) + if len(in.ContainerSelector.ContainerNames) == 0 { + err := errors.Wrapf(errInvalidValue, "the name of container is required on %s action", in.Action) + allErrs = append(allErrs, field.Invalid(path.Child("containerNames"), in.ContainerNames, err.Error())) } } return allErrs diff --git a/api/v1alpha1/podchaos_webhook_test.go b/api/v1alpha1/podchaos_webhook_test.go index 69088c6084..d92c7349d0 100644 --- a/api/v1alpha1/podchaos_webhook_test.go +++ b/api/v1alpha1/podchaos_webhook_test.go @@ -1,20 +1,22 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -29,7 +31,7 @@ var _ = Describe("podchaos_webhook", func() { Expect(podchaos.Spec.Selector.Namespaces[0]).To(Equal(metav1.NamespaceDefault)) }) }) - Context("ChaosValidator of podchaos", func() { + Context("webhook.Validator of podchaos", func() { It("Validate", func() { type TestCase struct { @@ -38,7 +40,6 @@ var _ = Describe("podchaos_webhook", func() { execute func(chaos *PodChaos) error expect string } - duration := "400s" tcs := []TestCase{ { name: "simple ValidateCreate for ContainerKillAction", @@ -52,23 +53,8 @@ var _ = Describe("podchaos_webhook", func() { }, }, execute: func(chaos *PodChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "simple ValidateUpdate for PodKillAction", - chaos: PodChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo2", - }, - Spec: PodChaosSpec{ - Action: PodKillAction, - }, - }, - execute: func(chaos *PodChaos) error { - return chaos.ValidateUpdate(chaos) + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, @@ -81,61 +67,13 @@ var _ = Describe("podchaos_webhook", func() { }, }, execute: func(chaos *PodChaos) error { - return chaos.ValidateDelete() + _, err := chaos.ValidateDelete() + return err }, expect: "", }, { - name: "only define the Scheduler and execute PodFailureAction", - chaos: PodChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo4", - }, - Spec: PodChaosSpec{ - Scheduler: &SchedulerSpec{ - Cron: "@every 10m", - }, - Action: PodFailureAction, - }, - }, - execute: func(chaos *PodChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "only define the Duration and execute PodFailureAction", - chaos: PodChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo5", - }, - Spec: PodChaosSpec{ - Action: PodFailureAction, - Duration: &duration, - }, - }, - execute: func(chaos *PodChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "unknow action", - chaos: PodChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo6", - }, - }, - execute: func(chaos *PodChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "validate the ContainerName", + name: "validate the ContainerNames", chaos: PodChaos{ ObjectMeta: metav1.ObjectMeta{ Namespace: metav1.NamespaceDefault, @@ -146,7 +84,8 @@ var _ = Describe("podchaos_webhook", func() { }, }, execute: func(chaos *PodChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, diff --git a/api/v1alpha1/podhttpchaos_types.go b/api/v1alpha1/podhttpchaos_types.go new file mode 100644 index 0000000000..89fdb1766c --- /dev/null +++ b/api/v1alpha1/podhttpchaos_types.go @@ -0,0 +1,229 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// PodHttpChaosSpec defines the desired state of PodHttpChaos. +type PodHttpChaosSpec struct { + // Rules are a list of injection rule for http request. + // +optional + Rules []PodHttpChaosRule `json:"rules,omitempty"` + + // TLS is the tls config, + // will be override if there are multiple HTTPChaos experiments are applied + // +optional + TLS *PodHttpChaosTLS `json:"tls,omitempty"` +} + +// PodHttpChaosStatus defines the actual state of PodHttpChaos. +type PodHttpChaosStatus struct { + // Pid represents a running tproxy process id. + // +optional + Pid int64 `json:"pid,omitempty"` + + // StartTime represents the start time of a tproxy process. + // +optional + StartTime int64 `json:"startTime,omitempty"` + + // +optional + FailedMessage string `json:"failedMessage,omitempty"` + + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` +} + +// PodHttpChaosRule defines the injection rule for http. +type PodHttpChaosRule struct { + PodHttpChaosBaseRule `json:",inline"` + + // Source represents the source of current rules + Source string `json:"source,omitempty"` + + // Port represents the target port to be proxy of. + Port int32 `json:"port"` +} + +// PodHttpChaosBaseRule defines the injection rule without source and port. +type PodHttpChaosBaseRule struct { + // Target is the object to be selected and injected, . + Target PodHttpChaosTarget `json:"target"` + + // Selector contains the rules to select target. + Selector PodHttpChaosSelector `json:"selector"` + + // Actions contains rules to inject target. + Actions PodHttpChaosActions `json:"actions"` +} + +type PodHttpChaosSelector struct { + // Port is a rule to select server listening on specific port. + // +optional + Port *int32 `json:"port,omitempty"` + + // Path is a rule to select target by uri path in http request. + // +optional + Path *string `json:"path,omitempty"` + + // Method is a rule to select target by http method in request. + // +optional + Method *string `json:"method,omitempty"` + + // Code is a rule to select target by http status code in response. + // +optional + Code *int32 `json:"code,omitempty"` + + // RequestHeaders is a rule to select target by http headers in request. + // The key-value pairs represent header name and header value pairs. + // +optional + RequestHeaders map[string]string `json:"request_headers,omitempty"` + + // ResponseHeaders is a rule to select target by http headers in response. + // The key-value pairs represent header name and header value pairs. + // +optional + ResponseHeaders map[string]string `json:"response_headers,omitempty"` +} + +// PodHttpChaosActions defines possible actions of HttpChaos. +type PodHttpChaosActions struct { + // Abort is a rule to abort a http session. + // +optional + Abort *bool `json:"abort,omitempty"` + + // Delay represents the delay of the target request/response. + // A duration string is a possibly unsigned sequence of + // decimal numbers, each with optional fraction and a unit suffix, + // such as "300ms", "2h45m". + // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + // +optional + Delay *string `json:"delay,omitempty" webhook:"Delay"` + + // Replace is a rule to replace some contents in target. + // +optional + Replace *PodHttpChaosReplaceActions `json:"replace,omitempty"` + + // Patch is a rule to patch some contents in target. + // +optional + Patch *PodHttpChaosPatchActions `json:"patch,omitempty"` +} + +// PodHttpChaosPatchActions defines possible patch-actions of HttpChaos. +type PodHttpChaosPatchActions struct { + // Body is a rule to patch message body of target. + // +optional + Body *PodHttpChaosPatchBodyAction `json:"body,omitempty"` + + // Queries is a rule to append uri queries of target(Request only). + // For example: `[["foo", "bar"], ["foo", "unknown"]]`. + // +optional + Queries [][]string `json:"queries,omitempty"` + + // Headers is a rule to append http headers of target. + // For example: `[["Set-Cookie", ""], ["Set-Cookie", ""]]`. + // +optional + Headers [][]string `json:"headers,omitempty"` +} + +// PodHttpChaosPatchBodyAction defines patch body action of HttpChaos. +type PodHttpChaosPatchBodyAction struct { + // Type represents the patch type, only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) currently. + Type string `json:"type"` + + // Value is the patch contents. + Value string `json:"value"` +} + +// PodHttpChaosReplaceActions defines possible replace-actions of HttpChaos. +type PodHttpChaosReplaceActions struct { + // Path is rule to to replace uri path in http request. + // +optional + Path *string `json:"path,omitempty"` + + // Method is a rule to replace http method in request. + // +optional + Method *string `json:"method,omitempty"` + + // Code is a rule to replace http status code in response. + // +optional + Code *int32 `json:"code,omitempty"` + + // Body is a rule to replace http message body in target. + // +optional + Body []byte `json:"body,omitempty"` + + // Queries is a rule to replace uri queries in http request. + // For example, with value `{ "foo": "unknown" }`, the `/?foo=bar` will be altered to `/?foo=unknown`, + // +optional + Queries map[string]string `json:"queries,omitempty"` + + // Headers is a rule to replace http headers of target. + // The key-value pairs represent header name and header value pairs. + // +optional + Headers map[string]string `json:"headers,omitempty"` +} + +// PodHttpChaosTarget represents the type of an HttpChaos Action +type PodHttpChaosTarget string + +const ( + // PodHttpRequest represents injecting chaos for http request + PodHttpRequest PodHttpChaosTarget = "Request" + + // PodHttpResponse represents injecting chaos for http response + PodHttpResponse PodHttpChaosTarget = "Response" +) + +// PodHttpChaosTLS contains the tls config for HTTPChaos +type PodHttpChaosTLS struct { + // SecretName represents the name of required secret resource + SecretName string `json:"secretName"` + + // SecretNamespace represents the namespace of required secret resource + SecretNamespace string `json:"secretNamespace"` + + // CertName represents the data name of cert file in secret, `tls.crt` for example + CertName string `json:"certName"` + + // KeyName represents the data name of key file in secret, `tls.key` for example + KeyName string `json:"keyName"` + + // CAName represents the data name of ca file in secret, `ca.crt` for example + // +optional + CAName *string `json:"caName,omitempty"` +} + +// +kubebuilder:object:root=true + +// +chaos-mesh:base +// +chaos-mesh:webhook:enableUpdate +// +kubebuilder:subresource:status +// PodHttpChaos is the Schema for the podhttpchaos API +type PodHttpChaos struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PodHttpChaosSpec `json:"spec,omitempty"` + Status PodHttpChaosStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// PodHttpChaosList contains a list of PodHttpChaos +type PodHttpChaosList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []PodHttpChaos `json:"items"` +} diff --git a/api/v1alpha1/podiochaos_types.go b/api/v1alpha1/podiochaos_types.go index 6e18efde07..965a0607ad 100644 --- a/api/v1alpha1/podiochaos_types.go +++ b/api/v1alpha1/podiochaos_types.go @@ -1,22 +1,24 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -// PodIoChaosSpec defines the desired state of IoChaos -type PodIoChaosSpec struct { +// PodIOChaosSpec defines the desired state of IOChaos +type PodIOChaosSpec struct { // VolumeMountPath represents the target mount path // It must be a root of mount path now. // TODO: search the mount parent of any path automatically. @@ -27,22 +29,14 @@ type PodIoChaosSpec struct { // +optional Container *string `json:"container,omitempty"` - // Pid represents a running toda process id - // +optional - Pid int64 `json:"pid,omitempty"` - - // StartTime represents the start time of a toda process + // Actions are a list of IOChaos actions // +optional - StartTime int64 `json:"startTime,omitempty"` - - // Actions are a list of IoChaos actions - // +optional - Actions []IoChaosAction `json:"actions,omitempty"` + Actions []IOChaosAction `json:"actions,omitempty"` } -// IoChaosAction defines an possible action of IoChaos -type IoChaosAction struct { - Type IoChaosType `json:"type"` +// IOChaosAction defines a possible action of IOChaos +type IOChaosAction struct { + Type IOChaosType `json:"type"` Filter `json:",inline"` @@ -66,25 +60,25 @@ type IoChaosAction struct { Source string `json:"source,omitempty"` } -// IoChaosType represents the type of an IoChaos Action -type IoChaosType string +// IOChaosType represents the type of IOChaos Action +type IOChaosType string const ( // IoLatency represents injecting latency for io operation - IoLatency IoChaosType = "latency" + IoLatency IOChaosType = "latency" // IoFaults represents injecting faults for io operation - IoFaults IoChaosType = "fault" + IoFaults IOChaosType = "fault" // IoAttrOverride represents replacing attribution for io operation - IoAttrOverride IoChaosType = "attrOverride" + IoAttrOverride IOChaosType = "attrOverride" // IoMistake represents injecting incorrect read or write for io operation - IoMistake IoChaosType = "mistake" + IoMistake IOChaosType = "mistake" ) -// Filter represents a filter of IoChaos action, which will define the -// scope of an IoChaosAction +// Filter represents a filter of IOChaos action, which will define the +// scope of an IOChaosAction type Filter struct { // Path represents a glob of injecting path Path string `json:"path"` @@ -133,7 +127,7 @@ type AttrOverrideSpec struct { // MistakeSpec represents one type of mistake type MistakeSpec struct { - // Filling determines what is filled in the miskate data. + // Filling determines what is filled in the mistake data. // +optional // +kubebuilder:validation:Enum=zero;random Filling FillingType `json:"filling,omitempty"` @@ -166,7 +160,7 @@ type Timespec struct { Nsec int64 `json:"nsec"` } -// FileType represents type of a file +// FileType represents type of file type FileType string const ( @@ -216,28 +210,43 @@ const ( Bmap IoMethod = "bmap" ) -// KindPodIoChaos is the kind for pod io chaos -const KindPodIoChaos = "PodIoChaos" - +// +chaos-mesh:base +// +chaos-mesh:webhook:enableUpdate // +kubebuilder:object:root=true - -// PodIoChaos is the Schema for the podiochaos API -type PodIoChaos struct { +// +kubebuilder:subresource:status +// PodIOChaos is the Schema for the podiochaos API +type PodIOChaos struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec PodIoChaosSpec `json:"spec,omitempty"` + Spec PodIOChaosSpec `json:"spec,omitempty"` + + //+optional + Status PodIOChaosStatus `json:"status,omitempty"` +} + +type PodIOChaosStatus struct { + + // Pid represents a running toda process id + // +optional + Pid int64 `json:"pid,omitempty"` + + // StartTime represents the start time of a toda process + // +optional + StartTime int64 `json:"startTime,omitempty"` + + // +optional + FailedMessage string `json:"failedMessage,omitempty"` + + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` } // +kubebuilder:object:root=true -// PodIoChaosList contains a list of PodIoChaos -type PodIoChaosList struct { +// PodIOChaosList contains a list of PodIOChaos +type PodIOChaosList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []PodIoChaos `json:"items"` -} - -func init() { - SchemeBuilder.Register(&PodIoChaos{}, &PodIoChaosList{}) + Items []PodIOChaos `json:"items"` } diff --git a/api/v1alpha1/podiochaos_webhook.go b/api/v1alpha1/podiochaos_webhook.go deleted file mode 100644 index 55ed290d4c..0000000000 --- a/api/v1alpha1/podiochaos_webhook.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package v1alpha1 - -import ( - "context" - "encoding/json" - "net/http" - - ctrl "sigs.k8s.io/controller-runtime" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - "sigs.k8s.io/controller-runtime/pkg/webhook" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" -) - -// log is for logging in this package. -var podiochaoslog = logf.Log.WithName("rawpodio-resource") - -// +kubebuilder:object:generate=false - -// PodIoChaosHandler represents the implementation of podiochaos -type PodIoChaosHandler interface { - Apply(context.Context, *PodIoChaos) error -} - -var podIoChaosHandler PodIoChaosHandler - -// RegisterPodIoHandler registers handler into webhook -func RegisterPodIoHandler(newHandler PodIoChaosHandler) { - podIoChaosHandler = newHandler -} - -// SetupWebhookWithManager setup PodIoChaos's webhook with manager -func (in *PodIoChaos) SetupWebhookWithManager(mgr ctrl.Manager) error { - mgr.GetWebhookServer(). - Register("/mutate-chaos-mesh-org-v1alpha1-podiochaos", &webhook.Admission{Handler: &PodIoChaosWebhookRunner{}}) - return nil -} - -// +kubebuilder:webhook:path=/mutate-chaos-mesh-org-v1alpha1-podiochaos,mutating=true,failurePolicy=fail,groups=chaos-mesh.org,resources=podiochaos,verbs=create;update,versions=v1alpha1,name=mpodiochaos.kb.io - -// +kubebuilder:object:generate=false - -// PodIoChaosWebhookRunner runs webhook for podiochaos -type PodIoChaosWebhookRunner struct { - decoder *admission.Decoder -} - -// Handle will run poiochaoshandler for this resource -func (r *PodIoChaosWebhookRunner) Handle(ctx context.Context, req admission.Request) admission.Response { - chaos := &PodIoChaos{} - err := r.decoder.Decode(req, chaos) - if err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - if podIoChaosHandler != nil { - err = podIoChaosHandler.Apply(ctx, chaos) - if err != nil { - // TODO: refine the http status code - return admission.Errored(http.StatusInternalServerError, err) - } - } - - // mutate the fields in pod - - marshaledPodIoChaos, err := json.Marshal(chaos) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - return admission.PatchResponseFromRaw(req.Object.Raw, marshaledPodIoChaos) -} - -// InjectDecoder injects decoder into webhook runner -func (r *PodIoChaosWebhookRunner) InjectDecoder(d *admission.Decoder) error { - r.decoder = d - return nil -} diff --git a/api/v1alpha1/podnetworkchaos_types.go b/api/v1alpha1/podnetworkchaos_types.go index 1550b6f39f..99ff2b8a2b 100644 --- a/api/v1alpha1/podnetworkchaos_types.go +++ b/api/v1alpha1/podnetworkchaos_types.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 @@ -20,10 +22,10 @@ import ( // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. -// KindPodNetworkChaos is the kind for network chaos -const KindPodNetworkChaos = "PodNetworkChaos" - // +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +chaos-mesh:base +// +chaos-mesh:webhook:enableUpdate // PodNetworkChaos is the Schema for the PodNetworkChaos API type PodNetworkChaos struct { @@ -35,7 +37,7 @@ type PodNetworkChaos struct { // +optional // Most recently observed status of the chaos experiment about pods - Status PodNetworkChaosStatus `json:"status"` + Status PodNetworkChaosStatus `json:"status,omitempty"` } // PodNetworkChaosSpec defines the desired state of PodNetworkChaos @@ -53,18 +55,50 @@ type PodNetworkChaosSpec struct { TrafficControls []RawTrafficControl `json:"tcs,omitempty"` } +// IPSetType represents the type of IP set +type IPSetType string + +const ( + SetIPSet IPSetType = "list:set" + NetPortIPSet IPSetType = "hash:net,port" + NetIPSet IPSetType = "hash:net" +) + // RawIPSet represents an ipset on specific pod type RawIPSet struct { // The name of ipset Name string `json:"name"` - // The contents of ipset - Cidrs []string `json:"cidrs"` + IPSetType IPSetType `json:"ipsetType"` + + // The contents of ipset. + // Only available when IPSetType is NetIPSet. + // +optional + Cidrs []string `json:"cidrs,omitempty"` + + // The contents of ipset. + // Only available when IPSetType is NetPortIPSet. + // +optional + CidrAndPorts []CidrAndPort `json:"cidrAndPorts,omitempty"` + + // The contents of ipset. + // Only available when IPSetType is SetIPSet. + // +optional + SetNames []string `json:"setNames,omitempty"` // The name and namespace of the source network chaos RawRuleSource `json:",inline"` } +// CidrAndPort represents CIDR and port pair +type CidrAndPort struct { + Cidr string `json:"cidr"` + + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=65535 + Port uint16 `json:"port"` +} + // ChainDirection represents the direction of chain type ChainDirection string @@ -82,11 +116,17 @@ type RawIptables struct { Name string `json:"name"` // The name of related ipset - IPSets []string `json:"ipsets"` + // +optional + // +nullable + IPSets []string `json:"ipsets,omitempty"` // The block direction of this iptables rule Direction ChainDirection `json:"direction"` + // Device represents the network device to be affected. + // +optional + Device string `json:"device,omitempty"` + RawRuleSource `json:",inline"` } @@ -114,29 +154,43 @@ type RawTrafficControl struct { // The name and namespace of the source network chaos Source string `json:"source"` + + // Device represents the network device to be affected. + // +optional + Device string `json:"device,omitempty"` } // TcParameter represents the parameters for a traffic control chaos type TcParameter struct { // Delay represents the detail about delay action + // +ui:form:when=action=='delay' // +optional Delay *DelaySpec `json:"delay,omitempty"` // Loss represents the detail about loss action + // +ui:form:when=action=='loss' // +optional Loss *LossSpec `json:"loss,omitempty"` // DuplicateSpec represents the detail about loss action + // +ui:form:when=action=='duplicate' // +optional Duplicate *DuplicateSpec `json:"duplicate,omitempty"` // Corrupt represents the detail about corrupt action + // +ui:form:when=action=='corrupt' // +optional Corrupt *CorruptSpec `json:"corrupt,omitempty"` // Bandwidth represents the detail about bandwidth control action + // +ui:form:when=action=='bandwidth' // +optional Bandwidth *BandwidthSpec `json:"bandwidth,omitempty"` + + // Rate represents the detail about rate control action + // +ui:form:when=action=='rate' + // +optional + Rate *RateSpec `json:"rate,omitempty"` } // RawRuleSource represents the name and namespace of the source network chaos @@ -146,7 +200,9 @@ type RawRuleSource struct { // PodNetworkChaosStatus defines the observed state of PodNetworkChaos type PodNetworkChaosStatus struct { - ChaosStatus `json:",inline"` + FailedMessage string `json:"failedMessage,omitempty"` + + ObservedGeneration int64 `json:"observedGeneration,omitempty"` } // +kubebuilder:object:root=true @@ -157,39 +213,3 @@ type PodNetworkChaosList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []PodNetworkChaos `json:"items"` } - -// GetStatus returns the status of chaos -func (in *PodNetworkChaos) GetStatus() *ChaosStatus { - return &in.Status.ChaosStatus -} - -// GetChaos returns a chaos instance -func (in *PodNetworkChaos) GetChaos() *ChaosInstance { - instance := &ChaosInstance{ - Name: in.Name, - Namespace: in.Namespace, - Kind: "NetworkChaos", - StartTime: in.CreationTimestamp.Time, - Status: string(in.GetStatus().Experiment.Phase), - } - if in.DeletionTimestamp != nil { - instance.EndTime = in.DeletionTimestamp.Time - } - return instance -} - -// ListChaos returns a list of network chaos -func (in *PodNetworkChaosList) ListChaos() []*ChaosInstance { - if len(in.Items) == 0 { - return nil - } - res := make([]*ChaosInstance, 0, len(in.Items)) - for _, item := range in.Items { - res = append(res, item.GetChaos()) - } - return res -} - -func init() { - SchemeBuilder.Register(&PodNetworkChaos{}, &PodNetworkChaosList{}) -} diff --git a/api/v1alpha1/podnetworkchaos_webhook.go b/api/v1alpha1/podnetworkchaos_webhook.go deleted file mode 100644 index 10686c807c..0000000000 --- a/api/v1alpha1/podnetworkchaos_webhook.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package v1alpha1 - -import ( - "context" - - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/webhook" -) - -// log is for logging in this package. -var podnetworkchaoslog = logf.Log.WithName("rawpodnetwork-resource") - -// +kubebuilder:object:generate=false - -// PodNetworkChaosHandler represents the implementation of podnetworkchaos -type PodNetworkChaosHandler interface { - Apply(context.Context, *PodNetworkChaos) error -} - -var podNetworkChaosHandler PodNetworkChaosHandler - -// RegisterRawPodNetworkHandler registers handler into webhook -func RegisterRawPodNetworkHandler(newHandler PodNetworkChaosHandler) { - podNetworkChaosHandler = newHandler -} - -// SetupWebhookWithManager setup PodNetworkChaos's webhook with manager -func (in *PodNetworkChaos) SetupWebhookWithManager(mgr ctrl.Manager) error { - return ctrl.NewWebhookManagedBy(mgr). - For(in). - Complete() -} - -// +kubebuilder:webhook:path=/mutate-chaos-mesh-org-v1alpha1-podnetworkchaos,mutating=true,failurePolicy=fail,groups=chaos-mesh.org,resources=podnetworkchaos,verbs=create;update,versions=v1alpha1,name=mpodnetworkchaos.kb.io - -var _ webhook.Defaulter = &PodNetworkChaos{} - -// Default implements webhook.Defaulter so a webhook will be registered for the type -func (in *PodNetworkChaos) Default() { - podnetworkchaoslog.Info("default", "name", in.Name) - - // Do nothing here -} - -// +kubebuilder:webhook:verbs=create;update,path=/validate-chaos-mesh-org-v1alpha1-podnetworkchaos,mutating=false,failurePolicy=fail,groups=chaos-mesh.org,resources=podnetworkchaos,versions=v1alpha1,name=vpodnetworkchaos.kb.io - -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (in *PodNetworkChaos) ValidateCreate() error { - // TODO: validate - - podnetworkchaoslog.Info("validate create", "name", in.Name) - - if podNetworkChaosHandler != nil { - err := podNetworkChaosHandler.Apply(context.TODO(), in) - if err != nil { - return err - } - } - - return nil -} - -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (in *PodNetworkChaos) ValidateUpdate(old runtime.Object) error { - // TODO: validate - - podnetworkchaoslog.Info("validate update", "name", in.Name) - - if podNetworkChaosHandler != nil { - err := podNetworkChaosHandler.Apply(context.TODO(), in) - if err != nil { - return err - } - } - - return nil -} - -// ValidateDelete implements webhook.Validator so a webhook will be registered for the type -func (in *PodNetworkChaos) ValidateDelete() error { - podnetworkchaoslog.Info("validate delete", "name", in.Name) - - return nil -} - -// SelectSpec returns the selector config for authority validate -func (in *PodNetworkChaos) GetSelectSpec() []SelectSpec { - return nil -} diff --git a/api/v1alpha1/remote_cluster_types.go b/api/v1alpha1/remote_cluster_types.go new file mode 100644 index 0000000000..f53f9e7781 --- /dev/null +++ b/api/v1alpha1/remote_cluster_types.go @@ -0,0 +1,96 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "encoding/json" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster +// +kubebuilder:subresource:status +// +chaos-mesh:base +// RemoteCluster defines a remote cluster +type RemoteCluster struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec RemoteClusterSpec `json:"spec,omitempty"` + + // +optional + Status RemoteClusterStatus `json:"status,omitempty"` +} + +// RemoteClusterSpec defines the specification of a remote cluster +type RemoteClusterSpec struct { + Namespace string `json:"namespace"` + Version string `json:"version"` + + KubeConfig RemoteClusterKubeConfig `json:"kubeConfig"` + + // +optional + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +kubebuilder:validation:Type=object + ConfigOverride json.RawMessage `json:"configOverride,omitempty"` +} + +// RemoteClusterKubeConfig refers to a secret by which we'll use to connect remote cluster +type RemoteClusterKubeConfig struct { + SecretRef RemoteClusterSecretRef `json:"secretRef"` +} + +// RemoteClusterSecretRef refers to a secret in any namespaces +type RemoteClusterSecretRef struct { + Namespace string `json:"namespace"` + Name string `json:"name"` + + Key string `json:"key"` +} + +type RemoteClusterStatus struct { + CurrentVersion string `json:"currentVersion"` + + // Conditions represents the current condition of the remote cluster + // +optional + Conditions []RemoteClusterCondition `json:"conditions,omitempty"` + ObservedGeneration int64 `json:"observedGeneration,omitempty"` +} + +type RemoteClusterConditionType string + +var ( + RemoteClusterConditionInstalled RemoteClusterConditionType = "Installed" + RemoteClusterConditionReady RemoteClusterConditionType = "Ready" +) + +type RemoteClusterCondition struct { + Type RemoteClusterConditionType `json:"type"` + Status corev1.ConditionStatus `json:"status"` + // +optional + Reason string `json:"reason"` +} + +// RemoteClusterList contains a list of RemoteCluster +// +kubebuilder:object:root=true +type RemoteClusterList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []RemoteCluster `json:"items"` +} diff --git a/api/v1alpha1/schedule_item.go b/api/v1alpha1/schedule_item.go new file mode 100644 index 0000000000..4e7b71e7e8 --- /dev/null +++ b/api/v1alpha1/schedule_item.go @@ -0,0 +1,45 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/util/validation/field" + + gw "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" +) + +type ScheduleItem struct { + EmbedChaos `json:",inline"` + // +optional + Workflow *WorkflowSpec `json:"workflow,omitempty"` +} + +func (in EmbedChaos) Validate(path *field.Path, chaosType string) field.ErrorList { + var allErrors field.ErrorList + root, err := in.SpawnNewObject(TemplateType(chaosType)) + if err != nil { + allErrors = append(allErrors, field.Invalid(path, in, err.Error())) + return allErrors + } + + gw.Default(root) + err = in.RestoreChaosSpec(root) + if err != nil { + allErrors = append(allErrors, field.Invalid(path, in, err.Error())) + return allErrors + } + return gw.Validate(root) +} diff --git a/api/v1alpha1/schedule_type_test.go b/api/v1alpha1/schedule_type_test.go new file mode 100644 index 0000000000..a893e39f41 --- /dev/null +++ b/api/v1alpha1/schedule_type_test.go @@ -0,0 +1,90 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "context" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// These tests are written in BDD-style using Ginkgo framework. Refer to +// http://onsi.github.io/ginkgo to learn more. + +var _ = Describe("Schedule", func() { + var ( + key types.NamespacedName + created, fetched *Schedule + ) + + BeforeEach(func() { + // Add any setup steps that needs to be executed before each test + }) + + AfterEach(func() { + // Add any teardown steps that needs to be executed after each test + }) + + Context("Create API", func() { + It("should create an object successfully", func() { + key = types.NamespacedName{ + Name: "foo", + Namespace: "default", + } + + created = &Schedule{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + }, + Spec: ScheduleSpec{ + Schedule: "* * * * 1", + ScheduleItem: ScheduleItem{ + EmbedChaos: EmbedChaos{PodChaos: &PodChaosSpec{ + Action: PodKillAction, + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Mode: OneMode, + }, + }, + }, + }, + }, + ConcurrencyPolicy: ForbidConcurrent, + Type: ScheduleTypePodChaos, + }, + Status: ScheduleStatus{ + LastScheduleTime: metav1.Time{Time: time.Now()}, + }, + } + + By("creating an API obj") + Expect(k8sClient.Create(context.TODO(), created)).To(Succeed()) + + fetched = &Schedule{} + Expect(k8sClient.Get(context.TODO(), key, fetched)).To(Succeed()) + Expect(fetched).To(Equal(created)) + + By("deleting the created object") + Expect(k8sClient.Delete(context.TODO(), created)).To(Succeed()) + Expect(k8sClient.Get(context.TODO(), key, created)).ToNot(Succeed()) + }) + }) +}) diff --git a/api/v1alpha1/schedule_types.go b/api/v1alpha1/schedule_types.go new file mode 100644 index 0000000000..f1f2f3e8dc --- /dev/null +++ b/api/v1alpha1/schedule_types.go @@ -0,0 +1,126 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "github.com/robfig/cron/v3" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const KindSchedule = "Schedule" + +// +kubebuilder:object:root=true + +// Schedule is the cronly schedule object +type Schedule struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ScheduleSpec `json:"spec"` + + // +optional + Status ScheduleStatus `json:"status,omitempty"` +} + +type ConcurrencyPolicy string + +var ( + ForbidConcurrent ConcurrencyPolicy = "Forbid" + AllowConcurrent ConcurrencyPolicy = "Allow" +) + +func (c ConcurrencyPolicy) IsForbid() bool { + return c == ForbidConcurrent || c == "" +} + +func (c ConcurrencyPolicy) IsAllow() bool { + return c == AllowConcurrent +} + +// ScheduleSpec is the specification of a schedule object +type ScheduleSpec struct { + Schedule string `json:"schedule"` + + // +optional + // +nullable + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:ExclusiveMinimum=true + StartingDeadlineSeconds *int64 `json:"startingDeadlineSeconds"` + + // +optional + // +kubebuilder:default=Forbid + // +kubebuilder:validation:Enum=Forbid;Allow + ConcurrencyPolicy ConcurrencyPolicy `json:"concurrencyPolicy"` + + // +optional + // +kubebuilder:validation:Minimum=1 + HistoryLimit int `json:"historyLimit,omitempty"` + + Type ScheduleTemplateType `json:"type"` + + ScheduleItem `json:",inline"` +} + +// ScheduleStatus is the status of a schedule object +type ScheduleStatus struct { + // +optional + Active []corev1.ObjectReference `json:"active,omitempty"` + + // +optional + // +nullable + LastScheduleTime metav1.Time `json:"time,omitempty"` +} + +type ScheduleTemplateType string + +func (in *Schedule) IsPaused() bool { + if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { + return false + } + return true +} + +// +kubebuilder:object:root=true + +// ScheduleList contains a list of Schedule +type ScheduleList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Schedule `json:"items"` +} + +func (in *ScheduleList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} + +func (in *ScheduleList) DeepCopyList() GenericChaosList { + return in.DeepCopy() +} + +var StandardCronParser = cron.NewParser( + cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor, +) + +func init() { + SchemeBuilder.Register(&Schedule{}) + SchemeBuilder.Register(&ScheduleList{}) +} diff --git a/api/v1alpha1/schedule_webhook.go b/api/v1alpha1/schedule_webhook.go new file mode 100644 index 0000000000..ec3583f932 --- /dev/null +++ b/api/v1alpha1/schedule_webhook.go @@ -0,0 +1,103 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "fmt" + + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" +) + +// log is for logging in this package. +var schedulelog = logf.Log.WithName("schedule-resource") + +var _ webhook.Defaulter = &Schedule{} + +// Default implements webhook.Defaulter so a webhook will be registered for the type +func (in *Schedule) Default() { + schedulelog.Info("default", "name", in.Name) + in.Spec.ConcurrencyPolicy.Default() +} + +func (in *ConcurrencyPolicy) Default() { + if *in == "" { + *in = ForbidConcurrent + } +} + +var _ webhook.Validator = &Schedule{} + +// ValidateCreate implements webhook.Validator so a webhook will be registered for the type +func (in *Schedule) ValidateCreate() (admission.Warnings, error) { + schedulelog.Info("validate create", "name", in.Name) + return in.Validate() +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *Schedule) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + schedulelog.Info("validate update", "name", in.Name) + return in.Validate() +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *Schedule) ValidateDelete() (admission.Warnings, error) { + schedulelog.Info("validate delete", "name", in.Name) + return nil, nil +} + +// Validate validates chaos object +func (in *Schedule) Validate() ([]string, error) { + allErrs := in.Spec.Validate() + if len(allErrs) > 0 { + return nil, errors.New(allErrs.ToAggregate().Error()) + } + return nil, nil +} + +func (in *ScheduleSpec) Validate() field.ErrorList { + specField := field.NewPath("spec") + allErrs := field.ErrorList{} + allErrs = append(allErrs, in.validateSchedule(specField.Child("schedule"))...) + allErrs = append(allErrs, in.validateChaos(specField)...) + return allErrs +} + +// validateSchedule validates the cron +func (in *ScheduleSpec) validateSchedule(schedule *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + _, err := StandardCronParser.Parse(in.Schedule) + if err != nil { + allErrs = append(allErrs, field.Invalid(schedule, + in.Schedule, + fmt.Sprintf("parse schedule field error:%s", err))) + } + + return allErrs +} + +// validateChaos validates the chaos +func (in *ScheduleSpec) validateChaos(chaos *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if in.Type != ScheduleTypeWorkflow { + allErrs = append(allErrs, in.EmbedChaos.Validate(chaos, string(in.Type))...) + } + return allErrs +} diff --git a/api/v1alpha1/schedule_webhook_test.go b/api/v1alpha1/schedule_webhook_test.go new file mode 100644 index 0000000000..ca59220ed8 --- /dev/null +++ b/api/v1alpha1/schedule_webhook_test.go @@ -0,0 +1,141 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("schedule_webhook", func() { + Context("webhook.Validator of schedule", func() { + It("Validate", func() { + + type TestCase struct { + name string + schedule Schedule + execute func(schedule *Schedule) error + expect string + } + tcs := []TestCase{ + { + name: "validation for normal chaos", + schedule: Schedule{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo1", + }, + Spec: ScheduleSpec{ + ScheduleItem: ScheduleItem{EmbedChaos: EmbedChaos{PodChaos: &PodChaosSpec{ + Action: ContainerKillAction, + }}}, + Type: ScheduleTypePodChaos, + Schedule: "@every 5s", + }, + }, + execute: func(schedule *Schedule) error { + _, err := schedule.ValidateCreate() + return err + }, + expect: "error", + }, + { + name: "validation for schedule", + schedule: Schedule{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo2", + }, + Spec: ScheduleSpec{ + ScheduleItem: ScheduleItem{EmbedChaos: EmbedChaos{PodChaos: &PodChaosSpec{}}}, + Type: ScheduleTypePodChaos, + Schedule: "@every -5s", + }, + }, + execute: func(schedule *Schedule) error { + _, err := schedule.ValidateCreate() + return err + }, + expect: "", + }, + { + name: "validation for workflow", + schedule: Schedule{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo3", + }, + Spec: ScheduleSpec{ + ScheduleItem: ScheduleItem{Workflow: &WorkflowSpec{}}, + Type: ScheduleTypeWorkflow, + Schedule: "@every 5s", + }, + }, + execute: func(schedule *Schedule) error { + _, err := schedule.ValidateCreate() + return err + }, + expect: "", + }, + { + name: "validation for cron with second", + schedule: Schedule{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo3", + }, + Spec: ScheduleSpec{ + ScheduleItem: ScheduleItem{Workflow: &WorkflowSpec{}}, + Type: ScheduleTypeWorkflow, + Schedule: "*/1 * * * * *", + }, + }, + execute: func(schedule *Schedule) error { + _, err := schedule.ValidateCreate() + return err + }, + expect: "", + }, + } + + for _, tc := range tcs { + err := tc.execute(&tc.schedule) + if tc.expect == "error" { + Expect(err).To(HaveOccurred()) + } else { + Expect(err).NotTo(HaveOccurred()) + } + } + }) + }) + + Context("webhook.Default of schedule", func() { + s := Schedule{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "foo3", + }, + Spec: ScheduleSpec{ + ScheduleItem: ScheduleItem{Workflow: &WorkflowSpec{}}, + Type: ScheduleTypeWorkflow, + Schedule: "*/1 * * * * *", + }, + } + s.Default() + Expect(s.Spec.ConcurrencyPolicy).To(Equal(ForbidConcurrent)) + }) +}) diff --git a/api/v1alpha1/selector.go b/api/v1alpha1/selector.go new file mode 100644 index 0000000000..83cc1704ff --- /dev/null +++ b/api/v1alpha1/selector.go @@ -0,0 +1,137 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// LabelSelectorRequirements is list of LabelSelectorRequirement +type LabelSelectorRequirements []metav1.LabelSelectorRequirement + +// SelectorMode represents the mode to run chaos action. +type SelectorMode string + +const ( + // OneMode represents that the system will do the chaos action on one object selected randomly. + OneMode SelectorMode = "one" + // AllMode represents that the system will do the chaos action on all objects + // regardless of status (not ready or not running pods includes). + // Use this label carefully. + AllMode SelectorMode = "all" + // FixedMode represents that the system will do the chaos action on a specific number of running objects. + FixedMode SelectorMode = "fixed" + // FixedPercentMode to specify a fixed % that can be inject chaos action. + FixedPercentMode SelectorMode = "fixed-percent" + // RandomMaxPercentMode to specify a maximum % that can be inject chaos action. + RandomMaxPercentMode SelectorMode = "random-max-percent" +) + +// GenericSelectorSpec defines some selectors to select objects. +type GenericSelectorSpec struct { + // Namespaces is a set of namespace to which objects belong. + // +optional + Namespaces []string `json:"namespaces,omitempty"` + + // Map of string keys and values that can be used to select objects. + // A selector based on fields. + // +optional + FieldSelectors map[string]string `json:"fieldSelectors,omitempty"` + + // Map of string keys and values that can be used to select objects. + // A selector based on labels. + // +optional + LabelSelectors map[string]string `json:"labelSelectors,omitempty"` + + // a slice of label selector expressions that can be used to select objects. + // A list of selectors based on set-based label expressions. + // +optional + ExpressionSelectors LabelSelectorRequirements `json:"expressionSelectors,omitempty" swaggerignore:"true"` + + // Map of string keys and values that can be used to select objects. + // A selector based on annotations. + // +optional + AnnotationSelectors map[string]string `json:"annotationSelectors,omitempty"` +} + +// PodSelectorSpec defines the some selectors to select objects. +// If the all selectors are empty, all objects will be used in chaos experiment. +type PodSelectorSpec struct { + GenericSelectorSpec `json:",inline"` + + // Nodes is a set of node name and objects must belong to these nodes. + // +optional + Nodes []string `json:"nodes,omitempty"` + + // Pods is a map of string keys and a set values that used to select pods. + // The key defines the namespace which pods belong, + // and the each values is a set of pod names. + // +optional + Pods map[string][]string `json:"pods,omitempty"` + + // Map of string keys and values that can be used to select nodes. + // Selector which must match a node's labels, + // and objects must belong to these selected nodes. + // +optional + NodeSelectors map[string]string `json:"nodeSelectors,omitempty"` + + // PodPhaseSelectors is a set of condition of a pod at the current time. + // supported value: Pending / Running / Succeeded / Failed / Unknown + // +optional + PodPhaseSelectors []string `json:"podPhaseSelectors,omitempty"` +} + +func (in *PodSelectorSpec) DefaultNamespace(namespace string) { + if len(in.Namespaces) == 0 { + in.Namespaces = []string{namespace} + } +} + +type PodSelector struct { + // Selector is used to select pods that are used to inject chaos action. + Selector PodSelectorSpec `json:"selector"` + + // Mode defines the mode to run chaos action. + // Supported mode: one / all / fixed / fixed-percent / random-max-percent + // +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent + Mode SelectorMode `json:"mode"` + + // Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + // If `FixedMode`, provide an integer of pods to do chaos action. + // If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + // IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action + // +optional + Value string `json:"value,omitempty"` +} + +type ContainerSelector struct { + PodSelector `json:",inline"` + + // ContainerNames indicates list of the name of affected container. + // If not set, the first container will be injected + // +optional + ContainerNames []string `json:"containerNames,omitempty"` +} + +// ClusterScoped returns true if the selector selects Pods in the cluster +func (in PodSelectorSpec) ClusterScoped() bool { + // in fact, this will never happened, will add namespace if it is empty, so len(s.Namespaces) can not be 0, + // but still add judgentment here for safe + // https://github.com/chaos-mesh/chaos-mesh/blob/478d00d01bb0f9fb08a1085428a7da8c8f9df4e8/api/v1alpha1/common_webhook.go#L22 + if len(in.Namespaces) == 0 && len(in.Pods) == 0 { + return true + } + + return false +} diff --git a/api/v1alpha1/statuscheck_types.go b/api/v1alpha1/statuscheck_types.go new file mode 100644 index 0000000000..776717ac53 --- /dev/null +++ b/api/v1alpha1/statuscheck_types.go @@ -0,0 +1,277 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "net/http" + "time" + + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +chaos-mesh:base +type StatusCheck struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the behavior of a status check + Spec StatusCheckSpec `json:"spec"` + + // +optional + // Most recently observed status of status check + Status StatusCheckStatus `json:"status,omitempty"` +} + +type StatusCheckMode string + +const ( + // StatusCheckSynchronous means the status check will exit + // immediately after success or failure. + StatusCheckSynchronous StatusCheckMode = "Synchronous" + // StatusCheckContinuous means the status check will continue to + // execute until the duration is exceeded or the status check fails. + StatusCheckContinuous StatusCheckMode = "Continuous" +) + +type StatusCheckType string + +const ( + TypeHTTP StatusCheckType = "HTTP" +) + +type StatusCheckSpec struct { + // Mode defines the execution mode of the status check. + // Support type: Synchronous / Continuous + // +optional + // +kubebuilder:validation:Enum=Synchronous;Continuous + Mode StatusCheckMode `json:"mode,omitempty"` + + // Type defines the specific status check type. + // Support type: HTTP + // +kubebuilder:default=HTTP + // +kubebuilder:validation:Enum=HTTP + Type StatusCheckType `json:"type"` + + // Duration defines the duration of the whole status check if the + // number of failed execution does not exceed the failure threshold. + // Duration is available to both `Synchronous` and `Continuous` mode. + // 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". + // +optional + Duration *string `json:"duration,omitempty" webhook:"Duration"` + + // TimeoutSeconds defines the number of seconds after which + // an execution of status check times out. + // +optional + // +kubebuilder:default=1 + // +kubebuilder:validation:Minimum=1 + TimeoutSeconds int `json:"timeoutSeconds,omitempty"` + + // IntervalSeconds defines how often (in seconds) to perform + // an execution of status check. + // +optional + // +kubebuilder:default=10 + // +kubebuilder:validation:Minimum=1 + IntervalSeconds int `json:"intervalSeconds,omitempty"` + + // FailureThreshold defines the minimum consecutive failure + // for the status check to be considered failed. + // +optional + // +kubebuilder:default=3 + // +kubebuilder:validation:Minimum=1 + FailureThreshold int `json:"failureThreshold,omitempty"` + + // SuccessThreshold defines the minimum consecutive successes + // for the status check to be considered successful. + // SuccessThreshold only works for `Synchronous` mode. + // +optional + // +kubebuilder:default=1 + // +kubebuilder:validation:Minimum=1 + SuccessThreshold int `json:"successThreshold,omitempty"` + + // RecordsHistoryLimit defines the number of record to retain. + // +optional + // +kubebuilder:default=100 + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=1000 + RecordsHistoryLimit int `json:"recordsHistoryLimit,omitempty"` + + // +optional + *EmbedStatusCheck `json:",inline,omitempty"` +} + +type StatusCheckStatus struct { + // StartTime represents time when the status check started to execute. + // +optional + StartTime *metav1.Time `json:"startTime,omitempty"` + + // CompletionTime represents time when the status check was completed. + // +optional + CompletionTime *metav1.Time `json:"completionTime,omitempty"` + + // Count represents the total number of the status check executed. + // +optional + Count int64 `json:"count,omitempty"` + + // Conditions represents the latest available observations of a StatusCheck's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + Conditions []StatusCheckCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + // Records contains the history of the execution of StatusCheck. + // +optional + Records []StatusCheckRecord `json:"records,omitempty"` +} + +type StatusCheckOutcome string + +const ( + StatusCheckOutcomeSuccess StatusCheckOutcome = "Success" + StatusCheckOutcomeFailure StatusCheckOutcome = "Failure" +) + +type StatusCheckRecord struct { + StartTime *metav1.Time `json:"startTime"` + Outcome StatusCheckOutcome `json:"outcome"` +} + +type StatusCheckConditionType string + +const ( + // StatusCheckConditionCompleted means the status check is completed. + // It will be `True`, in the following scenarios: + // 1. the duration is exceeded + // 2. the failure threshold is exceeded + // 3. the success threshold is exceeded (only the `Synchronous` mode) + StatusCheckConditionCompleted StatusCheckConditionType = "Completed" + // StatusCheckConditionDurationExceed means the duration is exceeded. + StatusCheckConditionDurationExceed StatusCheckConditionType = "DurationExceed" + // StatusCheckConditionFailureThresholdExceed means the failure threshold is exceeded. + StatusCheckConditionFailureThresholdExceed StatusCheckConditionType = "FailureThresholdExceed" + // StatusCheckConditionSuccessThresholdExceed means the success threshold is exceeded. + StatusCheckConditionSuccessThresholdExceed StatusCheckConditionType = "SuccessThresholdExceed" +) + +type StatusCheckReason string + +const ( + StatusCheckDurationExceed StatusCheckReason = "StatusCheckDurationExceed" + StatusCheckFailureThresholdExceed StatusCheckReason = "StatusCheckFailureThresholdExceed" + StatusCheckSuccessThresholdExceed StatusCheckReason = "StatusCheckSuccessThresholdExceed" + StatusCheckExecutionFailed StatusCheckReason = "StatusCheckExecutionFailed" + StatusCheckExecutionSucceed StatusCheckReason = "StatusCheckExecutionSucceed" +) + +type StatusCheckCondition struct { + Type StatusCheckConditionType `json:"type"` + Status corev1.ConditionStatus `json:"status"` + Reason StatusCheckReason `json:"reason"` + LastProbeTime *metav1.Time `json:"lastProbeTime"` + LastTransitionTime *metav1.Time `json:"lastTransitionTime"` +} + +type EmbedStatusCheck struct { + // +optional + HTTPStatusCheck *HTTPStatusCheck `json:"http,omitempty"` +} + +type HTTPCriteria struct { + // StatusCode defines the expected http status code for the request. + // A statusCode string could be a single code (e.g. 200), or + // an inclusive range (e.g. 200-400, both `200` and `400` are included). + StatusCode string `json:"statusCode" webhook:"StatusCode"` + // TODO: support response body +} + +type HTTPRequestMethod string + +const ( + MethodGet = "GET" + MethodPost = "POST" +) + +type HTTPStatusCheck struct { + RequestUrl string `json:"url"` + + // +optional + // +kubebuilder:validation:Enum=GET;POST + // +kubebuilder:default=GET + RequestMethod HTTPRequestMethod `json:"method,omitempty"` + // +optional + RequestHeaders http.Header `json:"headers,omitempty"` + // +optional + RequestBody string `json:"body,omitempty"` + // Criteria defines how to determine the result of the status check. + Criteria HTTPCriteria `json:"criteria"` +} + +// StatusCheckList contains a list of StatusCheck +// +kubebuilder:object:root=true +type StatusCheckList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []StatusCheck `json:"items"` +} + +func (in *StatusCheckSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { + return nil, nil + } + duration, err := time.ParseDuration(*in.Duration) + if err != nil { + return nil, errors.Wrapf(err, "parse duration %s", *in.Duration) + } + return &duration, nil +} + +func (in *StatusCheck) DurationExceed(now time.Time) (bool, time.Duration, error) { + if in.Status.StartTime == nil { + return false, 0, nil + } + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, errors.Wrap(err, "get duration") + } + + if duration != nil { + stopTime := in.Status.StartTime.Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } + + return false, stopTime.Sub(now), nil + } + + return false, 0, nil +} + +// IsCompleted checks if the status check is completed, according to the StatusCheckConditionCompleted condition. +func (in *StatusCheck) IsCompleted() bool { + for _, condition := range in.Status.Conditions { + if condition.Type == StatusCheckConditionCompleted && + condition.Status == corev1.ConditionTrue { + return true + } + } + return false +} diff --git a/api/v1alpha1/statuscheck_types_test.go b/api/v1alpha1/statuscheck_types_test.go new file mode 100644 index 0000000000..8ed86449f2 --- /dev/null +++ b/api/v1alpha1/statuscheck_types_test.go @@ -0,0 +1,82 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// These tests are written in BDD-style using Ginkgo framework. Refer to +// http://onsi.github.io/ginkgo to learn more. + +var _ = Describe("StatusCheck", func() { + var ( + key types.NamespacedName + created, fetched *StatusCheck + ) + + BeforeEach(func() { + // Add any setup steps that needs to be executed before each test + }) + + AfterEach(func() { + // Add any teardown steps that needs to be executed after each test + }) + + Context("Create API", func() { + It("should create an object successfully", func() { + key = types.NamespacedName{ + Name: "foo", + Namespace: "default", + } + + created = &StatusCheck{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + }, + Spec: StatusCheckSpec{ + Mode: StatusCheckSynchronous, + Type: TypeHTTP, + EmbedStatusCheck: &EmbedStatusCheck{ + HTTPStatusCheck: &HTTPStatusCheck{ + RequestUrl: "http://1.1.1.1:8080/health", + Criteria: HTTPCriteria{ + StatusCode: "200", + }, + }, + }, + }, + } + + By("creating an API obj") + Expect(k8sClient.Create(context.TODO(), created)).To(Succeed()) + + fetched = &StatusCheck{} + Expect(k8sClient.Get(context.TODO(), key, fetched)).To(Succeed()) + Expect(fetched).To(Equal(created)) + + By("deleting the created object") + Expect(k8sClient.Delete(context.TODO(), created)).To(Succeed()) + Expect(k8sClient.Get(context.TODO(), key, created)).ToNot(Succeed()) + }) + }) +}) diff --git a/api/v1alpha1/statuscheck_webhook.go b/api/v1alpha1/statuscheck_webhook.go new file mode 100644 index 0000000000..fe6f532c93 --- /dev/null +++ b/api/v1alpha1/statuscheck_webhook.go @@ -0,0 +1,118 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "fmt" + "net/url" + "reflect" + "strconv" + "strings" + + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/util/validation/field" + + "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" +) + +func (in *StatusCheckSpec) Default(root interface{}, field *reflect.StructField) { + if in.Mode == "" { + in.Mode = StatusCheckSynchronous + } +} + +func (in *StatusCheckSpec) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if in.Type == TypeHTTP { + if in.EmbedStatusCheck == nil || in.EmbedStatusCheck.HTTPStatusCheck == nil { + allErrs = append(allErrs, field.Invalid(path.Child("http"), nil, "the detail of http status check is required")) + } + } else { + allErrs = append(allErrs, field.Invalid(path.Child("type"), in.Type, fmt.Sprintf("unrecognized type: %s", in.Type))) + } + + return allErrs +} + +func (in *HTTPStatusCheck) Validate(root interface{}, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if in.RequestUrl == "" { + allErrs = append(allErrs, field.Invalid(path.Child("url"), in.RequestUrl, "request url is required")) + return allErrs + } + + if _, err := url.ParseRequestURI(in.RequestUrl); err != nil { + allErrs = append(allErrs, field.Invalid(path.Child("url"), in.RequestUrl, "invalid http request url")) + } + return allErrs +} + +type StatusCode string + +func (in *StatusCode) Validate(root interface{}, path *field.Path) field.ErrorList { + packError := func(err error) field.ErrorList { + return field.ErrorList{ + field.Invalid(path, in, fmt.Sprintf("incorrect status code format: %s", err.Error())), + } + } + + codeStr := string(*in) + if codeStr == "" { + return field.ErrorList{ + field.Invalid(path, in, "status code is required"), + } + } + + if code, err := strconv.Atoi(codeStr); err == nil { + if !validateHTTPStatusCode(code) { + return packError(errors.New("invalid status code")) + } + } else { + index := strings.Index(codeStr, "-") + if index == -1 { + return packError(errors.New("not a single number or a range")) + } + + validateRange := func(codeStr string) error { + code, err := strconv.Atoi(codeStr) + if err != nil { + return err + } + if !validateHTTPStatusCode(code) { + return errors.Errorf("invalid status code range, code: %d", code) + } + return nil + } + start := codeStr[:index] + end := codeStr[index+1:] + if err := validateRange(start); err != nil { + return packError(err) + } + if err := validateRange(end); err != nil { + return packError(err) + } + } + return nil +} + +func validateHTTPStatusCode(code int) bool { + return code > 0 && code < 1000 +} + +func init() { + genericwebhook.Register("StatusCode", reflect.PtrTo(reflect.TypeOf(StatusCode("")))) +} diff --git a/api/v1alpha1/statuscheck_webhook_test.go b/api/v1alpha1/statuscheck_webhook_test.go new file mode 100644 index 0000000000..de69abaa31 --- /dev/null +++ b/api/v1alpha1/statuscheck_webhook_test.go @@ -0,0 +1,148 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("statuscheck_webhook", func() { + Context("webhook.Defaultor of statuscheck", func() { + It("Default", func() { + statusCheck := &StatusCheck{} + statusCheck.Default() + Expect(statusCheck.Spec.Mode).To(Equal(StatusCheckSynchronous)) + }) + }) + Context("webhook.Validator of statuscheck", func() { + It("Validate", func() { + type TestCase struct { + name string + statusCheck StatusCheck + expect string + } + tcs := []TestCase{ + { + name: "simple Validate", + statusCheck: StatusCheck{ + Spec: StatusCheckSpec{ + Type: TypeHTTP, + EmbedStatusCheck: &EmbedStatusCheck{ + HTTPStatusCheck: &HTTPStatusCheck{ + RequestUrl: "http://1.1.1.1", + Criteria: HTTPCriteria{ + StatusCode: "200", + }, + }, + }, + }, + }, + expect: "", + }, + { + name: "simple Validate with status code range", + statusCheck: StatusCheck{ + Spec: StatusCheckSpec{ + Type: TypeHTTP, + EmbedStatusCheck: &EmbedStatusCheck{ + HTTPStatusCheck: &HTTPStatusCheck{ + RequestUrl: "http://1.1.1.1", + Criteria: HTTPCriteria{ + StatusCode: "200-400", + }, + }, + }, + }, + }, + expect: "", + }, + { + name: "unknown type", + statusCheck: StatusCheck{ + Spec: StatusCheckSpec{ + Type: "CMD", + }, + }, + expect: "unrecognized type", + }, + { + name: "invalid request url", + statusCheck: StatusCheck{ + Spec: StatusCheckSpec{ + Type: TypeHTTP, + EmbedStatusCheck: &EmbedStatusCheck{ + HTTPStatusCheck: &HTTPStatusCheck{ + RequestUrl: "1.1.1.1", + Criteria: HTTPCriteria{ + StatusCode: "-1", + }, + }, + }, + }, + }, + expect: "invalid http request url", + }, + { + name: "invalid status code", + statusCheck: StatusCheck{ + Spec: StatusCheckSpec{ + Type: TypeHTTP, + EmbedStatusCheck: &EmbedStatusCheck{ + HTTPStatusCheck: &HTTPStatusCheck{ + RequestUrl: "http://1.1.1.1", + Criteria: HTTPCriteria{ + StatusCode: "-1", + }, + }, + }, + }, + }, + expect: "invalid status code", + }, + { + name: "invalid status code range", + statusCheck: StatusCheck{ + Spec: StatusCheckSpec{ + Type: TypeHTTP, + EmbedStatusCheck: &EmbedStatusCheck{ + HTTPStatusCheck: &HTTPStatusCheck{ + RequestUrl: "http://1.1.1.1", + Criteria: HTTPCriteria{ + StatusCode: "200-x", + }, + }, + }, + }, + }, + expect: "incorrect status code format", + }, + } + + for _, tc := range tcs { + _, err := tc.statusCheck.ValidateCreate() + if len(tc.expect) != 0 { + Expect(err).To(HaveOccurred()) + Expect(strings.Contains(err.Error(), tc.expect)).To(BeTrue(), "expected error: %s, got: %s", tc.expect, err.Error()) + } else { + Expect(err).ToNot(HaveOccurred()) + } + } + }) + }) +}) diff --git a/api/v1alpha1/statuschecktemplate_types.go b/api/v1alpha1/statuschecktemplate_types.go new file mode 100644 index 0000000000..bb91d846a1 --- /dev/null +++ b/api/v1alpha1/statuschecktemplate_types.go @@ -0,0 +1,91 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "fmt" + + v1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" +) + +const ( + // TemplateTypeLabelKey is a label that represents the template type. + TemplateTypeLabelKey = "template.chaos-mesh.org/type" + // ManagedByLabelKey is a label that represents the tool being used + // to manage the operation of the object. + ManagedByLabelKey = "app.kubernetes.io/managed-by" + // ManagedByLabelValue is the value that represents the object is + // managed by Chaos Mesh. + ManagedByLabelValue = "chaos-mesh" + + // TemplateNameAnnotationKey is an annotation that represents + // the real name of the template. + TemplateNameAnnotationKey = "template.chaos-mesh.org/name" + // TemplateDescriptionAnnotationKey is an annotation that represents + // the description of the template. + TemplateDescriptionAnnotationKey = "template.chaos-mesh.org/description" + + // PrefixStatusCheckTemplate is the prefix of the name of a StatusCheckTemplate. + PrefixStatusCheckTemplate = "template-status-check" + // StatusCheckTemplateKey is the key that status check spec + // saved in the template ConfigMap. + StatusCheckTemplateKey = "spec" +) + +// StatusCheckTemplate represents a template of status check. +// A statusCheckTemplate would save in the ConfigMap named `template-status-check-`. +// +kubebuilder:object:generate=false +type StatusCheckTemplate struct { + StatusCheckSpec `json:",inline"` +} + +func GetTemplateName(cm v1.ConfigMap) string { + return cm.Annotations[TemplateNameAnnotationKey] +} + +func GetTemplateDescription(cm v1.ConfigMap) string { + return cm.Annotations[TemplateDescriptionAnnotationKey] +} + +func GenerateTemplateName(name string) string { + return fmt.Sprintf("%s-%s", PrefixStatusCheckTemplate, name) +} + +func IsStatusCheckTemplate(cm v1.ConfigMap) bool { + return cm.Labels[ManagedByLabelKey] == ManagedByLabelValue && + cm.Labels[TemplateTypeLabelKey] == KindStatusCheck && + cm.Name == GenerateTemplateName(cm.Annotations[TemplateNameAnnotationKey]) +} + +func (in *StatusCheckTemplate) Validate() (admission.Warnings, error) { + statusCheck := &StatusCheck{ + Spec: in.StatusCheckSpec, + } + return statusCheck.Validate() +} + +func (in *StatusCheckTemplate) Default() { + if in == nil { + return + } + + statusCheck := &StatusCheck{ + Spec: in.StatusCheckSpec, + } + statusCheck.Default() + in.StatusCheckSpec = *statusCheck.Spec.DeepCopy() +} diff --git a/api/v1alpha1/stresschaos_types.go b/api/v1alpha1/stresschaos_types.go index c707e8a436..9dbcf07c68 100644 --- a/api/v1alpha1/stresschaos_types.go +++ b/api/v1alpha1/stresschaos_types.go @@ -1,29 +1,31 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "fmt" - "github.com/docker/go-units" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // Stress chaos is a chaos to generate plenty of stresses over a collection of pods. // +kubebuilder:object:root=true -// +chaos-mesh:base +// +kubebuilder:printcolumn:name="duration",type=string,JSONPath=`.spec.duration` +// +chaos-mesh:experiment // StressChaos is the Schema for the stresschaos API type StressChaos struct { @@ -35,24 +37,16 @@ type StressChaos struct { // +optional // Most recently observed status of the time chaos experiment - Status StressChaosStatus `json:"status"` + Status StressChaosStatus `json:"status,omitempty"` } +var _ InnerObjectWithCustomStatus = (*StressChaos)(nil) +var _ InnerObjectWithSelector = (*StressChaos)(nil) +var _ InnerObject = (*StressChaos)(nil) + // StressChaosSpec defines the desired state of StressChaos type StressChaosSpec struct { - // Mode defines the mode to run chaos action. - // Supported mode: one / all / fixed / fixed-percent / random-max-percent - Mode PodMode `json:"mode"` - - // Value is required when the mode is set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - // If `FixedPodMode`, provide an integer of pods to do chaos action. - // If `FixedPercentPodMod`, provide a number from 0-100 to specify the max % of pods the server can do chaos action. - // If `RandomMaxPercentPodMod`, provide a number from 0-100 to specify the % of pods to do chaos action - // +optional - Value string `json:"value"` - - // Selector is used to select pods that are used to inject chaos action. - Selector SelectorSpec `json:"selector"` + ContainerSelector `json:",inline"` // Stressors defines plenty of stressors supported to stress system components out. // You can use one or more of them to make up various kinds of stresses. At least @@ -69,32 +63,13 @@ type StressChaosSpec struct { // +optional StressngStressors string `json:"stressngStressors,omitempty"` - // ContainerName indicates the target container to inject stress in - // +optional - ContainerName *string `json:"containerName,omitempty"` - // Duration represents the duration of the chaos action // +optional - Duration *string `json:"duration,omitempty"` + Duration *string `json:"duration,omitempty" webhook:"Duration"` - // Scheduler defines some schedule rules to control the running time of the chaos experiment about time. + // RemoteCluster represents the remote cluster where the chaos will be deployed // +optional - Scheduler *SchedulerSpec `json:"scheduler,omitempty"` -} - -// GetSelector is a getter for Selector (for implementing SelectSpec) -func (in *StressChaosSpec) GetSelector() SelectorSpec { - return in.Selector -} - -// GetMode is a getter for Mode (for implementing SelectSpec) -func (in *StressChaosSpec) GetMode() PodMode { - return in.Mode -} - -// GetValue is a getter for Value (for implementing SelectSpec) -func (in *StressChaosSpec) GetValue() string { - return in.Value + RemoteCluster string `json:"remoteCluster,omitempty"` } // StressChaosStatus defines the observed state of StressChaos @@ -107,12 +82,18 @@ type StressChaosStatus struct { // StressInstance is an instance generates stresses type StressInstance struct { - // UID is the instance identifier + // UID is the stress-ng identifier + // +optional + UID string `json:"uid,omitempty"` + // MemoryUID is the memStress identifier // +optional - UID string `json:"uid"` - // StartTime specifies when the instance starts + MemoryUID string `json:"memoryUid,omitempty"` + // StartTime specifies when the stress-ng starts // +optional - StartTime *metav1.Time `json:"startTime"` + StartTime *metav1.Time `json:"startTime,omitempty"` + // MemoryStartTime specifies when the memStress starts + // +optional + MemoryStartTime *metav1.Time `json:"memoryStartTime,omitempty"` } // Stressors defines plenty of stressors supported to stress system components out. @@ -120,67 +101,78 @@ type StressInstance struct { type Stressors struct { // MemoryStressor stresses virtual memory out // +optional - MemoryStressor *MemoryStressor `json:"memory,omitempty" mapstructure:"memory"` + MemoryStressor *MemoryStressor `json:"memory,omitempty"` // CPUStressor stresses CPU out // +optional - CPUStressor *CPUStressor `json:"cpu,omitempty" mapstructure:"cpu"` + CPUStressor *CPUStressor `json:"cpu,omitempty"` } // Normalize the stressors to comply with stress-ng -func (in *Stressors) Normalize() (string, error) { - stressors := "" - if in.MemoryStressor != nil { - stressors += fmt.Sprintf(" --vm %d --vm-keep", in.MemoryStressor.Workers) +func (in *Stressors) Normalize() (cpuStressors string, memoryStressors string, err error) { + cpuStressors = "" + memoryStressors = "" + err = nil + + if in.MemoryStressor != nil && in.MemoryStressor.Workers != 0 { + memoryStressors += fmt.Sprintf(" --workers %d", in.MemoryStressor.Workers) + if len(in.MemoryStressor.Size) != 0 { - if in.MemoryStressor.Size[len(in.MemoryStressor.Size)-1] != '%' { - size, err := units.FromHumanSize(in.MemoryStressor.Size) - if err != nil { - return "", err - } - stressors += fmt.Sprintf(" --vm-bytes %d", size) - } else { - stressors += fmt.Sprintf("--vm-bytes %s", - in.MemoryStressor.Size) - } + memoryStressors += fmt.Sprintf(" --size %s", in.MemoryStressor.Size) } if in.MemoryStressor.Options != nil { for _, v := range in.MemoryStressor.Options { - stressors += fmt.Sprintf(" %v ", v) + memoryStressors += fmt.Sprintf(" %v ", v) } } } - if in.CPUStressor != nil { - stressors += fmt.Sprintf(" --cpu %d", in.CPUStressor.Workers) + if in.CPUStressor != nil && in.CPUStressor.Workers != 0 { + // Without these two args, we may not reach the resource limit of pod, + // especially when we set cpu workers > 1 + // More details see: https://github.com/chaos-mesh/chaos-mesh/issues/3100 + cpuStressors += " --cpu-load-slice 10 --cpu-method sqrt" + cpuStressors += fmt.Sprintf(" --cpu %d", in.CPUStressor.Workers) + if in.CPUStressor.Load != nil { - stressors += fmt.Sprintf(" --cpu-load %d", + cpuStressors += fmt.Sprintf(" --cpu-load %d", *in.CPUStressor.Load) } if in.CPUStressor.Options != nil { for _, v := range in.CPUStressor.Options { - stressors += fmt.Sprintf(" %v ", v) + cpuStressors += fmt.Sprintf(" %v ", v) } } } - return stressors, nil + + return } // Stressor defines common configurations of a stressor type Stressor struct { // Workers specifies N workers to apply the stressor. + // Maximum 8192 workers can run by stress-ng + // +kubebuilder:validation:Maximum=8192 Workers int `json:"workers"` } // MemoryStressor defines how to stress memory out type MemoryStressor struct { - Stressor `json:",inline" mapstructure:",squash"` + Stressor `json:",inline"` // Size specifies N bytes consumed per vm worker, default is the total available memory. // One can specify the size as % of total available memory or in units of B, KB/KiB, // MB/MiB, GB/GiB, TB/TiB. // +optional - Size string `json:"size,omitempty"` + Size string `json:"size,omitempty" webhook:"Bytes"` + + // OOMScoreAdj sets the oom_score_adj of the stress process. See `man 5 proc` to know more + // about this option. + // +kubebuilder:validation:Minimum=-1000 + // +kubebuilder:validation:Maximum=1000 + // +kubebuilder:default=0 + // +optional + OOMScoreAdj int `json:"oomScoreAdj,omitempty"` // extend stress-ng options // +optional @@ -189,9 +181,11 @@ type MemoryStressor struct { // CPUStressor defines how to stress CPU out type CPUStressor struct { - Stressor `json:",inline" mapstructure:",squash"` + Stressor `json:",inline"` // Load specifies P percent loading per CPU worker. 0 is effectively a sleep (no load) and 100 // is full loading. + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=100 // +optional Load *int `json:"load,omitempty"` @@ -199,3 +193,13 @@ type CPUStressor struct { // +optional Options []string `json:"options,omitempty"` } + +func (obj *StressChaos) GetSelectorSpecs() map[string]interface{} { + return map[string]interface{}{ + ".": &obj.Spec.ContainerSelector, + } +} + +func (obj *StressChaos) GetCustomStatus() interface{} { + return &obj.Status.Instances +} diff --git a/api/v1alpha1/stresschaos_types_test.go b/api/v1alpha1/stresschaos_types_test.go index d07a04887d..c9647341e4 100644 --- a/api/v1alpha1/stresschaos_types_test.go +++ b/api/v1alpha1/stresschaos_types_test.go @@ -1,22 +1,24 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "context" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -43,6 +45,11 @@ var _ = Describe("StressChaos", func() { Namespace: "default", }, Spec: StressChaosSpec{ + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Mode: OneMode, + }, + }, Stressors: &Stressors{MemoryStressor: &MemoryStressor{Stressor: Stressor{Workers: 1}}}, }, } diff --git a/api/v1alpha1/stresschaos_webhook.go b/api/v1alpha1/stresschaos_webhook.go index 7ca4b60197..2c4beb00b7 100644 --- a/api/v1alpha1/stresschaos_webhook.go +++ b/api/v1alpha1/stresschaos_webhook.go @@ -1,185 +1,102 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - "errors" "fmt" + "reflect" "strconv" "github.com/docker/go-units" - "k8s.io/apimachinery/pkg/runtime" + "github.com/pkg/errors" "k8s.io/apimachinery/pkg/util/validation/field" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/webhook" -) - -// +kubebuilder:object:generate=false - -// Validateable defines how a resource is validated -type Validateable interface { - Validate(parent *field.Path) field.ErrorList -} -// log is for logging in this package. -var ( - stressChaosLog = ctrl.Log.WithName("stresschaos-resource") + "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" ) -// +kubebuilder:webhook:path=/mutate-chaos-mesh-org-v1alpha1-stresschaos,mutating=true,failurePolicy=fail,groups=chaos-mesh.org,resources=stresschaos,verbs=create;update,versions=v1alpha1,name=mstresschaos.kb.io - -var _ webhook.Defaulter = &StressChaos{} - -// Default implements webhook.Defaulter so a webhook will be registered for the type -func (in *StressChaos) Default() { - stressChaosLog.Info("default", "name", in.Name) - in.Spec.Selector.DefaultNamespace(in.GetNamespace()) -} - -// +kubebuilder:webhook:verbs=create;update,path=/validate-chaos-mesh-org-v1alpha1-stresschaos,mutating=false,failurePolicy=fail,groups=chaos-mesh.org,resources=stresschaos,versions=v1alpha1,name=vstresschaos.kb.io - -var _ ChaosValidator = &StressChaos{} - -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (in *StressChaos) ValidateCreate() error { - stressChaosLog.Info("validate create", "name", in.Name) - return in.Validate() -} - -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (in *StressChaos) ValidateUpdate(old runtime.Object) error { - stressChaosLog.Info("validate update", "name", in.Name) - return in.Validate() -} - -// ValidateDelete implements webhook.Validator so a webhook will be registered for the type -func (in *StressChaos) ValidateDelete() error { - stressChaosLog.Info("validate delete", "name", in.Name) - - // Nothing to do? - return nil -} - -// Validate validates chaos object -func (in *StressChaos) Validate() error { - root := field.NewPath("stresschaos") - errs := in.Spec.Validate(root) - errs = append(errs, in.ValidatePodMode(root)...) - errs = append(errs, in.ValidateScheduler(root.Child("spec"))...) - if len(errs) > 0 { - return fmt.Errorf(errs.ToAggregate().Error()) - } - return nil -} - -// ValidatePodMode validates the value with podmode -func (in *StressChaos) ValidatePodMode(spec *field.Path) field.ErrorList { - return ValidatePodMode(in.Spec.Value, in.Spec.Mode, spec.Child("value")) -} - -// ValidateScheduler validates whether scheduler is well defined -func (in *StressChaos) ValidateScheduler(spec *field.Path) field.ErrorList { - return ValidateScheduler(in, spec) -} - -// SelectSpec returns the selector config for authority validate -func (in *StressChaos) GetSelectSpec() []SelectSpec { - return []SelectSpec{&in.Spec} -} - // Validate validates the scheduler and duration -func (in *StressChaosSpec) Validate(parent *field.Path) field.ErrorList { - errs := field.ErrorList{} - current := parent.Child("spec") +func (in *StressChaosSpec) Validate(root interface{}, path *field.Path) field.ErrorList { if len(in.StressngStressors) == 0 && in.Stressors == nil { - errs = append(errs, field.Invalid(current, in, "missing stressors")) - } else if in.Stressors != nil { - errs = append(errs, in.Stressors.Validate(current)...) + return field.ErrorList{ + field.Invalid(path, in, "missing stressors"), + } } - return errs + return nil } // Validate validates whether the Stressors are all well defined -func (in *Stressors) Validate(parent *field.Path) field.ErrorList { - errs := field.ErrorList{} - current := parent.Child("stressors") - once := false - if in.MemoryStressor != nil { - errs = append(errs, in.MemoryStressor.Validate(current)...) - once = true - } - if in.CPUStressor != nil { - errs = append(errs, in.CPUStressor.Validate(current)...) - once = true - } - if !once { - errs = append(errs, field.Invalid(current, in, "missing stressors")) +func (in *Stressors) Validate(root interface{}, path *field.Path) field.ErrorList { + if in == nil { + return nil } - return errs -} -// Validate validates whether the Stressor is well defined -func (in *Stressor) Validate(parent *field.Path) field.ErrorList { - errs := field.ErrorList{} - if in.Workers <= 0 { - errs = append(errs, field.Invalid(parent, in, "workers should always be positive")) + if in.MemoryStressor == nil && in.CPUStressor == nil { + return field.ErrorList{ + field.Invalid(path, in, "missing stressors"), + } } - return errs + return nil } -// Validate validates whether the MemoryStressor is well defined -func (in *MemoryStressor) Validate(parent *field.Path) field.ErrorList { - errs := field.ErrorList{} - current := parent.Child("vm") - errs = append(errs, in.Stressor.Validate(current)...) - if err := in.tryParseBytes(); err != nil { - errs = append(errs, field.Invalid(current, in, - fmt.Sprintf("incorrect bytes format: %s", err))) +type Bytes string + +func (in *Bytes) Validate(root interface{}, path *field.Path) field.ErrorList { + packError := func(err error) field.ErrorList { + return field.ErrorList{ + field.Invalid(path, in, fmt.Sprintf("incorrect bytes format: %s", err.Error())), + } } - return errs -} -func (in *MemoryStressor) tryParseBytes() error { - length := len(in.Size) + // in cannot be nil + size := *in + length := len(size) if length == 0 { return nil } - if in.Size[length-1] == '%' { - percent, err := strconv.Atoi(in.Size[:length-1]) + + var err error + if size[length-1] == '%' { + var percent int + percent, err = strconv.Atoi(string(size)[:length-1]) if err != nil { - return err + return packError(err) } if percent > 100 || percent < 0 { - return errors.New("illegal proportion") + err = errors.New("illegal proportion") + return packError(err) } } else { - size, err := units.FromHumanSize(in.Size) + _, err = units.FromHumanSize(string(size)) if err != nil { - return err + return packError(err) } - in.Size = fmt.Sprintf("%db", size) } + return nil } -// Validate validates whether the CPUStressor is well defined -func (in *CPUStressor) Validate(parent *field.Path) field.ErrorList { +// Validate validates whether the Stressor is well defined +func (in *Stressor) Validate(parent *field.Path) field.ErrorList { errs := field.ErrorList{} - current := parent.Child("cpu") - errs = append(errs, in.Stressor.Validate(current)...) - if in.Load != nil && (*in.Load < 0 || *in.Load > 100) { - errs = append(errs, field.Invalid(current, in, "illegal proportion")) + if in.Workers <= 0 { + errs = append(errs, field.Invalid(parent, in, "workers should always be positive")) } return errs } + +func init() { + genericwebhook.Register("Bytes", reflect.PtrTo(reflect.TypeOf(Bytes("")))) +} diff --git a/api/v1alpha1/stresschaos_webhook_test.go b/api/v1alpha1/stresschaos_webhook_test.go index ff644d90b5..118e0fab5b 100644 --- a/api/v1alpha1/stresschaos_webhook_test.go +++ b/api/v1alpha1/stresschaos_webhook_test.go @@ -1,23 +1,24 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/validation/field" ) var _ = Describe("stresschaos_webhook", func() { @@ -30,7 +31,7 @@ var _ = Describe("stresschaos_webhook", func() { Expect(stresschaos.Spec.Selector.Namespaces[0]).To(Equal(metav1.NamespaceDefault)) }) }) - Context("ChaosValidator of stresschaos", func() { + Context("webhook.Validator of stresschaos", func() { It("Validate StressChaos", func() { type TestCase struct { @@ -39,7 +40,6 @@ var _ = Describe("stresschaos_webhook", func() { execute func(chaos *StressChaos) error expect string } - duration := "400s" stressors := &Stressors{ MemoryStressor: &MemoryStressor{ Stressor: Stressor{Workers: 1}, @@ -58,7 +58,8 @@ var _ = Describe("stresschaos_webhook", func() { }, }, execute: func(chaos *StressChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err }, expect: "", }, @@ -74,7 +75,8 @@ var _ = Describe("stresschaos_webhook", func() { }, }, execute: func(chaos *StressChaos) error { - return chaos.ValidateUpdate(chaos) + _, err := chaos.ValidateUpdate(chaos) + return err }, expect: "", }, @@ -90,46 +92,11 @@ var _ = Describe("stresschaos_webhook", func() { }, }, execute: func(chaos *StressChaos) error { - return chaos.ValidateDelete() + _, err := chaos.ValidateDelete() + return err }, expect: "", }, - { - name: "only define the Scheduler", - chaos: StressChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo4", - }, - Spec: StressChaosSpec{ - Stressors: stressors, - Scheduler: &SchedulerSpec{ - Cron: "@every 10m", - }, - }, - }, - execute: func(chaos *StressChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "only define the Duration", - chaos: StressChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo5", - }, - Spec: StressChaosSpec{ - Stressors: stressors, - Duration: &duration, - }, - }, - execute: func(chaos *StressChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, { name: "missing stressors", chaos: StressChaos{ @@ -139,7 +106,8 @@ var _ = Describe("stresschaos_webhook", func() { }, }, execute: func(chaos *StressChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, @@ -155,52 +123,52 @@ var _ = Describe("stresschaos_webhook", func() { } }) - It("Validate Stressors", func() { - type TestCase struct { - name string - stressor Validateable - errs int - } - tcs := []TestCase{ - { - name: "missing workers", - stressor: &Stressor{}, - errs: 1, - }, - { - name: "default MemoryStressor", - stressor: &MemoryStressor{ - Stressor: Stressor{Workers: 1}, - }, - errs: 0, - }, - { - name: "default CPUStressor", - stressor: &CPUStressor{ - Stressor: Stressor{Workers: 1}, - }, - errs: 0, - }, - } - parent := field.NewPath("parent") - for _, tc := range tcs { - Expect(tc.stressor.Validate(parent)).To(HaveLen(tc.errs)) - } - }) + // It("Validate Stressors", func() { + //type TestCase struct { + //name string + //stressor Validateable + //errs int + //} + //tcs := []TestCase{ + //{ + //name: "missing workers", + //stressor: &Stressor{}, + //errs: 1, + //}, + //{ + //name: "default MemoryStressor", + //stressor: &MemoryStressor{ + //Stressor: Stressor{Workers: 1}, + //}, + //errs: 0, + //}, + //{ + //name: "default CPUStressor", + //stressor: &CPUStressor{ + //Stressor: Stressor{Workers: 1}, + //}, + //errs: 0, + //}, + //} + //parent := field.NewPath("parent") + //for _, tc := range tcs { + //Expect(tc.stressor.Validate(parent)).To(HaveLen(tc.errs)) + //} + //}) - It("Parse MemoryStressor fields", func() { - vm := MemoryStressor{} - incorrectBytes := []string{"-1", "-1%", "101%", "x%", "-1Kb"} - for _, b := range incorrectBytes { - vm.Size = b - Expect(vm.tryParseBytes()).Should(HaveOccurred()) - } - correctBytes := []string{"", "1%", "100KB", "100B"} - for _, b := range correctBytes { - vm.Size = b - Expect(vm.tryParseBytes()).ShouldNot(HaveOccurred()) - } - }) + //It("Parse MemoryStressor fields", func() { + //vm := MemoryStressor{} + //incorrectBytes := []string{"-1", "-1%", "101%", "x%", "-1Kb"} + //for _, b := range incorrectBytes { + //vm.Size = b + //Expect(vm.tryParseBytes()).Should(HaveOccurred()) + //} + //correctBytes := []string{"", "1%", "100KB", "100B"} + //for _, b := range correctBytes { + //vm.Size = b + //Expect(vm.tryParseBytes()).ShouldNot(HaveOccurred()) + //} + //}) }) diff --git a/api/v1alpha1/suite_test.go b/api/v1alpha1/suite_test.go index 4f0fd442bf..3cbe896960 100644 --- a/api/v1alpha1/suite_test.go +++ b/api/v1alpha1/suite_test.go @@ -1,15 +1,17 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 @@ -17,17 +19,16 @@ import ( "os" "path/filepath" "testing" + "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" ) // These tests use Ginkgo (BDD-style Go testing framework). Refer to @@ -40,17 +41,16 @@ var testEnv *envtest.Environment func TestAPIs(t *testing.T) { RegisterFailHandler(Fail) - RunSpecsWithDefaultAndCustomReporters(t, - "v1 Suite", - []Reporter{envtest.NewlineReporter{}}) + RunSpecs(t, "v1 Suite") } -var _ = BeforeSuite(func(done Done) { - logf.SetLogger(zap.LoggerTo(GinkgoWriter, true)) +var _ = BeforeSuite(func(ctx SpecContext) { + + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) By("bootstrapping test environment") t := true - if os.Getenv("TEST_USE_EXISTING_CLUSTER") == "true" { + if os.Getenv("USE_EXISTING_CLUSTER") == "true" { testEnv = &envtest.Environment{ UseExistingCluster: &t, } @@ -71,8 +71,7 @@ var _ = BeforeSuite(func(done Done) { Expect(err).ToNot(HaveOccurred()) Expect(k8sClient).ToNot(BeNil()) - close(done) -}, 60) +}, NodeTimeout(60*time.Second)) var _ = AfterSuite(func() { By("tearing down the test environment") diff --git a/api/v1alpha1/timechaos_types.go b/api/v1alpha1/timechaos_types.go index 004cc4f4ad..b6930a940d 100644 --- a/api/v1alpha1/timechaos_types.go +++ b/api/v1alpha1/timechaos_types.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 @@ -18,7 +20,8 @@ import ( ) // +kubebuilder:object:root=true -// +chaos-mesh:base +// +kubebuilder:printcolumn:name="duration",type=string,JSONPath=`.spec.duration` +// +chaos-mesh:experiment // TimeChaos is the Schema for the timechaos API type TimeChaos struct { @@ -30,77 +33,42 @@ type TimeChaos struct { // +optional // Most recently observed status of the time chaos experiment - Status TimeChaosStatus `json:"status"` + Status TimeChaosStatus `json:"status,omitempty"` } +var _ InnerObjectWithSelector = (*TimeChaos)(nil) +var _ InnerObject = (*TimeChaos)(nil) + // TimeChaosSpec defines the desired state of TimeChaos type TimeChaosSpec struct { - // Mode defines the mode to run chaos action. - // Supported mode: one / all / fixed / fixed-percent / random-max-percent - // +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent - Mode PodMode `json:"mode"` - - // Value is required when the mode is set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - // If `FixedPodMode`, provide an integer of pods to do chaos action. - // If `FixedPercentPodMod`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. - // If `RandomMaxPercentPodMod`, provide a number from 0-100 to specify the max percent of pods to do chaos action - // +optional - Value string `json:"value"` - - // Selector is used to select pods that are used to inject chaos action. - Selector SelectorSpec `json:"selector"` + ContainerSelector `json:",inline"` // TimeOffset defines the delta time of injected program. It's a possibly signed sequence of decimal numbers, such as // "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - TimeOffset string `json:"timeOffset"` + TimeOffset string `json:"timeOffset" webhook:"TimeOffset"` // ClockIds defines all affected clock id // All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", // "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", // "CLOCK_BOOTTIME_ALARM"] // Default value is ["CLOCK_REALTIME"] - ClockIds []string `json:"clockIds,omitempty"` - - // ContainerName indicates the name of affected container. - // If not set, all containers will be injected - // +optional - ContainerNames []string `json:"containerNames,omitempty"` + ClockIds []string `json:"clockIds,omitempty" webhook:"ClockIds,nilable"` // Duration represents the duration of the chaos action Duration *string `json:"duration,omitempty"` - // Scheduler defines some schedule rules to control the running time of the chaos experiment about time. - Scheduler *SchedulerSpec `json:"scheduler,omitempty"` -} - -// SetDefaultValue will set default value for empty fields -func (in *TimeChaos) SetDefaultValue() { - in.Spec.DefaultClockIds() -} - -// DefaultClockIds will set default value for empty ClockIds fields -func (in *TimeChaosSpec) DefaultClockIds() { - if in.ClockIds == nil || len(in.ClockIds) == 0 { - in.ClockIds = []string{"CLOCK_REALTIME"} - } -} - -// GetSelector is a getter for Selector (for implementing SelectSpec) -func (in *TimeChaosSpec) GetSelector() SelectorSpec { - return in.Selector -} - -// GetMode is a getter for Mode (for implementing SelectSpec) -func (in *TimeChaosSpec) GetMode() PodMode { - return in.Mode -} - -// GetValue is a getter for Value (for implementing SelectSpec) -func (in *TimeChaosSpec) GetValue() string { - return in.Value + // RemoteCluster represents the remote cluster where the chaos will be deployed + // +optional + RemoteCluster string `json:"remoteCluster,omitempty"` } // TimeChaosStatus defines the observed state of TimeChaos type TimeChaosStatus struct { ChaosStatus `json:",inline"` } + +func (in *TimeChaos) GetSelectorSpecs() map[string]interface{} { + return map[string]interface{}{ + ".": &in.Spec.ContainerSelector, + } +} diff --git a/api/v1alpha1/timechaos_webhook.go b/api/v1alpha1/timechaos_webhook.go index 589b4a5674..2661b0f91d 100644 --- a/api/v1alpha1/timechaos_webhook.go +++ b/api/v1alpha1/timechaos_webhook.go @@ -1,105 +1,56 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( "fmt" + "reflect" "time" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/webhook" -) - -// log is for logging in this package. -var timechaoslog = logf.Log.WithName("timechaos-resource") - -// +kubebuilder:webhook:path=/mutate-chaos-mesh-org-v1alpha1-timechaos,mutating=true,failurePolicy=fail,groups=chaos-mesh.org,resources=timechaos,verbs=create;update,versions=v1alpha1,name=mtimechaos.kb.io - -var _ webhook.Defaulter = &TimeChaos{} - -// Default implements webhook.Defaulter so a webhook will be registered for the type -func (in *TimeChaos) Default() { - timechaoslog.Info("default", "name", in.Name) - - in.Spec.Selector.DefaultNamespace(in.GetNamespace()) - in.Spec.DefaultClockIds() -} - -// +kubebuilder:webhook:verbs=create;update,path=/validate-chaos-mesh-org-v1alpha1-timechaos,mutating=false,failurePolicy=fail,groups=chaos-mesh.org,resources=timechaos,versions=v1alpha1,name=vtimechaos.kb.io - -var _ ChaosValidator = &TimeChaos{} - -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (in *TimeChaos) ValidateCreate() error { - timechaoslog.Info("validate create", "name", in.Name) - return in.Validate() -} -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (in *TimeChaos) ValidateUpdate(old runtime.Object) error { - timechaoslog.Info("validate update", "name", in.Name) - return in.Validate() -} - -// ValidateDelete implements webhook.Validator so a webhook will be registered for the type -func (in *TimeChaos) ValidateDelete() error { - timechaoslog.Info("validate delete", "name", in.Name) - - // Nothing to do? - return nil -} + "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" +) -// Validate validates chaos object -func (in *TimeChaos) Validate() error { - specField := field.NewPath("spec") - allErrs := in.ValidateScheduler(specField) - allErrs = append(allErrs, in.ValidatePodMode(specField)...) - allErrs = append(allErrs, in.Spec.validateTimeOffset(specField.Child("timeOffset"))...) +type ClockIds []string - if len(allErrs) > 0 { - return fmt.Errorf(allErrs.ToAggregate().Error()) +// DefaultClockIds will set default value for empty ClockIds fields +func (in *ClockIds) Default(root interface{}, field *reflect.StructField) { + // in cannot be nil + if *in == nil || len(*in) == 0 { + *in = []string{"CLOCK_REALTIME"} } - return nil -} - -// ValidateScheduler validates the scheduler and duration -func (in *TimeChaos) ValidateScheduler(spec *field.Path) field.ErrorList { - return ValidateScheduler(in, spec) -} - -// ValidatePodMode validates the value with podmode -func (in *TimeChaos) ValidatePodMode(spec *field.Path) field.ErrorList { - return ValidatePodMode(in.Spec.Value, in.Spec.Mode, spec.Child("value")) } -// SelectSpec returns the selector config for authority validate -func (in *TimeChaos) GetSelectSpec() []SelectSpec { - return []SelectSpec{&in.Spec} -} +type TimeOffset string -// validateTimeOffset validates the timeOffset -func (in *TimeChaosSpec) validateTimeOffset(timeOffset *field.Path) field.ErrorList { +func (in *TimeOffset) Validate(root interface{}, path *field.Path) field.ErrorList { allErrs := field.ErrorList{} - _, err := time.ParseDuration(in.TimeOffset) + _, err := time.ParseDuration(string(*in)) if err != nil { - allErrs = append(allErrs, field.Invalid(timeOffset, - in.TimeOffset, + allErrs = append(allErrs, field.Invalid(path, + in, fmt.Sprintf("parse timeOffset field error:%s", err))) } return allErrs } + +func init() { + genericwebhook.Register("ClockIds", reflect.PtrTo(reflect.TypeOf(ClockIds{}))) + genericwebhook.Register("TimeOffset", reflect.PtrTo(reflect.TypeOf(TimeOffset("")))) +} diff --git a/api/v1alpha1/timechaos_webhook_test.go b/api/v1alpha1/timechaos_webhook_test.go index a4dd4e67e9..e784cea293 100644 --- a/api/v1alpha1/timechaos_webhook_test.go +++ b/api/v1alpha1/timechaos_webhook_test.go @@ -1,20 +1,22 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -30,7 +32,7 @@ var _ = Describe("timechaos_webhook", func() { Expect(timechaos.Spec.ClockIds[0]).To(Equal("CLOCK_REALTIME")) }) }) - Context("ChaosValidator of timechaos", func() { + Context("webhook.Validator of timechaos", func() { It("Validate", func() { type TestCase struct { @@ -39,7 +41,6 @@ var _ = Describe("timechaos_webhook", func() { execute func(chaos *TimeChaos) error expect string } - duration := "400s" tcs := []TestCase{ { name: "simple ValidateCreate", @@ -51,7 +52,8 @@ var _ = Describe("timechaos_webhook", func() { Spec: TimeChaosSpec{TimeOffset: "1s"}, }, execute: func(chaos *TimeChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err }, expect: "", }, @@ -65,7 +67,8 @@ var _ = Describe("timechaos_webhook", func() { Spec: TimeChaosSpec{TimeOffset: "1s"}, }, execute: func(chaos *TimeChaos) error { - return chaos.ValidateUpdate(chaos) + _, err := chaos.ValidateUpdate(chaos) + return err }, expect: "", }, @@ -79,46 +82,11 @@ var _ = Describe("timechaos_webhook", func() { Spec: TimeChaosSpec{TimeOffset: "1s"}, }, execute: func(chaos *TimeChaos) error { - return chaos.ValidateDelete() + _, err := chaos.ValidateDelete() + return err }, expect: "", }, - { - name: "only define the Scheduler", - chaos: TimeChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo4", - }, - Spec: TimeChaosSpec{ - Scheduler: &SchedulerSpec{ - Cron: "@every 10m", - }, - TimeOffset: "1s", - }, - }, - execute: func(chaos *TimeChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, - { - name: "only define the Duration", - chaos: TimeChaos{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "foo5", - }, - Spec: TimeChaosSpec{ - Duration: &duration, - TimeOffset: "1s", - }, - }, - execute: func(chaos *TimeChaos) error { - return chaos.ValidateCreate() - }, - expect: "error", - }, { name: "validate the timeOffset", chaos: TimeChaos{ @@ -131,7 +99,8 @@ var _ = Describe("timechaos_webhook", func() { }, }, execute: func(chaos *TimeChaos) error { - return chaos.ValidateCreate() + _, err := chaos.ValidateCreate() + return err }, expect: "error", }, diff --git a/api/v1alpha1/workflow_types.go b/api/v1alpha1/workflow_types.go index 7f18940de4..a1ec1df368 100644 --- a/api/v1alpha1/workflow_types.go +++ b/api/v1alpha1/workflow_types.go @@ -4,24 +4,28 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( - "fmt" - + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ) // +kubebuilder:object:root=true // +kubebuilder:resource:shortName=wf +// +kubebuilder:subresource:status +// +chaos-mesh:experiment type Workflow struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -34,6 +38,12 @@ type Workflow struct { Status WorkflowStatus `json:"status"` } +func (in *Workflow) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + +const KindWorkflow = "Workflow" + type WorkflowSpec struct { Entry string `json:"entry"` Templates []Template `json:"templates"` @@ -41,19 +51,44 @@ type WorkflowSpec struct { type WorkflowStatus struct { // +optional - EntryNode *string `json:"entry_node,omitempty"` + EntryNode *string `json:"entryNode,omitempty"` + // +optional + StartTime *metav1.Time `json:"startTime,omitempty"` + // +optional + EndTime *metav1.Time `json:"endTime,omitempty"` + // Represents the latest available observations of a workflow's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + Conditions []WorkflowCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` +} + +type WorkflowConditionType string + +const ( + WorkflowConditionAccomplished WorkflowConditionType = "Accomplished" + WorkflowConditionScheduled WorkflowConditionType = "Scheduled" +) + +type WorkflowCondition struct { + Type WorkflowConditionType `json:"type"` + Status corev1.ConditionStatus `json:"status"` + Reason string `json:"reason"` + StartTime *metav1.Time `json:"startTime,omitempty"` } type TemplateType string const ( - TypeTask TemplateType = "Task" - TypeSerial TemplateType = "Serial" - TypeParallel TemplateType = "Parallel" - TypeSuspend TemplateType = "Suspend" + TypeTask TemplateType = "Task" + TypeSerial TemplateType = "Serial" + TypeParallel TemplateType = "Parallel" + TypeSuspend TemplateType = "Suspend" + TypeSchedule TemplateType = "Schedule" + TypeStatusCheck TemplateType = "StatusCheck" ) -func IsChoasTemplateType(target TemplateType) bool { +func IsChaosTemplateType(target TemplateType) bool { return contains(allChaosTemplateType, target) } @@ -67,12 +102,67 @@ func contains(arr []TemplateType, target TemplateType) bool { } type Template struct { - Name string `json:"name"` - Type TemplateType `json:"template_type"` - Duration *string `json:"duration,omitempty"` - Tasks []string `json:"tasks,omitempty"` + Name string `json:"name"` + Type TemplateType `json:"templateType"` + // +optional + Deadline *string `json:"deadline,omitempty"` + // Task describes the behavior of the custom task. Only used when Type is TypeTask. + // +optional + Task *Task `json:"task,omitempty"` + // Children describes the children steps of serial or parallel node. Only used when Type is TypeSerial or TypeParallel. + // +optional + Children []string `json:"children,omitempty"` + // ConditionalBranches describes the conditional branches of custom tasks. Only used when Type is TypeTask. + // +optional + ConditionalBranches []ConditionalBranch `json:"conditionalBranches,omitempty"` + // EmbedChaos describe the chaos to be injected with chaos nodes. Only used when Type is TypeChaos. // +optional *EmbedChaos `json:",inline"` + // Schedule describe the Schedule(describing scheduled chaos) to be injected with chaos nodes. Only used when Type is TypeSchedule. + // +optional + Schedule *ChaosOnlyScheduleSpec `json:"schedule,omitempty"` + // StatusCheck describe the behavior of StatusCheck. Only used when Type is TypeStatusCheck. + // +optional + StatusCheck *StatusCheckSpec `json:"statusCheck,omitempty"` + // AbortWithStatusCheck describe whether to abort the workflow when the failure threshold of StatusCheck is exceeded. + // Only used when Type is TypeStatusCheck. + // +optional + AbortWithStatusCheck bool `json:"abortWithStatusCheck,omitempty"` +} + +// ChaosOnlyScheduleSpec is very similar with ScheduleSpec, but it could not schedule Workflow +// because we could not resolve nested CRD now +type ChaosOnlyScheduleSpec struct { + Schedule string `json:"schedule"` + + // +optional + // +nullable + // +kubebuilder:validation:Minimum=0 + StartingDeadlineSeconds *int64 `json:"startingDeadlineSeconds"` + + // +optional + // +kubebuilder:validation:Enum=Forbid;Allow + ConcurrencyPolicy ConcurrencyPolicy `json:"concurrencyPolicy"` + + // +optional + // +kubebuilder:validation:Minimum=1 + HistoryLimit int `json:"historyLimit,omitempty"` + + Type ScheduleTemplateType `json:"type"` + + EmbedChaos `json:",inline"` +} + +type Task struct { + // Container is the main container image to run in the pod + Container *corev1.Container `json:"container,omitempty"` + + // Volumes is a list of volumes that can be mounted by containers in a template. + // +patchStrategy=merge + // +patchMergeKey=name + Volumes []corev1.Volume `json:"volumes,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // TODO: maybe we could specify parameters in other ways, like loading context from file } // +kubebuilder:object:root=true @@ -82,13 +172,27 @@ type WorkflowList struct { Items []Workflow `json:"items"` } +func (in *WorkflowList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} + +// TODO: refactor: not so accurate +func (in *WorkflowList) DeepCopyList() GenericChaosList { + return in.DeepCopy() +} + func init() { SchemeBuilder.Register(&Workflow{}, &WorkflowList{}) } func FetchChaosByTemplateType(templateType TemplateType) (runtime.Object, error) { if kind, ok := all.kinds[string(templateType)]; ok { - return kind.Chaos.DeepCopyObject(), nil + return kind.SpawnObject(), nil } - return nil, fmt.Errorf("no such kind refers to template type %s", templateType) + return nil, errors.Wrapf(errInvalidValue, "unknown template type %s", templateType) } diff --git a/api/v1alpha1/workflow_webhook.go b/api/v1alpha1/workflow_webhook.go new file mode 100644 index 0000000000..44df255914 --- /dev/null +++ b/api/v1alpha1/workflow_webhook.go @@ -0,0 +1,280 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "fmt" + "reflect" + "sort" + + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/apimachinery/pkg/util/validation/field" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + gw "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" +) + +// log is for logging in this package. +var workflowlog = logf.Log.WithName("workflow-resource") + +var _ webhook.Validator = &Workflow{} + +func (in *Workflow) ValidateCreate() (admission.Warnings, error) { + var allErrs field.ErrorList + specPath := field.NewPath("spec") + allErrs = append(allErrs, entryMustExists(specPath.Child("entry"), in.Spec.Entry, in.Spec.Templates)...) + allErrs = append(allErrs, validateTemplates(specPath.Child("templates"), in.Spec.Templates)...) + if len(allErrs) > 0 { + return nil, errors.New(allErrs.ToAggregate().Error()) + } + return nil, nil +} + +func (in *Workflow) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + return in.ValidateCreate() +} + +func (in *Workflow) ValidateDelete() (admission.Warnings, error) { + return nil, nil +} + +func entryMustExists(path *field.Path, entry string, templates []Template) field.ErrorList { + var result field.ErrorList + // name is required + if len(entry) == 0 { + result = append(result, field.Required(path, "the entry of workflow is required")) + } + founded := false + for _, item := range templates { + if item.Name == entry { + founded = true + break + } + } + if !founded { + result = append(result, field.Invalid(path, entry, fmt.Sprintf("can not find a template with name %s", entry))) + } + return result +} + +func validateTemplates(path *field.Path, templates []Template) field.ErrorList { + var result field.ErrorList + if len(templates) == 0 { + result = append(result, field.Invalid(path, templates, "templates in workflow could not be empty")) + return result + } + var allNames []string + for _, template := range templates { + allNames = append(allNames, template.Name) + } + result = append(result, namesCouldNotBeDuplicated(path, allNames)...) + + for i, item := range templates { + itemPath := path.Index(i) + result = append(result, validateTemplate(itemPath, item, templates)...) + } + return result +} + +func validateTemplate(path *field.Path, template Template, allTemplates []Template) field.ErrorList { + var result field.ErrorList + // name is required + if len(template.Name) == 0 { + result = append(result, field.Required(path.Child("name"), "name of template is required")) + } + + // name must be restricted with DNS-1123 + errs := validation.IsDNS1123Subdomain(template.Name) + if len(errs) > 0 { + result = append(result, field.Invalid(path.Child("name"), template.Name, fmt.Sprintf("field name must be DNS-1123 subdomain, %s", errs))) + } + + // template name could not be duplicated + + switch templateType := template.Type; { + case templateType == TypeSuspend: + if template.Deadline == nil || len(*template.Deadline) == 0 { + result = append(result, field.Invalid(path.Child("deadline"), template.Deadline, "deadline in template with type Suspend could not be empty")) + } + result = append(result, shouldBeNoTask(path, template)...) + result = append(result, shouldBeNoChildren(path, template)...) + result = append(result, shouldBeNoConditionalBranches(path, template)...) + result = append(result, shouldBeNoEmbedChaos(path, template)...) + result = append(result, shouldBeNoSchedule(path, template)...) + case templateType == TypeSerial, templateType == TypeParallel: + for i, item := range template.Children { + result = append(result, templateMustExists(item, path.Child("children").Index(i), allTemplates)...) + } + result = append(result, shouldBeNoTask(path, template)...) + result = append(result, shouldBeNoConditionalBranches(path, template)...) + result = append(result, shouldBeNoEmbedChaos(path, template)...) + result = append(result, shouldBeNoSchedule(path, template)...) + case templateType == TypeSchedule: + result = append(result, shouldBeNoTask(path, template)...) + result = append(result, shouldBeNoChildren(path, template)...) + result = append(result, shouldBeNoConditionalBranches(path, template)...) + result = append(result, shouldBeNoEmbedChaos(path, template)...) + case templateType == TypeTask: + result = append(result, shouldBeNoChildren(path, template)...) + result = append(result, shouldBeNoEmbedChaos(path, template)...) + result = append(result, shouldBeNoSchedule(path, template)...) + case IsChaosTemplateType(templateType): + result = append(result, shouldNotSetupDurationInTheChaos(path, template)...) + + result = append(result, shouldBeNoTask(path, template)...) + result = append(result, shouldBeNoChildren(path, template)...) + result = append(result, shouldBeNoConditionalBranches(path, template)...) + result = append(result, shouldBeNoSchedule(path, template)...) + + result = append(result, template.EmbedChaos.Validate(path, string(templateType))...) + case templateType == TypeStatusCheck: + result = append(result, shouldBeNoTask(path, template)...) + result = append(result, shouldBeNoChildren(path, template)...) + result = append(result, shouldBeNoConditionalBranches(path, template)...) + result = append(result, shouldBeNoEmbedChaos(path, template)...) + result = append(result, shouldBeNoSchedule(path, template)...) + default: + result = append(result, field.Invalid(path.Child("templateType"), template.Type, fmt.Sprintf("unrecognized template type: %s", template.Type))) + } + + return result +} + +func namesCouldNotBeDuplicated(templatesPath *field.Path, names []string) field.ErrorList { + nameCounter := make(map[string]int) + for _, name := range names { + if count, ok := nameCounter[name]; ok { + nameCounter[name] = count + 1 + } else { + nameCounter[name] = 1 + } + } + var duplicatedNames []string + for name, count := range nameCounter { + if count > 1 { + duplicatedNames = append(duplicatedNames, name) + } + } + sort.Strings(duplicatedNames) + if len(duplicatedNames) > 0 { + return field.ErrorList{ + field.Invalid(templatesPath, "", fmt.Sprintf("template name must be unique, duplicated names: %s", duplicatedNames)), + } + } + return nil +} + +func templateMustExists(templateName string, path *field.Path, template []Template) field.ErrorList { + var result field.ErrorList + + founded := false + for _, item := range template { + if item.Name == templateName { + founded = true + break + } + } + + if !founded { + err := field.Invalid(path, templateName, fmt.Sprintf("can not find a template with name %s", templateName)) + result = append(result, err) + } + return result +} + +func shouldNotSetupDurationInTheChaos(path *field.Path, template Template) field.ErrorList { + var result field.ErrorList + + if template.EmbedChaos == nil { + result = append(result, field.Invalid(path.Child(string(template.Type)), nil, fmt.Sprintf("the value of chaos %s is required", template.Type))) + return result + } + + spec := reflect.ValueOf(template.EmbedChaos).Elem().FieldByName(string(template.Type)) + if !spec.IsValid() || spec.IsNil() { + result = append(result, field.Invalid(path.Child(string(template.Type)), + nil, + fmt.Sprintf("parse workflow field error: missing chaos spec %s", template.Type))) + return result + } + if commonSpec, ok := spec.Interface().(ContainsDuration); !ok { + result = append(result, field.Invalid(path, "", fmt.Sprintf("Chaos: %s does not implement CommonSpec", template.Type))) + } else { + duration, err := commonSpec.GetDuration() + if err != nil { + result = append(result, field.Invalid(path, "", err.Error())) + return result + } + if duration != nil { + result = append(result, field.Invalid(path, duration, "should not define duration in chaos when using Workflow, use Template#Deadline instead.")) + } + } + return result +} + +func shouldBeNoTask(path *field.Path, template Template) field.ErrorList { + if template.Task != nil { + return field.ErrorList{ + field.Invalid(path, template.Task, "this template should not contain Task"), + } + } + return nil +} + +func shouldBeNoChildren(path *field.Path, template Template) field.ErrorList { + if len(template.Children) > 0 { + return field.ErrorList{ + field.Invalid(path, template.Children, "this template should not contain Children"), + } + } + return nil +} + +func shouldBeNoConditionalBranches(path *field.Path, template Template) field.ErrorList { + if len(template.ConditionalBranches) > 0 { + return field.ErrorList{ + field.Invalid(path, template.ConditionalBranches, "this template should not contain ConditionalBranches"), + } + } + return nil +} + +func shouldBeNoEmbedChaos(path *field.Path, template Template) field.ErrorList { + // TODO: we could improve that with code generation in the future + if template.EmbedChaos != nil { + return field.ErrorList{ + field.Invalid(path, template.EmbedChaos, "this template should not contain any Chaos"), + } + } + return nil +} + +func shouldBeNoSchedule(path *field.Path, template Template) field.ErrorList { + if template.Schedule != nil { + return field.ErrorList{ + field.Invalid(path, template.Schedule, "this template should not contain Schedule"), + } + } + return nil +} + +func (in *Workflow) Default() { + gw.Default(in) +} diff --git a/api/v1alpha1/workflow_webhook_test.go b/api/v1alpha1/workflow_webhook_test.go new file mode 100644 index 0000000000..c22a400d5c --- /dev/null +++ b/api/v1alpha1/workflow_webhook_test.go @@ -0,0 +1,482 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + "fmt" + "reflect" + "testing" + "time" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func Test_entryMustExists(t *testing.T) { + entryPath := field.NewPath("spec", "entry") + + type args struct { + path *field.Path + entry string + templates []Template + } + tests := []struct { + name string + args args + want field.ErrorList + }{ + { + name: "entry is empty", + args: args{ + path: entryPath, + entry: "", + templates: nil, + }, + want: field.ErrorList{ + field.Required(entryPath, "the entry of workflow is required"), + field.Invalid(entryPath, "", fmt.Sprintf("can not find a template with name %s", "")), + }, + }, { + name: "entry does not exist in templates", + args: args{ + path: entryPath, + entry: "entry", + templates: []Template{ + { + Name: "whatever is not entry", + Type: TypeSuspend, + }, + }, + }, + want: field.ErrorList{ + field.Invalid(entryPath, "entry", fmt.Sprintf("can not find a template with name %s", "entry")), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := entryMustExists(tt.args.path, tt.args.entry, tt.args.templates); !reflect.DeepEqual(got, tt.want) { + t.Errorf("entryMustExists() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_validateTemplates(t *testing.T) { + templatesPath := field.NewPath("spec", "templates") + var nilTemplates []Template + type args struct { + path *field.Path + templates []Template + } + tests := []struct { + name string + args args + want field.ErrorList + }{ + { + name: "templates is nil", + args: args{ + path: templatesPath, + templates: nil, + }, + want: field.ErrorList{ + field.Invalid(templatesPath, nilTemplates, "templates in workflow could not be empty"), + }, + }, { + name: "templates is empty", + args: args{ + path: templatesPath, + templates: []Template{}, + }, + want: field.ErrorList{ + field.Invalid(templatesPath, []Template{}, "templates in workflow could not be empty"), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := validateTemplates(tt.args.path, tt.args.templates); !reflect.DeepEqual(got, tt.want) { + t.Errorf("validateTemplates() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_shouldBeNoTask(t *testing.T) { + templatePath := field.NewPath("spec", "templates").Index(0) + mockTask := Task{ + Container: &corev1.Container{Name: "fake-container"}, + } + type args struct { + path *field.Path + template Template + } + tests := []struct { + name string + args args + want field.ErrorList + }{ + { + name: "contains unexpected task", + args: args{ + path: templatePath, + template: Template{ + Task: &mockTask, + }, + }, + want: field.ErrorList{ + field.Invalid(templatePath, &mockTask, "this template should not contain Task"), + }, + }, { + name: "does not contain task", + args: args{ + path: templatePath, + template: Template{}, + }, + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := shouldBeNoTask(tt.args.path, tt.args.template); !reflect.DeepEqual(got, tt.want) { + t.Errorf("shouldBeNoTask() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_shouldBeNoChildren(t *testing.T) { + templatePath := field.NewPath("spec", "templates").Index(0) + mockChildren := []string{"child-a", "child-b"} + type args struct { + path *field.Path + template Template + } + tests := []struct { + name string + args args + want field.ErrorList + }{ + { + name: "contains unexpected children", + args: args{ + path: templatePath, + template: Template{ + Children: mockChildren, + }, + }, + want: field.ErrorList{ + field.Invalid(templatePath, mockChildren, "this template should not contain Children"), + }, + }, { + name: "does not contain children", + args: args{ + path: templatePath, + template: Template{}, + }, + want: nil, + }, { + name: "empty array is also valid", + args: args{ + path: templatePath, + template: Template{ + Children: []string{}, + }, + }, + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := shouldBeNoChildren(tt.args.path, tt.args.template); !reflect.DeepEqual(got, tt.want) { + t.Errorf("shouldBeNoChildren() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_shouldBeNoConditionalBranches(t *testing.T) { + templatePath := field.NewPath("spec", "templates").Index(0) + mockConditionalBranches := []ConditionalBranch{ + {Target: "", Expression: ""}, + } + type args struct { + path *field.Path + template Template + } + tests := []struct { + name string + args args + want field.ErrorList + }{ + { + name: "contains unexpected conditional branches", + args: args{ + path: templatePath, + template: Template{ + ConditionalBranches: mockConditionalBranches, + }, + }, + want: field.ErrorList{ + field.Invalid(templatePath, mockConditionalBranches, "this template should not contain ConditionalBranches"), + }, + }, { + name: "does not contain conditional branches", + args: args{ + path: templatePath, + template: Template{}, + }, + want: nil, + }, { + name: "empty array is also valid", + args: args{ + path: templatePath, + template: Template{ + ConditionalBranches: []ConditionalBranch{}, + }, + }, + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := shouldBeNoConditionalBranches(tt.args.path, tt.args.template); !reflect.DeepEqual(got, tt.want) { + t.Errorf("shouldBeNoConditionalBranches() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_shouldBeNoEmbedChaos(t *testing.T) { + templatePath := field.NewPath("spec", "templates").Index(0) + type args struct { + path *field.Path + template Template + } + mockedEmbedChaos := &EmbedChaos{ + PodChaos: &PodChaosSpec{ + ContainerSelector: ContainerSelector{ + PodSelector: PodSelector{ + Selector: PodSelectorSpec{ + GenericSelectorSpec: GenericSelectorSpec{ + Namespaces: []string{"default"}, + }, + }, + }, + }, + Action: PodKillAction, + }, + } + tests := []struct { + name string + args args + want field.ErrorList + }{ + { + name: "unexpected embedded chaos", + args: args{ + path: templatePath, + template: Template{ + EmbedChaos: mockedEmbedChaos, + }, + }, + want: field.ErrorList{ + field.Invalid(templatePath, mockedEmbedChaos, "this template should not contain any Chaos"), + }, + }, { + name: "only nil embedded chaos is valid", + args: args{ + path: templatePath, + template: Template{ + EmbedChaos: nil, + }, + }, + want: nil, + }, { + name: "an embedded chaos with all the nil fields is also INVALID", + args: args{ + path: templatePath, + template: Template{ + EmbedChaos: &EmbedChaos{}, + }, + }, + want: field.ErrorList{ + field.Invalid(templatePath, &EmbedChaos{}, "this template should not contain any Chaos"), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := shouldBeNoEmbedChaos(tt.args.path, tt.args.template); !reflect.DeepEqual(got, tt.want) { + t.Errorf("shouldBeNoEmbedChaos() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_shouldBeNoSchedule(t *testing.T) { + templatePath := field.NewPath("spec", "templates").Index(0) + type args struct { + path *field.Path + template Template + } + mockedSchedule := &ChaosOnlyScheduleSpec{ + Type: ScheduleTypePodChaos, + } + tests := []struct { + name string + args args + want field.ErrorList + }{ + { + name: "unexpected schedule", + args: args{ + path: templatePath, + template: Template{ + Schedule: mockedSchedule, + }, + }, + want: field.ErrorList{ + field.Invalid(templatePath, mockedSchedule, "this template should not contain Schedule"), + }, + }, { + name: "no schedule", + args: args{ + path: templatePath, + template: Template{ + Schedule: nil, + }, + }, + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := shouldBeNoSchedule(tt.args.path, tt.args.template); !reflect.DeepEqual(got, tt.want) { + t.Errorf("shouldBeNoSchedule() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_namesCouldNotBeDuplicated(t *testing.T) { + templatesPath := field.NewPath("spec", "templates") + type args struct { + templatesPath *field.Path + names []string + } + tests := []struct { + name string + args args + want field.ErrorList + }{ + { + name: "names could not be duplicated", + args: args{ + templatesPath: templatesPath, + names: []string{"template-a", "template-b", "template-c", "template-a", "template-b", "template-d"}, + }, + want: field.ErrorList{ + field.Invalid(templatesPath, "", fmt.Sprintf("template name must be unique, duplicated names: %s", []string{"template-a", "template-b"})), + }, + }, { + name: "names could not be duplicated", + args: args{ + templatesPath: templatesPath, + names: []string{"template-a", "template-b", "template-c", "template-d"}, + }, + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := namesCouldNotBeDuplicated(tt.args.templatesPath, tt.args.names); !reflect.DeepEqual(got, tt.want) { + t.Errorf("namesCouldNotBeDuplicated() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_shouldNotSetupDurationInTheChaos(t *testing.T) { + templatesPath := field.NewPath("spec", "templates") + duration20sString := "20s" + duration20s := 20 * time.Second + + type args struct { + path *field.Path + template Template + } + tests := []struct { + name string + args args + want field.ErrorList + }{ + { + name: "should return error when embed chaos is not set", + args: args{ + path: templatesPath, + template: Template{ + Name: "invalid-pod-chaos", + Type: TypePodChaos, + EmbedChaos: nil, + }, + }, + want: field.ErrorList{ + field.Invalid(templatesPath.Child(string(TypePodChaos)), nil, fmt.Sprintf("the value of chaos %s is required", string(TypePodChaos))), + }, + }, + { + name: "should not set duration in the chaos", + args: args{ + path: templatesPath, + template: Template{ + Name: "invalid-pod-chaos", + Type: TypePodChaos, + EmbedChaos: &EmbedChaos{ + PodChaos: &PodChaosSpec{ + Duration: &duration20sString, + }, + }, + }, + }, + want: field.ErrorList{ + field.Invalid(templatesPath, &duration20s, "should not define duration in chaos when using Workflow, use Template#Deadline instead."), + }, + }, { + name: "should set duration in the template", + args: args{ + path: templatesPath, + template: Template{ + Name: "invalid-pod-chaos", + Type: TypePodChaos, + Deadline: &duration20sString, + EmbedChaos: &EmbedChaos{ + PodChaos: &PodChaosSpec{}, + }, + }, + }, + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := shouldNotSetupDurationInTheChaos(tt.args.path, tt.args.template); !reflect.DeepEqual(got, tt.want) { + t.Errorf("shouldNotSetupDurationInTheChaos() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/api/v1alpha1/workflownode_types.go b/api/v1alpha1/workflownode_types.go index 8c23e07742..4d8a972893 100644 --- a/api/v1alpha1/workflownode_types.go +++ b/api/v1alpha1/workflownode_types.go @@ -4,27 +4,34 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package v1alpha1 import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" ) const ( - LabelControlledBy = "chaos-mesh.org/controlled-by" - LabelWorkflow = "chaos-mesh.org/workflow" + LabelControlledBy = "chaos-mesh.org/controlled-by" + LabelWorkflow = "chaos-mesh.org/workflow" + WorkflowAnnotationAbort = "workflow.chaos-mesh.org/abort" ) +const KindWorkflowNode = "WorkflowNode" + // +kubebuilder:object:root=true // +kubebuilder:resource:shortName=wfn +// +kubebuilder:subresource:status type WorkflowNode struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -34,53 +41,87 @@ type WorkflowNode struct { // +optional // Most recently observed status of the workflow node - Status WorkflowNodeStatus `json:"status"` + Status WorkflowNodeStatus `json:"status,omitempty"` } type WorkflowNodeSpec struct { - TemplateName string `json:"template_name"` - WorkflowName string `json:"workflow_name"` + TemplateName string `json:"templateName"` + WorkflowName string `json:"workflowName"` Type TemplateType `json:"type"` - StartTime *metav1.Time `json:"start_time"` + StartTime *metav1.Time `json:"startTime"` // +optional Deadline *metav1.Time `json:"deadline,omitempty"` // +optional - Tasks []string `json:"tasks,omitempty"` + Task *Task `json:"task,omitempty"` + // +optional + Children []string `json:"children,omitempty"` + // +optional + ConditionalBranches []ConditionalBranch `json:"conditionalBranches,omitempty"` // +optional *EmbedChaos `json:",inline,omitempty"` + // +optional + Schedule *ScheduleSpec `json:"schedule,omitempty"` + // StatusCheck describe the behavior of StatusCheck. Only used when Type is TypeStatusCheck. + // +optional + StatusCheck *StatusCheckSpec `json:"statusCheck,omitempty"` + // AbortWithStatusCheck describe whether to abort the workflow when the failure threshold of StatusCheck is exceeded. + // Only used when Type is TypeStatusCheck. + // +optional + AbortWithStatusCheck bool `json:"abortWithStatusCheck,omitempty"` } type WorkflowNodeStatus struct { - // ExpectedChildrenNum means the expected children to execute + // ChaosResource refs to the real chaos CR object. // +optional - ExpectedChildrenNum *int `json:"expected_children_num,omitempty"` + ChaosResource *corev1.TypedLocalObjectReference `json:"chaosResource,omitempty"` - // ChaosResource refs to the real chaos CR object. + // ConditionalBranchesStatus records the evaluation result of each ConditionalBranch // +optional - ChaosResource *corev1.TypedLocalObjectReference `json:"chaos_resource,omitempty"` + ConditionalBranchesStatus *ConditionalBranchesStatus `json:"conditionalBranchesStatus,omitempty"` // ActiveChildren means the created children node // +optional - ActiveChildren []corev1.LocalObjectReference `json:"active_children,omitempty"` + ActiveChildren []corev1.LocalObjectReference `json:"activeChildren,omitempty"` // Children is necessary for representing the order when replicated child template references by parent template. // +optional - FinishedChildren []corev1.LocalObjectReference `json:"finished_children,omitempty"` + FinishedChildren []corev1.LocalObjectReference `json:"finishedChildren,omitempty"` - // Represents the latest available observations of a worklfow node's current state. + // Represents the latest available observations of a workflow node's current state. // +optional // +patchMergeKey=type // +patchStrategy=merge Conditions []WorkflowNodeCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` } +type ConditionalBranch struct { + // Target is the name of other template, if expression is evaluated as true, this template will be spawned. + Target string `json:"target"` + // Expression is the expression for this conditional branch, expected type of result is boolean. If expression is empty, this branch will always be selected/the template will be spawned. + // +optional + Expression string `json:"expression,omitempty"` +} + +type ConditionalBranchesStatus struct { + // +optional + Branches []ConditionalBranchStatus `json:"branches"` + // +optional + Context []string `json:"context"` +} + +type ConditionalBranchStatus struct { + Target string `json:"target"` + EvaluationResult corev1.ConditionStatus `json:"evaluationResult"` +} + type WorkflowNodeConditionType string const ( ConditionAccomplished WorkflowNodeConditionType = "Accomplished" ConditionDeadlineExceed WorkflowNodeConditionType = "DeadlineExceed" ConditionChaosInjected WorkflowNodeConditionType = "ChaosInjected" + ConditionAborted WorkflowNodeConditionType = "Aborted" ) type WorkflowNodeCondition struct { @@ -102,12 +143,47 @@ func init() { // Reasons const ( - EntryCreated string = "EntryCreated" - InvalidEntry string = "InvalidEntry" - NodeAccomplished string = "NodeAccomplished" - NodeDeadlineExceed string = "NodeDeadlineExceed" - NodeDeadlineNotExceed string = "NodeDeadlineNotExceed" - NodeDeadlineOmitted string = "NodeDeadlineOmitted" - ChaosCRCreated string = "ChaosCRCreated" - ChaosCRCreateFailed string = "ChaosCRCreateFailed" + EntryCreated string = "EntryCreated" + InvalidEntry string = "InvalidEntry" + WorkflowAccomplished string = "WorkflowAccomplished" + NodeAccomplished string = "NodeAccomplished" + NodesCreated string = "NodesCreated" + NodeDeadlineExceed string = "NodeDeadlineExceed" + NodeDeadlineNotExceed string = "NodeDeadlineNotExceed" + NodeDeadlineOmitted string = "NodeDeadlineOmitted" + ParentNodeDeadlineExceed string = "ParentNodeDeadlineExceed" + ChaosCRCreated string = "ChaosCRCreated" + ChaosCRCreateFailed string = "ChaosCRCreateFailed" + ChaosCRDeleted string = "ChaosCRDeleted" + ChaosCRDeleteFailed string = "ChaosCRDeleteFailed" + ChaosCRNotExists string = "ChaosCRNotExists" + TaskPodSpawned string = "TaskPodSpawned" + TaskPodSpawnFailed string = "TaskPodSpawnFailed" + TaskPodPodCompleted string = "TaskPodPodCompleted" + ConditionalBranchesSelected string = "ConditionalBranchesSelected" + RerunBySpecChanged string = "RerunBySpecChanged" + StatusCheckCreated string = "StatusCheckCreated" + StatusCheckCreatedFailed string = "StatusCheckCreatedFailed" + StatusCheckDeleted string = "StatusCheckDeleted" + StatusCheckDeletedFailed string = "StatusCheckDeletedFailed" + StatusCheckCompleted string = "StatusCheckCompleted" + StatusCheckNotExceedSuccessThreshold string = "StatusCheckNotExceedSuccessThreshold" + ParentNodeAborted string = "ParentNodeAborted" + WorkflowAborted string = "WorkflowAborted" ) + +// GenericChaosList only use to list GenericChaos by certain EmbedChaos +// +kubebuilder:object:generate=false +type GenericChaosList interface { + runtime.Object + metav1.ListInterface + GetItems() []GenericChaos + DeepCopyList() GenericChaosList +} + +// GenericChaos could be a place holder for any kubernetes Kind +// +kubebuilder:object:generate=false +type GenericChaos interface { + runtime.Object + metav1.Object +} diff --git a/api/v1alpha1/zz_generated.chaosmesh.go b/api/v1alpha1/zz_generated.chaosmesh.go index b645da9220..73c387a627 100644 --- a/api/v1alpha1/zz_generated.chaosmesh.go +++ b/api/v1alpha1/zz_generated.chaosmesh.go @@ -1,15 +1,19 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// + +// Code generated by chaos-builder. DO NOT EDIT. package v1alpha1 @@ -18,111 +22,63 @@ import ( "reflect" "time" + "github.com/pkg/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + gw "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" ) -const KindAwsChaos = "AwsChaos" +// updating spec of a chaos will have no effect, we'd better reject it +var ErrCanNotUpdateChaos = errors.New("Cannot update chaos spec") + +const KindAWSChaos = "AWSChaos" // IsDeleted returns whether this resource has been deleted -func (in *AwsChaos) IsDeleted() bool { +func (in *AWSChaos) IsDeleted() bool { return !in.DeletionTimestamp.IsZero() } // IsPaused returns whether this resource has been paused -func (in *AwsChaos) IsPaused() bool { +func (in *AWSChaos) IsPaused() bool { if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { return false } return true } +// GetObjectMeta would return the ObjectMeta for chaos +func (in *AWSChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + // GetDuration would return the duration for chaos -func (in *AwsChaos) GetDuration() (*time.Duration, error) { - if in.Spec.Duration == nil { +func (in *AWSChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { return nil, nil } - duration, err := time.ParseDuration(*in.Spec.Duration) + duration, err := time.ParseDuration(string(*in.Duration)) if err != nil { return nil, err } return &duration, nil } -func (in *AwsChaos) GetNextStart() time.Time { - if in.Status.Scheduler.NextStart == nil { - return time.Time{} - } - return in.Status.Scheduler.NextStart.Time -} - -func (in *AwsChaos) SetNextStart(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextStart = nil - return - } - - if in.Status.Scheduler.NextStart == nil { - in.Status.Scheduler.NextStart = &metav1.Time{} - } - in.Status.Scheduler.NextStart.Time = t -} - -func (in *AwsChaos) GetNextRecover() time.Time { - if in.Status.Scheduler.NextRecover == nil { - return time.Time{} - } - return in.Status.Scheduler.NextRecover.Time -} - -func (in *AwsChaos) SetNextRecover(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextRecover = nil - return - } - - if in.Status.Scheduler.NextRecover == nil { - in.Status.Scheduler.NextRecover = &metav1.Time{} - } - in.Status.Scheduler.NextRecover.Time = t -} - -// GetScheduler would return the scheduler for chaos -func (in *AwsChaos) GetScheduler() *SchedulerSpec { - return in.Spec.Scheduler -} - -// GetChaos would return the a record for chaos -func (in *AwsChaos) GetChaos() *ChaosInstance { - instance := &ChaosInstance{ - Name: in.Name, - Namespace: in.Namespace, - Kind: KindAwsChaos, - StartTime: in.CreationTimestamp.Time, - Action: "", - Status: string(in.Status.Experiment.Phase), - UID: string(in.UID), - } - - action := reflect.ValueOf(in).Elem().FieldByName("Spec").FieldByName("Action") - if action.IsValid() { - instance.Action = action.String() - } - if in.Spec.Duration != nil { - instance.Duration = *in.Spec.Duration - } - if in.DeletionTimestamp != nil { - instance.EndTime = in.DeletionTimestamp.Time - } - return instance -} - // GetStatus returns the status -func (in *AwsChaos) GetStatus() *ChaosStatus { +func (in *AWSChaos) GetStatus() *ChaosStatus { return &in.Status.ChaosStatus } +// GetRemoteCluster returns the remoteCluster +func (in *AWSChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + // GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. -func (in *AwsChaos) GetSpecAndMetaString() (string, error) { +func (in *AWSChaos) GetSpecAndMetaString() (string, error) { spec, err := json.Marshal(in.Spec) if err != nil { return "", err @@ -137,124 +93,134 @@ func (in *AwsChaos) GetSpecAndMetaString() (string, error) { // +kubebuilder:object:root=true -// AwsChaosList contains a list of AwsChaos -type AwsChaosList struct { +// AWSChaosList contains a list of AWSChaos +type AWSChaosList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []AwsChaos `json:"items"` + Items []AWSChaos `json:"items"` +} + +func (in *AWSChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() } // ListChaos returns a list of chaos -func (in *AwsChaosList) ListChaos() []*ChaosInstance { - res := make([]*ChaosInstance, 0, len(in.Items)) +func (in *AWSChaosList) ListChaos() []GenericChaos { + var result []GenericChaos for _, item := range in.Items { - res = append(res, item.GetChaos()) + item := item + result = append(result, &item) } - return res + return result } -const KindDNSChaos = "DNSChaos" +func (in *AWSChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err + } -// IsDeleted returns whether this resource has been deleted -func (in *DNSChaos) IsDeleted() bool { - return !in.DeletionTimestamp.IsZero() -} + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } -// IsPaused returns whether this resource has been paused -func (in *DNSChaos) IsPaused() bool { - if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { - return false + return false, stopTime.Sub(now), nil } - return true + + return false, 0, nil } -// GetDuration would return the duration for chaos -func (in *DNSChaos) GetDuration() (*time.Duration, error) { - if in.Spec.Duration == nil { - return nil, nil - } - duration, err := time.ParseDuration(*in.Spec.Duration) - if err != nil { - return nil, err +func (in *AWSChaos) IsOneShot() bool { + if in.Spec.Action==Ec2Restart { + return true } - return &duration, nil + + return false } -func (in *DNSChaos) GetNextStart() time.Time { - if in.Status.Scheduler.NextStart == nil { - return time.Time{} - } - return in.Status.Scheduler.NextStart.Time +var AWSChaosWebhookLog = logf.Log.WithName("AWSChaos-resource") + +func (in *AWSChaos) ValidateCreate() (admission.Warnings, error) { + AWSChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() } -func (in *DNSChaos) SetNextStart(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextStart = nil - return +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *AWSChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + AWSChaosWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*AWSChaos).Spec) { + return nil, ErrCanNotUpdateChaos } + return in.Validate() +} - if in.Status.Scheduler.NextStart == nil { - in.Status.Scheduler.NextStart = &metav1.Time{} - } - in.Status.Scheduler.NextStart.Time = t +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *AWSChaos) ValidateDelete() (admission.Warnings, error) { + AWSChaosWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil } -func (in *DNSChaos) GetNextRecover() time.Time { - if in.Status.Scheduler.NextRecover == nil { - return time.Time{} - } - return in.Status.Scheduler.NextRecover.Time +var _ webhook.Validator = &AWSChaos{} + +func (in *AWSChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) } -func (in *DNSChaos) SetNextRecover(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextRecover = nil - return - } +var _ webhook.Defaulter = &AWSChaos{} - if in.Status.Scheduler.NextRecover == nil { - in.Status.Scheduler.NextRecover = &metav1.Time{} - } - in.Status.Scheduler.NextRecover.Time = t +func (in *AWSChaos) Default() { + gw.Default(in) } -// GetScheduler would return the scheduler for chaos -func (in *DNSChaos) GetScheduler() *SchedulerSpec { - return in.Spec.Scheduler +const KindAzureChaos = "AzureChaos" + +// IsDeleted returns whether this resource has been deleted +func (in *AzureChaos) IsDeleted() bool { + return !in.DeletionTimestamp.IsZero() } -// GetChaos would return the a record for chaos -func (in *DNSChaos) GetChaos() *ChaosInstance { - instance := &ChaosInstance{ - Name: in.Name, - Namespace: in.Namespace, - Kind: KindDNSChaos, - StartTime: in.CreationTimestamp.Time, - Action: "", - Status: string(in.Status.Experiment.Phase), - UID: string(in.UID), +// IsPaused returns whether this resource has been paused +func (in *AzureChaos) IsPaused() bool { + if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { + return false } + return true +} - action := reflect.ValueOf(in).Elem().FieldByName("Spec").FieldByName("Action") - if action.IsValid() { - instance.Action = action.String() - } - if in.Spec.Duration != nil { - instance.Duration = *in.Spec.Duration +// GetObjectMeta would return the ObjectMeta for chaos +func (in *AzureChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + +// GetDuration would return the duration for chaos +func (in *AzureChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { + return nil, nil } - if in.DeletionTimestamp != nil { - instance.EndTime = in.DeletionTimestamp.Time + duration, err := time.ParseDuration(string(*in.Duration)) + if err != nil { + return nil, err } - return instance + return &duration, nil } // GetStatus returns the status -func (in *DNSChaos) GetStatus() *ChaosStatus { +func (in *AzureChaos) GetStatus() *ChaosStatus { return &in.Status.ChaosStatus } +// GetRemoteCluster returns the remoteCluster +func (in *AzureChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + // GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. -func (in *DNSChaos) GetSpecAndMetaString() (string, error) { +func (in *AzureChaos) GetSpecAndMetaString() (string, error) { spec, err := json.Marshal(in.Spec) if err != nil { return "", err @@ -269,124 +235,134 @@ func (in *DNSChaos) GetSpecAndMetaString() (string, error) { // +kubebuilder:object:root=true -// DNSChaosList contains a list of DNSChaos -type DNSChaosList struct { +// AzureChaosList contains a list of AzureChaos +type AzureChaosList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []DNSChaos `json:"items"` + Items []AzureChaos `json:"items"` +} + +func (in *AzureChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() } // ListChaos returns a list of chaos -func (in *DNSChaosList) ListChaos() []*ChaosInstance { - res := make([]*ChaosInstance, 0, len(in.Items)) +func (in *AzureChaosList) ListChaos() []GenericChaos { + var result []GenericChaos for _, item := range in.Items { - res = append(res, item.GetChaos()) + item := item + result = append(result, &item) } - return res + return result } -const KindGcpChaos = "GcpChaos" +func (in *AzureChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err + } -// IsDeleted returns whether this resource has been deleted -func (in *GcpChaos) IsDeleted() bool { - return !in.DeletionTimestamp.IsZero() -} + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } -// IsPaused returns whether this resource has been paused -func (in *GcpChaos) IsPaused() bool { - if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { - return false + return false, stopTime.Sub(now), nil } - return true + + return false, 0, nil } -// GetDuration would return the duration for chaos -func (in *GcpChaos) GetDuration() (*time.Duration, error) { - if in.Spec.Duration == nil { - return nil, nil - } - duration, err := time.ParseDuration(*in.Spec.Duration) - if err != nil { - return nil, err +func (in *AzureChaos) IsOneShot() bool { + if in.Spec.Action==AzureVmRestart { + return true } - return &duration, nil + + return false } -func (in *GcpChaos) GetNextStart() time.Time { - if in.Status.Scheduler.NextStart == nil { - return time.Time{} - } - return in.Status.Scheduler.NextStart.Time +var AzureChaosWebhookLog = logf.Log.WithName("AzureChaos-resource") + +func (in *AzureChaos) ValidateCreate() (admission.Warnings, error) { + AzureChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() } -func (in *GcpChaos) SetNextStart(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextStart = nil - return +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *AzureChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + AzureChaosWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*AzureChaos).Spec) { + return nil, ErrCanNotUpdateChaos } + return in.Validate() +} - if in.Status.Scheduler.NextStart == nil { - in.Status.Scheduler.NextStart = &metav1.Time{} - } - in.Status.Scheduler.NextStart.Time = t +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *AzureChaos) ValidateDelete() (admission.Warnings, error) { + AzureChaosWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil } -func (in *GcpChaos) GetNextRecover() time.Time { - if in.Status.Scheduler.NextRecover == nil { - return time.Time{} - } - return in.Status.Scheduler.NextRecover.Time +var _ webhook.Validator = &AzureChaos{} + +func (in *AzureChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) } -func (in *GcpChaos) SetNextRecover(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextRecover = nil - return - } +var _ webhook.Defaulter = &AzureChaos{} - if in.Status.Scheduler.NextRecover == nil { - in.Status.Scheduler.NextRecover = &metav1.Time{} - } - in.Status.Scheduler.NextRecover.Time = t +func (in *AzureChaos) Default() { + gw.Default(in) } -// GetScheduler would return the scheduler for chaos -func (in *GcpChaos) GetScheduler() *SchedulerSpec { - return in.Spec.Scheduler +const KindBlockChaos = "BlockChaos" + +// IsDeleted returns whether this resource has been deleted +func (in *BlockChaos) IsDeleted() bool { + return !in.DeletionTimestamp.IsZero() } -// GetChaos would return the a record for chaos -func (in *GcpChaos) GetChaos() *ChaosInstance { - instance := &ChaosInstance{ - Name: in.Name, - Namespace: in.Namespace, - Kind: KindGcpChaos, - StartTime: in.CreationTimestamp.Time, - Action: "", - Status: string(in.Status.Experiment.Phase), - UID: string(in.UID), +// IsPaused returns whether this resource has been paused +func (in *BlockChaos) IsPaused() bool { + if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { + return false } + return true +} - action := reflect.ValueOf(in).Elem().FieldByName("Spec").FieldByName("Action") - if action.IsValid() { - instance.Action = action.String() - } - if in.Spec.Duration != nil { - instance.Duration = *in.Spec.Duration +// GetObjectMeta would return the ObjectMeta for chaos +func (in *BlockChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + +// GetDuration would return the duration for chaos +func (in *BlockChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { + return nil, nil } - if in.DeletionTimestamp != nil { - instance.EndTime = in.DeletionTimestamp.Time + duration, err := time.ParseDuration(string(*in.Duration)) + if err != nil { + return nil, err } - return instance + return &duration, nil } // GetStatus returns the status -func (in *GcpChaos) GetStatus() *ChaosStatus { +func (in *BlockChaos) GetStatus() *ChaosStatus { return &in.Status.ChaosStatus } +// GetRemoteCluster returns the remoteCluster +func (in *BlockChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + // GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. -func (in *GcpChaos) GetSpecAndMetaString() (string, error) { +func (in *BlockChaos) GetSpecAndMetaString() (string, error) { spec, err := json.Marshal(in.Spec) if err != nil { return "", err @@ -401,124 +377,130 @@ func (in *GcpChaos) GetSpecAndMetaString() (string, error) { // +kubebuilder:object:root=true -// GcpChaosList contains a list of GcpChaos -type GcpChaosList struct { +// BlockChaosList contains a list of BlockChaos +type BlockChaosList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []GcpChaos `json:"items"` + Items []BlockChaos `json:"items"` +} + +func (in *BlockChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() } // ListChaos returns a list of chaos -func (in *GcpChaosList) ListChaos() []*ChaosInstance { - res := make([]*ChaosInstance, 0, len(in.Items)) +func (in *BlockChaosList) ListChaos() []GenericChaos { + var result []GenericChaos for _, item := range in.Items { - res = append(res, item.GetChaos()) + item := item + result = append(result, &item) } - return res + return result } -const KindHTTPChaos = "HTTPChaos" +func (in *BlockChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err + } -// IsDeleted returns whether this resource has been deleted -func (in *HTTPChaos) IsDeleted() bool { - return !in.DeletionTimestamp.IsZero() -} + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } -// IsPaused returns whether this resource has been paused -func (in *HTTPChaos) IsPaused() bool { - if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { - return false + return false, stopTime.Sub(now), nil } - return true + + return false, 0, nil } -// GetDuration would return the duration for chaos -func (in *HTTPChaos) GetDuration() (*time.Duration, error) { - if in.Spec.Duration == nil { - return nil, nil - } - duration, err := time.ParseDuration(*in.Spec.Duration) - if err != nil { - return nil, err - } - return &duration, nil +func (in *BlockChaos) IsOneShot() bool { + return false } -func (in *HTTPChaos) GetNextStart() time.Time { - if in.Status.Scheduler.NextStart == nil { - return time.Time{} - } - return in.Status.Scheduler.NextStart.Time +var BlockChaosWebhookLog = logf.Log.WithName("BlockChaos-resource") + +func (in *BlockChaos) ValidateCreate() (admission.Warnings, error) { + BlockChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() } -func (in *HTTPChaos) SetNextStart(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextStart = nil - return +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *BlockChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + BlockChaosWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*BlockChaos).Spec) { + return nil, ErrCanNotUpdateChaos } + return in.Validate() +} - if in.Status.Scheduler.NextStart == nil { - in.Status.Scheduler.NextStart = &metav1.Time{} - } - in.Status.Scheduler.NextStart.Time = t +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *BlockChaos) ValidateDelete() (admission.Warnings, error) { + BlockChaosWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil } -func (in *HTTPChaos) GetNextRecover() time.Time { - if in.Status.Scheduler.NextRecover == nil { - return time.Time{} - } - return in.Status.Scheduler.NextRecover.Time +var _ webhook.Validator = &BlockChaos{} + +func (in *BlockChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) } -func (in *HTTPChaos) SetNextRecover(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextRecover = nil - return - } +var _ webhook.Defaulter = &BlockChaos{} - if in.Status.Scheduler.NextRecover == nil { - in.Status.Scheduler.NextRecover = &metav1.Time{} - } - in.Status.Scheduler.NextRecover.Time = t +func (in *BlockChaos) Default() { + gw.Default(in) } -// GetScheduler would return the scheduler for chaos -func (in *HTTPChaos) GetScheduler() *SchedulerSpec { - return in.Spec.Scheduler +const KindDNSChaos = "DNSChaos" + +// IsDeleted returns whether this resource has been deleted +func (in *DNSChaos) IsDeleted() bool { + return !in.DeletionTimestamp.IsZero() } -// GetChaos would return the a record for chaos -func (in *HTTPChaos) GetChaos() *ChaosInstance { - instance := &ChaosInstance{ - Name: in.Name, - Namespace: in.Namespace, - Kind: KindHTTPChaos, - StartTime: in.CreationTimestamp.Time, - Action: "", - Status: string(in.Status.Experiment.Phase), - UID: string(in.UID), +// IsPaused returns whether this resource has been paused +func (in *DNSChaos) IsPaused() bool { + if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { + return false } + return true +} - action := reflect.ValueOf(in).Elem().FieldByName("Spec").FieldByName("Action") - if action.IsValid() { - instance.Action = action.String() - } - if in.Spec.Duration != nil { - instance.Duration = *in.Spec.Duration +// GetObjectMeta would return the ObjectMeta for chaos +func (in *DNSChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + +// GetDuration would return the duration for chaos +func (in *DNSChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { + return nil, nil } - if in.DeletionTimestamp != nil { - instance.EndTime = in.DeletionTimestamp.Time + duration, err := time.ParseDuration(string(*in.Duration)) + if err != nil { + return nil, err } - return instance + return &duration, nil } // GetStatus returns the status -func (in *HTTPChaos) GetStatus() *ChaosStatus { +func (in *DNSChaos) GetStatus() *ChaosStatus { return &in.Status.ChaosStatus } +// GetRemoteCluster returns the remoteCluster +func (in *DNSChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + // GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. -func (in *HTTPChaos) GetSpecAndMetaString() (string, error) { +func (in *DNSChaos) GetSpecAndMetaString() (string, error) { spec, err := json.Marshal(in.Spec) if err != nil { return "", err @@ -533,124 +515,130 @@ func (in *HTTPChaos) GetSpecAndMetaString() (string, error) { // +kubebuilder:object:root=true -// HTTPChaosList contains a list of HTTPChaos -type HTTPChaosList struct { +// DNSChaosList contains a list of DNSChaos +type DNSChaosList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []HTTPChaos `json:"items"` + Items []DNSChaos `json:"items"` +} + +func (in *DNSChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() } // ListChaos returns a list of chaos -func (in *HTTPChaosList) ListChaos() []*ChaosInstance { - res := make([]*ChaosInstance, 0, len(in.Items)) +func (in *DNSChaosList) ListChaos() []GenericChaos { + var result []GenericChaos for _, item := range in.Items { - res = append(res, item.GetChaos()) + item := item + result = append(result, &item) } - return res + return result } -const KindIoChaos = "IoChaos" +func (in *DNSChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err + } -// IsDeleted returns whether this resource has been deleted -func (in *IoChaos) IsDeleted() bool { - return !in.DeletionTimestamp.IsZero() -} + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } -// IsPaused returns whether this resource has been paused -func (in *IoChaos) IsPaused() bool { - if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { - return false + return false, stopTime.Sub(now), nil } - return true + + return false, 0, nil } -// GetDuration would return the duration for chaos -func (in *IoChaos) GetDuration() (*time.Duration, error) { - if in.Spec.Duration == nil { - return nil, nil - } - duration, err := time.ParseDuration(*in.Spec.Duration) - if err != nil { - return nil, err - } - return &duration, nil +func (in *DNSChaos) IsOneShot() bool { + return false } -func (in *IoChaos) GetNextStart() time.Time { - if in.Status.Scheduler.NextStart == nil { - return time.Time{} - } - return in.Status.Scheduler.NextStart.Time +var DNSChaosWebhookLog = logf.Log.WithName("DNSChaos-resource") + +func (in *DNSChaos) ValidateCreate() (admission.Warnings, error) { + DNSChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() } -func (in *IoChaos) SetNextStart(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextStart = nil - return +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *DNSChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + DNSChaosWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*DNSChaos).Spec) { + return nil, ErrCanNotUpdateChaos } + return in.Validate() +} - if in.Status.Scheduler.NextStart == nil { - in.Status.Scheduler.NextStart = &metav1.Time{} - } - in.Status.Scheduler.NextStart.Time = t +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *DNSChaos) ValidateDelete() (admission.Warnings, error) { + DNSChaosWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil } -func (in *IoChaos) GetNextRecover() time.Time { - if in.Status.Scheduler.NextRecover == nil { - return time.Time{} - } - return in.Status.Scheduler.NextRecover.Time +var _ webhook.Validator = &DNSChaos{} + +func (in *DNSChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) } -func (in *IoChaos) SetNextRecover(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextRecover = nil - return - } +var _ webhook.Defaulter = &DNSChaos{} - if in.Status.Scheduler.NextRecover == nil { - in.Status.Scheduler.NextRecover = &metav1.Time{} - } - in.Status.Scheduler.NextRecover.Time = t +func (in *DNSChaos) Default() { + gw.Default(in) } -// GetScheduler would return the scheduler for chaos -func (in *IoChaos) GetScheduler() *SchedulerSpec { - return in.Spec.Scheduler +const KindGCPChaos = "GCPChaos" + +// IsDeleted returns whether this resource has been deleted +func (in *GCPChaos) IsDeleted() bool { + return !in.DeletionTimestamp.IsZero() } -// GetChaos would return the a record for chaos -func (in *IoChaos) GetChaos() *ChaosInstance { - instance := &ChaosInstance{ - Name: in.Name, - Namespace: in.Namespace, - Kind: KindIoChaos, - StartTime: in.CreationTimestamp.Time, - Action: "", - Status: string(in.Status.Experiment.Phase), - UID: string(in.UID), +// IsPaused returns whether this resource has been paused +func (in *GCPChaos) IsPaused() bool { + if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { + return false } + return true +} - action := reflect.ValueOf(in).Elem().FieldByName("Spec").FieldByName("Action") - if action.IsValid() { - instance.Action = action.String() - } - if in.Spec.Duration != nil { - instance.Duration = *in.Spec.Duration +// GetObjectMeta would return the ObjectMeta for chaos +func (in *GCPChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + +// GetDuration would return the duration for chaos +func (in *GCPChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { + return nil, nil } - if in.DeletionTimestamp != nil { - instance.EndTime = in.DeletionTimestamp.Time + duration, err := time.ParseDuration(string(*in.Duration)) + if err != nil { + return nil, err } - return instance + return &duration, nil } // GetStatus returns the status -func (in *IoChaos) GetStatus() *ChaosStatus { +func (in *GCPChaos) GetStatus() *ChaosStatus { return &in.Status.ChaosStatus } +// GetRemoteCluster returns the remoteCluster +func (in *GCPChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + // GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. -func (in *IoChaos) GetSpecAndMetaString() (string, error) { +func (in *GCPChaos) GetSpecAndMetaString() (string, error) { spec, err := json.Marshal(in.Spec) if err != nil { return "", err @@ -665,115 +653,396 @@ func (in *IoChaos) GetSpecAndMetaString() (string, error) { // +kubebuilder:object:root=true -// IoChaosList contains a list of IoChaos -type IoChaosList struct { +// GCPChaosList contains a list of GCPChaos +type GCPChaosList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []IoChaos `json:"items"` + Items []GCPChaos `json:"items"` +} + +func (in *GCPChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() } // ListChaos returns a list of chaos -func (in *IoChaosList) ListChaos() []*ChaosInstance { - res := make([]*ChaosInstance, 0, len(in.Items)) +func (in *GCPChaosList) ListChaos() []GenericChaos { + var result []GenericChaos for _, item := range in.Items { - res = append(res, item.GetChaos()) + item := item + result = append(result, &item) } - return res + return result } -const KindJVMChaos = "JVMChaos" +func (in *GCPChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err + } -// IsDeleted returns whether this resource has been deleted -func (in *JVMChaos) IsDeleted() bool { - return !in.DeletionTimestamp.IsZero() -} + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } -// IsPaused returns whether this resource has been paused -func (in *JVMChaos) IsPaused() bool { - if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { - return false + return false, stopTime.Sub(now), nil } - return true + + return false, 0, nil +} + +func (in *GCPChaos) IsOneShot() bool { + if in.Spec.Action==NodeReset { + return true + } + + return false +} + +var GCPChaosWebhookLog = logf.Log.WithName("GCPChaos-resource") + +func (in *GCPChaos) ValidateCreate() (admission.Warnings, error) { + GCPChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *GCPChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + GCPChaosWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*GCPChaos).Spec) { + return nil, ErrCanNotUpdateChaos + } + return in.Validate() +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *GCPChaos) ValidateDelete() (admission.Warnings, error) { + GCPChaosWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil +} + +var _ webhook.Validator = &GCPChaos{} + +func (in *GCPChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) +} + +var _ webhook.Defaulter = &GCPChaos{} + +func (in *GCPChaos) Default() { + gw.Default(in) +} + +const KindHTTPChaos = "HTTPChaos" + +// IsDeleted returns whether this resource has been deleted +func (in *HTTPChaos) IsDeleted() bool { + return !in.DeletionTimestamp.IsZero() +} + +// IsPaused returns whether this resource has been paused +func (in *HTTPChaos) IsPaused() bool { + if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { + return false + } + return true +} + +// GetObjectMeta would return the ObjectMeta for chaos +func (in *HTTPChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta } // GetDuration would return the duration for chaos -func (in *JVMChaos) GetDuration() (*time.Duration, error) { - if in.Spec.Duration == nil { +func (in *HTTPChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { return nil, nil } - duration, err := time.ParseDuration(*in.Spec.Duration) + duration, err := time.ParseDuration(string(*in.Duration)) if err != nil { return nil, err } return &duration, nil } -func (in *JVMChaos) GetNextStart() time.Time { - if in.Status.Scheduler.NextStart == nil { - return time.Time{} +// GetStatus returns the status +func (in *HTTPChaos) GetStatus() *ChaosStatus { + return &in.Status.ChaosStatus +} + +// GetRemoteCluster returns the remoteCluster +func (in *HTTPChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + +// GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. +func (in *HTTPChaos) GetSpecAndMetaString() (string, error) { + spec, err := json.Marshal(in.Spec) + if err != nil { + return "", err } - return in.Status.Scheduler.NextStart.Time + + meta := in.ObjectMeta.DeepCopy() + meta.SetResourceVersion("") + meta.SetGeneration(0) + + return string(spec) + meta.String(), nil } -func (in *JVMChaos) SetNextStart(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextStart = nil - return +// +kubebuilder:object:root=true + +// HTTPChaosList contains a list of HTTPChaos +type HTTPChaosList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []HTTPChaos `json:"items"` +} + +func (in *HTTPChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() +} + +// ListChaos returns a list of chaos +func (in *HTTPChaosList) ListChaos() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} + +func (in *HTTPChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err } - if in.Status.Scheduler.NextStart == nil { - in.Status.Scheduler.NextStart = &metav1.Time{} + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } + + return false, stopTime.Sub(now), nil } - in.Status.Scheduler.NextStart.Time = t + + return false, 0, nil +} + +func (in *HTTPChaos) IsOneShot() bool { + return false +} + +var HTTPChaosWebhookLog = logf.Log.WithName("HTTPChaos-resource") + +func (in *HTTPChaos) ValidateCreate() (admission.Warnings, error) { + HTTPChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() } -func (in *JVMChaos) GetNextRecover() time.Time { - if in.Status.Scheduler.NextRecover == nil { - return time.Time{} +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *HTTPChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + HTTPChaosWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*HTTPChaos).Spec) { + return nil, ErrCanNotUpdateChaos } - return in.Status.Scheduler.NextRecover.Time + return in.Validate() } -func (in *JVMChaos) SetNextRecover(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextRecover = nil - return +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *HTTPChaos) ValidateDelete() (admission.Warnings, error) { + HTTPChaosWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil +} + +var _ webhook.Validator = &HTTPChaos{} + +func (in *HTTPChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) +} + +var _ webhook.Defaulter = &HTTPChaos{} + +func (in *HTTPChaos) Default() { + gw.Default(in) +} + +const KindIOChaos = "IOChaos" + +// IsDeleted returns whether this resource has been deleted +func (in *IOChaos) IsDeleted() bool { + return !in.DeletionTimestamp.IsZero() +} + +// IsPaused returns whether this resource has been paused +func (in *IOChaos) IsPaused() bool { + if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { + return false } + return true +} - if in.Status.Scheduler.NextRecover == nil { - in.Status.Scheduler.NextRecover = &metav1.Time{} +// GetObjectMeta would return the ObjectMeta for chaos +func (in *IOChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + +// GetDuration would return the duration for chaos +func (in *IOChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { + return nil, nil } - in.Status.Scheduler.NextRecover.Time = t + duration, err := time.ParseDuration(string(*in.Duration)) + if err != nil { + return nil, err + } + return &duration, nil +} + +// GetStatus returns the status +func (in *IOChaos) GetStatus() *ChaosStatus { + return &in.Status.ChaosStatus } -// GetScheduler would return the scheduler for chaos -func (in *JVMChaos) GetScheduler() *SchedulerSpec { - return in.Spec.Scheduler +// GetRemoteCluster returns the remoteCluster +func (in *IOChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster } -// GetChaos would return the a record for chaos -func (in *JVMChaos) GetChaos() *ChaosInstance { - instance := &ChaosInstance{ - Name: in.Name, - Namespace: in.Namespace, - Kind: KindJVMChaos, - StartTime: in.CreationTimestamp.Time, - Action: "", - Status: string(in.Status.Experiment.Phase), - UID: string(in.UID), +// GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. +func (in *IOChaos) GetSpecAndMetaString() (string, error) { + spec, err := json.Marshal(in.Spec) + if err != nil { + return "", err } - action := reflect.ValueOf(in).Elem().FieldByName("Spec").FieldByName("Action") - if action.IsValid() { - instance.Action = action.String() + meta := in.ObjectMeta.DeepCopy() + meta.SetResourceVersion("") + meta.SetGeneration(0) + + return string(spec) + meta.String(), nil +} + +// +kubebuilder:object:root=true + +// IOChaosList contains a list of IOChaos +type IOChaosList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []IOChaos `json:"items"` +} + +func (in *IOChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() +} + +// ListChaos returns a list of chaos +func (in *IOChaosList) ListChaos() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) } - if in.Spec.Duration != nil { - instance.Duration = *in.Spec.Duration + return result +} + +func (in *IOChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err } - if in.DeletionTimestamp != nil { - instance.EndTime = in.DeletionTimestamp.Time + + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } + + return false, stopTime.Sub(now), nil } - return instance + + return false, 0, nil +} + +func (in *IOChaos) IsOneShot() bool { + return false +} + +var IOChaosWebhookLog = logf.Log.WithName("IOChaos-resource") + +func (in *IOChaos) ValidateCreate() (admission.Warnings, error) { + IOChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *IOChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + IOChaosWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*IOChaos).Spec) { + return nil, ErrCanNotUpdateChaos + } + return in.Validate() +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *IOChaos) ValidateDelete() (admission.Warnings, error) { + IOChaosWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil +} + +var _ webhook.Validator = &IOChaos{} + +func (in *IOChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) +} + +var _ webhook.Defaulter = &IOChaos{} + +func (in *IOChaos) Default() { + gw.Default(in) +} + +const KindJVMChaos = "JVMChaos" + +// IsDeleted returns whether this resource has been deleted +func (in *JVMChaos) IsDeleted() bool { + return !in.DeletionTimestamp.IsZero() +} + +// IsPaused returns whether this resource has been paused +func (in *JVMChaos) IsPaused() bool { + if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { + return false + } + return true +} + +// GetObjectMeta would return the ObjectMeta for chaos +func (in *JVMChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + +// GetDuration would return the duration for chaos +func (in *JVMChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { + return nil, nil + } + duration, err := time.ParseDuration(string(*in.Duration)) + if err != nil { + return nil, err + } + return &duration, nil } // GetStatus returns the status @@ -781,6 +1050,11 @@ func (in *JVMChaos) GetStatus() *ChaosStatus { return &in.Status.ChaosStatus } +// GetRemoteCluster returns the remoteCluster +func (in *JVMChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + // GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. func (in *JVMChaos) GetSpecAndMetaString() (string, error) { spec, err := json.Marshal(in.Spec) @@ -804,13 +1078,77 @@ type JVMChaosList struct { Items []JVMChaos `json:"items"` } +func (in *JVMChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() +} + // ListChaos returns a list of chaos -func (in *JVMChaosList) ListChaos() []*ChaosInstance { - res := make([]*ChaosInstance, 0, len(in.Items)) +func (in *JVMChaosList) ListChaos() []GenericChaos { + var result []GenericChaos for _, item := range in.Items { - res = append(res, item.GetChaos()) + item := item + result = append(result, &item) + } + return result +} + +func (in *JVMChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err + } + + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } + + return false, stopTime.Sub(now), nil + } + + return false, 0, nil +} + +func (in *JVMChaos) IsOneShot() bool { + return false +} + +var JVMChaosWebhookLog = logf.Log.WithName("JVMChaos-resource") + +func (in *JVMChaos) ValidateCreate() (admission.Warnings, error) { + JVMChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *JVMChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + JVMChaosWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*JVMChaos).Spec) { + return nil, ErrCanNotUpdateChaos } - return res + return in.Validate() +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *JVMChaos) ValidateDelete() (admission.Warnings, error) { + JVMChaosWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil +} + +var _ webhook.Validator = &JVMChaos{} + +func (in *JVMChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) +} + +var _ webhook.Defaulter = &JVMChaos{} + +func (in *JVMChaos) Default() { + gw.Default(in) } const KindKernelChaos = "KernelChaos" @@ -828,93 +1166,311 @@ func (in *KernelChaos) IsPaused() bool { return true } +// GetObjectMeta would return the ObjectMeta for chaos +func (in *KernelChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + // GetDuration would return the duration for chaos -func (in *KernelChaos) GetDuration() (*time.Duration, error) { - if in.Spec.Duration == nil { +func (in *KernelChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { return nil, nil } - duration, err := time.ParseDuration(*in.Spec.Duration) + duration, err := time.ParseDuration(string(*in.Duration)) if err != nil { return nil, err } return &duration, nil } -func (in *KernelChaos) GetNextStart() time.Time { - if in.Status.Scheduler.NextStart == nil { - return time.Time{} +// GetStatus returns the status +func (in *KernelChaos) GetStatus() *ChaosStatus { + return &in.Status.ChaosStatus +} + +// GetRemoteCluster returns the remoteCluster +func (in *KernelChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + +// GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. +func (in *KernelChaos) GetSpecAndMetaString() (string, error) { + spec, err := json.Marshal(in.Spec) + if err != nil { + return "", err } - return in.Status.Scheduler.NextStart.Time + + meta := in.ObjectMeta.DeepCopy() + meta.SetResourceVersion("") + meta.SetGeneration(0) + + return string(spec) + meta.String(), nil +} + +// +kubebuilder:object:root=true + +// KernelChaosList contains a list of KernelChaos +type KernelChaosList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []KernelChaos `json:"items"` } -func (in *KernelChaos) SetNextStart(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextStart = nil - return +func (in *KernelChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() +} + +// ListChaos returns a list of chaos +func (in *KernelChaosList) ListChaos() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) } + return result +} - if in.Status.Scheduler.NextStart == nil { - in.Status.Scheduler.NextStart = &metav1.Time{} +func (in *KernelChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err } - in.Status.Scheduler.NextStart.Time = t + + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } + + return false, stopTime.Sub(now), nil + } + + return false, 0, nil +} + +func (in *KernelChaos) IsOneShot() bool { + return false +} + +var KernelChaosWebhookLog = logf.Log.WithName("KernelChaos-resource") + +func (in *KernelChaos) ValidateCreate() (admission.Warnings, error) { + KernelChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *KernelChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + KernelChaosWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*KernelChaos).Spec) { + return nil, ErrCanNotUpdateChaos + } + return in.Validate() +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *KernelChaos) ValidateDelete() (admission.Warnings, error) { + KernelChaosWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil +} + +var _ webhook.Validator = &KernelChaos{} + +func (in *KernelChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) +} + +var _ webhook.Defaulter = &KernelChaos{} + +func (in *KernelChaos) Default() { + gw.Default(in) +} + +const KindNetworkChaos = "NetworkChaos" + +// IsDeleted returns whether this resource has been deleted +func (in *NetworkChaos) IsDeleted() bool { + return !in.DeletionTimestamp.IsZero() +} + +// IsPaused returns whether this resource has been paused +func (in *NetworkChaos) IsPaused() bool { + if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { + return false + } + return true +} + +// GetObjectMeta would return the ObjectMeta for chaos +func (in *NetworkChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + +// GetDuration would return the duration for chaos +func (in *NetworkChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { + return nil, nil + } + duration, err := time.ParseDuration(string(*in.Duration)) + if err != nil { + return nil, err + } + return &duration, nil +} + +// GetStatus returns the status +func (in *NetworkChaos) GetStatus() *ChaosStatus { + return &in.Status.ChaosStatus +} + +// GetRemoteCluster returns the remoteCluster +func (in *NetworkChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + +// GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. +func (in *NetworkChaos) GetSpecAndMetaString() (string, error) { + spec, err := json.Marshal(in.Spec) + if err != nil { + return "", err + } + + meta := in.ObjectMeta.DeepCopy() + meta.SetResourceVersion("") + meta.SetGeneration(0) + + return string(spec) + meta.String(), nil +} + +// +kubebuilder:object:root=true + +// NetworkChaosList contains a list of NetworkChaos +type NetworkChaosList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []NetworkChaos `json:"items"` +} + +func (in *NetworkChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() } -func (in *KernelChaos) GetNextRecover() time.Time { - if in.Status.Scheduler.NextRecover == nil { - return time.Time{} +// ListChaos returns a list of chaos +func (in *NetworkChaosList) ListChaos() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) } - return in.Status.Scheduler.NextRecover.Time + return result } -func (in *KernelChaos) SetNextRecover(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextRecover = nil - return +func (in *NetworkChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err } - if in.Status.Scheduler.NextRecover == nil { - in.Status.Scheduler.NextRecover = &metav1.Time{} + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } + + return false, stopTime.Sub(now), nil } - in.Status.Scheduler.NextRecover.Time = t + + return false, 0, nil +} + +func (in *NetworkChaos) IsOneShot() bool { + return false } -// GetScheduler would return the scheduler for chaos -func (in *KernelChaos) GetScheduler() *SchedulerSpec { - return in.Spec.Scheduler +var NetworkChaosWebhookLog = logf.Log.WithName("NetworkChaos-resource") + +func (in *NetworkChaos) ValidateCreate() (admission.Warnings, error) { + NetworkChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() } -// GetChaos would return the a record for chaos -func (in *KernelChaos) GetChaos() *ChaosInstance { - instance := &ChaosInstance{ - Name: in.Name, - Namespace: in.Namespace, - Kind: KindKernelChaos, - StartTime: in.CreationTimestamp.Time, - Action: "", - Status: string(in.Status.Experiment.Phase), - UID: string(in.UID), +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *NetworkChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + NetworkChaosWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*NetworkChaos).Spec) { + return nil, ErrCanNotUpdateChaos } + return in.Validate() +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *NetworkChaos) ValidateDelete() (admission.Warnings, error) { + NetworkChaosWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil +} + +var _ webhook.Validator = &NetworkChaos{} + +func (in *NetworkChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) +} - action := reflect.ValueOf(in).Elem().FieldByName("Spec").FieldByName("Action") - if action.IsValid() { - instance.Action = action.String() +var _ webhook.Defaulter = &NetworkChaos{} + +func (in *NetworkChaos) Default() { + gw.Default(in) +} + +const KindPhysicalMachineChaos = "PhysicalMachineChaos" + +// IsDeleted returns whether this resource has been deleted +func (in *PhysicalMachineChaos) IsDeleted() bool { + return !in.DeletionTimestamp.IsZero() +} + +// IsPaused returns whether this resource has been paused +func (in *PhysicalMachineChaos) IsPaused() bool { + if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { + return false } - if in.Spec.Duration != nil { - instance.Duration = *in.Spec.Duration + return true +} + +// GetObjectMeta would return the ObjectMeta for chaos +func (in *PhysicalMachineChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + +// GetDuration would return the duration for chaos +func (in *PhysicalMachineChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { + return nil, nil } - if in.DeletionTimestamp != nil { - instance.EndTime = in.DeletionTimestamp.Time + duration, err := time.ParseDuration(string(*in.Duration)) + if err != nil { + return nil, err } - return instance + return &duration, nil } // GetStatus returns the status -func (in *KernelChaos) GetStatus() *ChaosStatus { +func (in *PhysicalMachineChaos) GetStatus() *ChaosStatus { return &in.Status.ChaosStatus } +// GetRemoteCluster returns the remoteCluster +func (in *PhysicalMachineChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + // GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. -func (in *KernelChaos) GetSpecAndMetaString() (string, error) { +func (in *PhysicalMachineChaos) GetSpecAndMetaString() (string, error) { spec, err := json.Marshal(in.Spec) if err != nil { return "", err @@ -929,284 +1485,451 @@ func (in *KernelChaos) GetSpecAndMetaString() (string, error) { // +kubebuilder:object:root=true -// KernelChaosList contains a list of KernelChaos -type KernelChaosList struct { +// PhysicalMachineChaosList contains a list of PhysicalMachineChaos +type PhysicalMachineChaosList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []KernelChaos `json:"items"` + Items []PhysicalMachineChaos `json:"items"` +} + +func (in *PhysicalMachineChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() } // ListChaos returns a list of chaos -func (in *KernelChaosList) ListChaos() []*ChaosInstance { - res := make([]*ChaosInstance, 0, len(in.Items)) +func (in *PhysicalMachineChaosList) ListChaos() []GenericChaos { + var result []GenericChaos for _, item := range in.Items { - res = append(res, item.GetChaos()) + item := item + result = append(result, &item) + } + return result +} + +func (in *PhysicalMachineChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err + } + + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } + + return false, stopTime.Sub(now), nil + } + + return false, 0, nil +} + +func (in *PhysicalMachineChaos) IsOneShot() bool { + return false +} + +var PhysicalMachineChaosWebhookLog = logf.Log.WithName("PhysicalMachineChaos-resource") + +func (in *PhysicalMachineChaos) ValidateCreate() (admission.Warnings, error) { + PhysicalMachineChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *PhysicalMachineChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + PhysicalMachineChaosWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*PhysicalMachineChaos).Spec) { + return nil, ErrCanNotUpdateChaos + } + return in.Validate() +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *PhysicalMachineChaos) ValidateDelete() (admission.Warnings, error) { + PhysicalMachineChaosWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil +} + +var _ webhook.Validator = &PhysicalMachineChaos{} + +func (in *PhysicalMachineChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) +} + +var _ webhook.Defaulter = &PhysicalMachineChaos{} + +func (in *PhysicalMachineChaos) Default() { + gw.Default(in) +} + +const KindPhysicalMachine = "PhysicalMachine" + +var PhysicalMachineWebhookLog = logf.Log.WithName("PhysicalMachine-resource") + +func (in *PhysicalMachine) ValidateCreate() (admission.Warnings, error) { + PhysicalMachineWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *PhysicalMachine) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + PhysicalMachineWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*PhysicalMachine).Spec) { + return nil, ErrCanNotUpdateChaos + } + return in.Validate() +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *PhysicalMachine) ValidateDelete() (admission.Warnings, error) { + PhysicalMachineWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil +} + +var _ webhook.Validator = &PhysicalMachine{} + +func (in *PhysicalMachine) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) +} + +var _ webhook.Defaulter = &PhysicalMachine{} + +func (in *PhysicalMachine) Default() { + gw.Default(in) +} + +const KindPodChaos = "PodChaos" + +// IsDeleted returns whether this resource has been deleted +func (in *PodChaos) IsDeleted() bool { + return !in.DeletionTimestamp.IsZero() +} + +// IsPaused returns whether this resource has been paused +func (in *PodChaos) IsPaused() bool { + if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { + return false + } + return true +} + +// GetObjectMeta would return the ObjectMeta for chaos +func (in *PodChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + +// GetDuration would return the duration for chaos +func (in *PodChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { + return nil, nil + } + duration, err := time.ParseDuration(string(*in.Duration)) + if err != nil { + return nil, err + } + return &duration, nil +} + +// GetStatus returns the status +func (in *PodChaos) GetStatus() *ChaosStatus { + return &in.Status.ChaosStatus +} + +// GetRemoteCluster returns the remoteCluster +func (in *PodChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + +// GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. +func (in *PodChaos) GetSpecAndMetaString() (string, error) { + spec, err := json.Marshal(in.Spec) + if err != nil { + return "", err + } + + meta := in.ObjectMeta.DeepCopy() + meta.SetResourceVersion("") + meta.SetGeneration(0) + + return string(spec) + meta.String(), nil +} + +// +kubebuilder:object:root=true + +// PodChaosList contains a list of PodChaos +type PodChaosList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []PodChaos `json:"items"` +} + +func (in *PodChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() +} + +// ListChaos returns a list of chaos +func (in *PodChaosList) ListChaos() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} + +func (in *PodChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err + } + + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } + + return false, stopTime.Sub(now), nil + } + + return false, 0, nil +} + +func (in *PodChaos) IsOneShot() bool { + if in.Spec.Action==PodKillAction || in.Spec.Action==ContainerKillAction { + return true + } + + return false +} + +var PodChaosWebhookLog = logf.Log.WithName("PodChaos-resource") + +func (in *PodChaos) ValidateCreate() (admission.Warnings, error) { + PodChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *PodChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + PodChaosWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*PodChaos).Spec) { + return nil, ErrCanNotUpdateChaos } - return res + return in.Validate() } -const KindNetworkChaos = "NetworkChaos" +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *PodChaos) ValidateDelete() (admission.Warnings, error) { + PodChaosWebhookLog.Info("validate delete", "name", in.Name) -// IsDeleted returns whether this resource has been deleted -func (in *NetworkChaos) IsDeleted() bool { - return !in.DeletionTimestamp.IsZero() + // Nothing to do? + return nil, nil } -// IsPaused returns whether this resource has been paused -func (in *NetworkChaos) IsPaused() bool { - if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { - return false - } - return true -} +var _ webhook.Validator = &PodChaos{} -// GetDuration would return the duration for chaos -func (in *NetworkChaos) GetDuration() (*time.Duration, error) { - if in.Spec.Duration == nil { - return nil, nil - } - duration, err := time.ParseDuration(*in.Spec.Duration) - if err != nil { - return nil, err - } - return &duration, nil +func (in *PodChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) } -func (in *NetworkChaos) GetNextStart() time.Time { - if in.Status.Scheduler.NextStart == nil { - return time.Time{} - } - return in.Status.Scheduler.NextStart.Time +var _ webhook.Defaulter = &PodChaos{} + +func (in *PodChaos) Default() { + gw.Default(in) } -func (in *NetworkChaos) SetNextStart(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextStart = nil - return - } +const KindPodHttpChaos = "PodHttpChaos" - if in.Status.Scheduler.NextStart == nil { - in.Status.Scheduler.NextStart = &metav1.Time{} - } - in.Status.Scheduler.NextStart.Time = t +var PodHttpChaosWebhookLog = logf.Log.WithName("PodHttpChaos-resource") + +func (in *PodHttpChaos) ValidateCreate() (admission.Warnings, error) { + PodHttpChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() } -func (in *NetworkChaos) GetNextRecover() time.Time { - if in.Status.Scheduler.NextRecover == nil { - return time.Time{} - } - return in.Status.Scheduler.NextRecover.Time +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *PodHttpChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + PodHttpChaosWebhookLog.Info("validate update", "name", in.Name) + return in.Validate() } -func (in *NetworkChaos) SetNextRecover(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextRecover = nil - return - } +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *PodHttpChaos) ValidateDelete() (admission.Warnings, error) { + PodHttpChaosWebhookLog.Info("validate delete", "name", in.Name) - if in.Status.Scheduler.NextRecover == nil { - in.Status.Scheduler.NextRecover = &metav1.Time{} - } - in.Status.Scheduler.NextRecover.Time = t + // Nothing to do? + return nil, nil } -// GetScheduler would return the scheduler for chaos -func (in *NetworkChaos) GetScheduler() *SchedulerSpec { - return in.Spec.Scheduler +var _ webhook.Validator = &PodHttpChaos{} + +func (in *PodHttpChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) } -// GetChaos would return the a record for chaos -func (in *NetworkChaos) GetChaos() *ChaosInstance { - instance := &ChaosInstance{ - Name: in.Name, - Namespace: in.Namespace, - Kind: KindNetworkChaos, - StartTime: in.CreationTimestamp.Time, - Action: "", - Status: string(in.Status.Experiment.Phase), - UID: string(in.UID), - } +var _ webhook.Defaulter = &PodHttpChaos{} - action := reflect.ValueOf(in).Elem().FieldByName("Spec").FieldByName("Action") - if action.IsValid() { - instance.Action = action.String() - } - if in.Spec.Duration != nil { - instance.Duration = *in.Spec.Duration - } - if in.DeletionTimestamp != nil { - instance.EndTime = in.DeletionTimestamp.Time - } - return instance +func (in *PodHttpChaos) Default() { + gw.Default(in) } -// GetStatus returns the status -func (in *NetworkChaos) GetStatus() *ChaosStatus { - return &in.Status.ChaosStatus +const KindPodIOChaos = "PodIOChaos" + +var PodIOChaosWebhookLog = logf.Log.WithName("PodIOChaos-resource") + +func (in *PodIOChaos) ValidateCreate() (admission.Warnings, error) { + PodIOChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() } -// GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. -func (in *NetworkChaos) GetSpecAndMetaString() (string, error) { - spec, err := json.Marshal(in.Spec) - if err != nil { - return "", err - } +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *PodIOChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + PodIOChaosWebhookLog.Info("validate update", "name", in.Name) + return in.Validate() +} - meta := in.ObjectMeta.DeepCopy() - meta.SetResourceVersion("") - meta.SetGeneration(0) +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *PodIOChaos) ValidateDelete() (admission.Warnings, error) { + PodIOChaosWebhookLog.Info("validate delete", "name", in.Name) - return string(spec) + meta.String(), nil + // Nothing to do? + return nil, nil } -// +kubebuilder:object:root=true +var _ webhook.Validator = &PodIOChaos{} -// NetworkChaosList contains a list of NetworkChaos -type NetworkChaosList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []NetworkChaos `json:"items"` +func (in *PodIOChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) } -// ListChaos returns a list of chaos -func (in *NetworkChaosList) ListChaos() []*ChaosInstance { - res := make([]*ChaosInstance, 0, len(in.Items)) - for _, item := range in.Items { - res = append(res, item.GetChaos()) - } - return res +var _ webhook.Defaulter = &PodIOChaos{} + +func (in *PodIOChaos) Default() { + gw.Default(in) } -const KindPodChaos = "PodChaos" +const KindPodNetworkChaos = "PodNetworkChaos" -// IsDeleted returns whether this resource has been deleted -func (in *PodChaos) IsDeleted() bool { - return !in.DeletionTimestamp.IsZero() +var PodNetworkChaosWebhookLog = logf.Log.WithName("PodNetworkChaos-resource") + +func (in *PodNetworkChaos) ValidateCreate() (admission.Warnings, error) { + PodNetworkChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() } -// IsPaused returns whether this resource has been paused -func (in *PodChaos) IsPaused() bool { - if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { - return false - } - return true +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *PodNetworkChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + PodNetworkChaosWebhookLog.Info("validate update", "name", in.Name) + return in.Validate() } -// GetDuration would return the duration for chaos -func (in *PodChaos) GetDuration() (*time.Duration, error) { - if in.Spec.Duration == nil { - return nil, nil - } - duration, err := time.ParseDuration(*in.Spec.Duration) - if err != nil { - return nil, err - } - return &duration, nil +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *PodNetworkChaos) ValidateDelete() (admission.Warnings, error) { + PodNetworkChaosWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil } -func (in *PodChaos) GetNextStart() time.Time { - if in.Status.Scheduler.NextStart == nil { - return time.Time{} - } - return in.Status.Scheduler.NextStart.Time +var _ webhook.Validator = &PodNetworkChaos{} + +func (in *PodNetworkChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) } -func (in *PodChaos) SetNextStart(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextStart = nil - return - } +var _ webhook.Defaulter = &PodNetworkChaos{} - if in.Status.Scheduler.NextStart == nil { - in.Status.Scheduler.NextStart = &metav1.Time{} - } - in.Status.Scheduler.NextStart.Time = t +func (in *PodNetworkChaos) Default() { + gw.Default(in) } -func (in *PodChaos) GetNextRecover() time.Time { - if in.Status.Scheduler.NextRecover == nil { - return time.Time{} - } - return in.Status.Scheduler.NextRecover.Time +const KindRemoteCluster = "RemoteCluster" + +var RemoteClusterWebhookLog = logf.Log.WithName("RemoteCluster-resource") + +func (in *RemoteCluster) ValidateCreate() (admission.Warnings, error) { + RemoteClusterWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() } -func (in *PodChaos) SetNextRecover(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextRecover = nil - return +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *RemoteCluster) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + RemoteClusterWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*RemoteCluster).Spec) { + return nil, ErrCanNotUpdateChaos } + return in.Validate() +} - if in.Status.Scheduler.NextRecover == nil { - in.Status.Scheduler.NextRecover = &metav1.Time{} - } - in.Status.Scheduler.NextRecover.Time = t +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *RemoteCluster) ValidateDelete() (admission.Warnings, error) { + RemoteClusterWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil } -// GetScheduler would return the scheduler for chaos -func (in *PodChaos) GetScheduler() *SchedulerSpec { - return in.Spec.Scheduler +var _ webhook.Validator = &RemoteCluster{} + +func (in *RemoteCluster) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) } -// GetChaos would return the a record for chaos -func (in *PodChaos) GetChaos() *ChaosInstance { - instance := &ChaosInstance{ - Name: in.Name, - Namespace: in.Namespace, - Kind: KindPodChaos, - StartTime: in.CreationTimestamp.Time, - Action: "", - Status: string(in.Status.Experiment.Phase), - UID: string(in.UID), - } +var _ webhook.Defaulter = &RemoteCluster{} - action := reflect.ValueOf(in).Elem().FieldByName("Spec").FieldByName("Action") - if action.IsValid() { - instance.Action = action.String() - } - if in.Spec.Duration != nil { - instance.Duration = *in.Spec.Duration - } - if in.DeletionTimestamp != nil { - instance.EndTime = in.DeletionTimestamp.Time - } - return instance +func (in *RemoteCluster) Default() { + gw.Default(in) } -// GetStatus returns the status -func (in *PodChaos) GetStatus() *ChaosStatus { - return &in.Status.ChaosStatus +const KindStatusCheck = "StatusCheck" + +var StatusCheckWebhookLog = logf.Log.WithName("StatusCheck-resource") + +func (in *StatusCheck) ValidateCreate() (admission.Warnings, error) { + StatusCheckWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() } -// GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. -func (in *PodChaos) GetSpecAndMetaString() (string, error) { - spec, err := json.Marshal(in.Spec) - if err != nil { - return "", err +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *StatusCheck) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + StatusCheckWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*StatusCheck).Spec) { + return nil, ErrCanNotUpdateChaos } + return in.Validate() +} - meta := in.ObjectMeta.DeepCopy() - meta.SetResourceVersion("") - meta.SetGeneration(0) +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *StatusCheck) ValidateDelete() (admission.Warnings, error) { + StatusCheckWebhookLog.Info("validate delete", "name", in.Name) - return string(spec) + meta.String(), nil + // Nothing to do? + return nil, nil } -// +kubebuilder:object:root=true +var _ webhook.Validator = &StatusCheck{} -// PodChaosList contains a list of PodChaos -type PodChaosList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []PodChaos `json:"items"` +func (in *StatusCheck) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) } -// ListChaos returns a list of chaos -func (in *PodChaosList) ListChaos() []*ChaosInstance { - res := make([]*ChaosInstance, 0, len(in.Items)) - for _, item := range in.Items { - res = append(res, item.GetChaos()) - } - return res +var _ webhook.Defaulter = &StatusCheck{} + +func (in *StatusCheck) Default() { + gw.Default(in) } const KindStressChaos = "StressChaos" @@ -1224,91 +1947,33 @@ func (in *StressChaos) IsPaused() bool { return true } +// GetObjectMeta would return the ObjectMeta for chaos +func (in *StressChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + // GetDuration would return the duration for chaos -func (in *StressChaos) GetDuration() (*time.Duration, error) { - if in.Spec.Duration == nil { +func (in *StressChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { return nil, nil } - duration, err := time.ParseDuration(*in.Spec.Duration) + duration, err := time.ParseDuration(string(*in.Duration)) if err != nil { return nil, err } return &duration, nil } -func (in *StressChaos) GetNextStart() time.Time { - if in.Status.Scheduler.NextStart == nil { - return time.Time{} - } - return in.Status.Scheduler.NextStart.Time -} - -func (in *StressChaos) SetNextStart(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextStart = nil - return - } - - if in.Status.Scheduler.NextStart == nil { - in.Status.Scheduler.NextStart = &metav1.Time{} - } - in.Status.Scheduler.NextStart.Time = t -} - -func (in *StressChaos) GetNextRecover() time.Time { - if in.Status.Scheduler.NextRecover == nil { - return time.Time{} - } - return in.Status.Scheduler.NextRecover.Time -} - -func (in *StressChaos) SetNextRecover(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextRecover = nil - return - } - - if in.Status.Scheduler.NextRecover == nil { - in.Status.Scheduler.NextRecover = &metav1.Time{} - } - in.Status.Scheduler.NextRecover.Time = t -} - -// GetScheduler would return the scheduler for chaos -func (in *StressChaos) GetScheduler() *SchedulerSpec { - return in.Spec.Scheduler -} - -// GetChaos would return the a record for chaos -func (in *StressChaos) GetChaos() *ChaosInstance { - instance := &ChaosInstance{ - Name: in.Name, - Namespace: in.Namespace, - Kind: KindStressChaos, - StartTime: in.CreationTimestamp.Time, - Action: "", - Status: string(in.Status.Experiment.Phase), - UID: string(in.UID), - } - - action := reflect.ValueOf(in).Elem().FieldByName("Spec").FieldByName("Action") - if action.IsValid() { - instance.Action = action.String() - } - if in.Spec.Duration != nil { - instance.Duration = *in.Spec.Duration - } - if in.DeletionTimestamp != nil { - instance.EndTime = in.DeletionTimestamp.Time - } - return instance -} - // GetStatus returns the status func (in *StressChaos) GetStatus() *ChaosStatus { return &in.Status.ChaosStatus } +// GetRemoteCluster returns the remoteCluster +func (in *StressChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + // GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. func (in *StressChaos) GetSpecAndMetaString() (string, error) { spec, err := json.Marshal(in.Spec) @@ -1332,108 +1997,109 @@ type StressChaosList struct { Items []StressChaos `json:"items"` } +func (in *StressChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() +} + // ListChaos returns a list of chaos -func (in *StressChaosList) ListChaos() []*ChaosInstance { - res := make([]*ChaosInstance, 0, len(in.Items)) +func (in *StressChaosList) ListChaos() []GenericChaos { + var result []GenericChaos for _, item := range in.Items { - res = append(res, item.GetChaos()) + item := item + result = append(result, &item) } - return res + return result } -const KindTimeChaos = "TimeChaos" +func (in *StressChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err + } -// IsDeleted returns whether this resource has been deleted -func (in *TimeChaos) IsDeleted() bool { - return !in.DeletionTimestamp.IsZero() -} + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } -// IsPaused returns whether this resource has been paused -func (in *TimeChaos) IsPaused() bool { - if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { - return false + return false, stopTime.Sub(now), nil } - return true + + return false, 0, nil } -// GetDuration would return the duration for chaos -func (in *TimeChaos) GetDuration() (*time.Duration, error) { - if in.Spec.Duration == nil { - return nil, nil - } - duration, err := time.ParseDuration(*in.Spec.Duration) - if err != nil { - return nil, err - } - return &duration, nil +func (in *StressChaos) IsOneShot() bool { + return false } -func (in *TimeChaos) GetNextStart() time.Time { - if in.Status.Scheduler.NextStart == nil { - return time.Time{} - } - return in.Status.Scheduler.NextStart.Time +var StressChaosWebhookLog = logf.Log.WithName("StressChaos-resource") + +func (in *StressChaos) ValidateCreate() (admission.Warnings, error) { + StressChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() } -func (in *TimeChaos) SetNextStart(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextStart = nil - return +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *StressChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + StressChaosWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*StressChaos).Spec) { + return nil, ErrCanNotUpdateChaos } + return in.Validate() +} - if in.Status.Scheduler.NextStart == nil { - in.Status.Scheduler.NextStart = &metav1.Time{} - } - in.Status.Scheduler.NextStart.Time = t +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *StressChaos) ValidateDelete() (admission.Warnings, error) { + StressChaosWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil } -func (in *TimeChaos) GetNextRecover() time.Time { - if in.Status.Scheduler.NextRecover == nil { - return time.Time{} - } - return in.Status.Scheduler.NextRecover.Time +var _ webhook.Validator = &StressChaos{} + +func (in *StressChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) } -func (in *TimeChaos) SetNextRecover(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextRecover = nil - return - } +var _ webhook.Defaulter = &StressChaos{} - if in.Status.Scheduler.NextRecover == nil { - in.Status.Scheduler.NextRecover = &metav1.Time{} - } - in.Status.Scheduler.NextRecover.Time = t +func (in *StressChaos) Default() { + gw.Default(in) } -// GetScheduler would return the scheduler for chaos -func (in *TimeChaos) GetScheduler() *SchedulerSpec { - return in.Spec.Scheduler +const KindTimeChaos = "TimeChaos" + +// IsDeleted returns whether this resource has been deleted +func (in *TimeChaos) IsDeleted() bool { + return !in.DeletionTimestamp.IsZero() } -// GetChaos would return the a record for chaos -func (in *TimeChaos) GetChaos() *ChaosInstance { - instance := &ChaosInstance{ - Name: in.Name, - Namespace: in.Namespace, - Kind: KindTimeChaos, - StartTime: in.CreationTimestamp.Time, - Action: "", - Status: string(in.Status.Experiment.Phase), - UID: string(in.UID), +// IsPaused returns whether this resource has been paused +func (in *TimeChaos) IsPaused() bool { + if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { + return false } + return true +} - action := reflect.ValueOf(in).Elem().FieldByName("Spec").FieldByName("Action") - if action.IsValid() { - instance.Action = action.String() - } - if in.Spec.Duration != nil { - instance.Duration = *in.Spec.Duration +// GetObjectMeta would return the ObjectMeta for chaos +func (in *TimeChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + +// GetDuration would return the duration for chaos +func (in *TimeChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { + return nil, nil } - if in.DeletionTimestamp != nil { - instance.EndTime = in.DeletionTimestamp.Time + duration, err := time.ParseDuration(string(*in.Duration)) + if err != nil { + return nil, err } - return instance + return &duration, nil } // GetStatus returns the status @@ -1441,6 +2107,11 @@ func (in *TimeChaos) GetStatus() *ChaosStatus { return &in.Status.ChaosStatus } +// GetRemoteCluster returns the remoteCluster +func (in *TimeChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + // GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. func (in *TimeChaos) GetSpecAndMetaString() (string, error) { spec, err := json.Marshal(in.Spec) @@ -1464,123 +2135,251 @@ type TimeChaosList struct { Items []TimeChaos `json:"items"` } +func (in *TimeChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() +} + // ListChaos returns a list of chaos -func (in *TimeChaosList) ListChaos() []*ChaosInstance { - res := make([]*ChaosInstance, 0, len(in.Items)) +func (in *TimeChaosList) ListChaos() []GenericChaos { + var result []GenericChaos for _, item := range in.Items { - res = append(res, item.GetChaos()) + item := item + result = append(result, &item) + } + return result +} + +func (in *TimeChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err + } + + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } + + return false, stopTime.Sub(now), nil + } + + return false, 0, nil +} + +func (in *TimeChaos) IsOneShot() bool { + return false +} + +var TimeChaosWebhookLog = logf.Log.WithName("TimeChaos-resource") + +func (in *TimeChaos) ValidateCreate() (admission.Warnings, error) { + TimeChaosWebhookLog.Info("validate create", "name", in.Name) + return in.Validate() +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *TimeChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + TimeChaosWebhookLog.Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*TimeChaos).Spec) { + return nil, ErrCanNotUpdateChaos } - return res + return in.Validate() +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *TimeChaos) ValidateDelete() (admission.Warnings, error) { + TimeChaosWebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil +} + +var _ webhook.Validator = &TimeChaos{} + +func (in *TimeChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) +} + +var _ webhook.Defaulter = &TimeChaos{} + +func (in *TimeChaos) Default() { + gw.Default(in) } func init() { - SchemeBuilder.Register(&AwsChaos{}, &AwsChaosList{}) - all.register(KindAwsChaos, &ChaosKind{ - Chaos: &AwsChaos{}, - ChaosList: &AwsChaosList{}, + SchemeBuilder.Register(&AWSChaos{}, &AWSChaosList{}) + all.register(KindAWSChaos, &ChaosKind{ + chaos: &AWSChaos{}, + list: &AWSChaosList{}, + }) + + SchemeBuilder.Register(&AzureChaos{}, &AzureChaosList{}) + all.register(KindAzureChaos, &ChaosKind{ + chaos: &AzureChaos{}, + list: &AzureChaosList{}, + }) + + SchemeBuilder.Register(&BlockChaos{}, &BlockChaosList{}) + all.register(KindBlockChaos, &ChaosKind{ + chaos: &BlockChaos{}, + list: &BlockChaosList{}, }) SchemeBuilder.Register(&DNSChaos{}, &DNSChaosList{}) all.register(KindDNSChaos, &ChaosKind{ - Chaos: &DNSChaos{}, - ChaosList: &DNSChaosList{}, + chaos: &DNSChaos{}, + list: &DNSChaosList{}, }) - SchemeBuilder.Register(&GcpChaos{}, &GcpChaosList{}) - all.register(KindGcpChaos, &ChaosKind{ - Chaos: &GcpChaos{}, - ChaosList: &GcpChaosList{}, + SchemeBuilder.Register(&GCPChaos{}, &GCPChaosList{}) + all.register(KindGCPChaos, &ChaosKind{ + chaos: &GCPChaos{}, + list: &GCPChaosList{}, }) SchemeBuilder.Register(&HTTPChaos{}, &HTTPChaosList{}) all.register(KindHTTPChaos, &ChaosKind{ - Chaos: &HTTPChaos{}, - ChaosList: &HTTPChaosList{}, + chaos: &HTTPChaos{}, + list: &HTTPChaosList{}, }) - SchemeBuilder.Register(&IoChaos{}, &IoChaosList{}) - all.register(KindIoChaos, &ChaosKind{ - Chaos: &IoChaos{}, - ChaosList: &IoChaosList{}, + SchemeBuilder.Register(&IOChaos{}, &IOChaosList{}) + all.register(KindIOChaos, &ChaosKind{ + chaos: &IOChaos{}, + list: &IOChaosList{}, }) SchemeBuilder.Register(&JVMChaos{}, &JVMChaosList{}) all.register(KindJVMChaos, &ChaosKind{ - Chaos: &JVMChaos{}, - ChaosList: &JVMChaosList{}, + chaos: &JVMChaos{}, + list: &JVMChaosList{}, }) SchemeBuilder.Register(&KernelChaos{}, &KernelChaosList{}) all.register(KindKernelChaos, &ChaosKind{ - Chaos: &KernelChaos{}, - ChaosList: &KernelChaosList{}, + chaos: &KernelChaos{}, + list: &KernelChaosList{}, }) SchemeBuilder.Register(&NetworkChaos{}, &NetworkChaosList{}) all.register(KindNetworkChaos, &ChaosKind{ - Chaos: &NetworkChaos{}, - ChaosList: &NetworkChaosList{}, + chaos: &NetworkChaos{}, + list: &NetworkChaosList{}, }) + SchemeBuilder.Register(&PhysicalMachineChaos{}, &PhysicalMachineChaosList{}) + all.register(KindPhysicalMachineChaos, &ChaosKind{ + chaos: &PhysicalMachineChaos{}, + list: &PhysicalMachineChaosList{}, + }) + + SchemeBuilder.Register(&PhysicalMachine{}, &PhysicalMachineList{}) + SchemeBuilder.Register(&PodChaos{}, &PodChaosList{}) all.register(KindPodChaos, &ChaosKind{ - Chaos: &PodChaos{}, - ChaosList: &PodChaosList{}, + chaos: &PodChaos{}, + list: &PodChaosList{}, }) + SchemeBuilder.Register(&PodHttpChaos{}, &PodHttpChaosList{}) + + SchemeBuilder.Register(&PodIOChaos{}, &PodIOChaosList{}) + + SchemeBuilder.Register(&PodNetworkChaos{}, &PodNetworkChaosList{}) + + SchemeBuilder.Register(&RemoteCluster{}, &RemoteClusterList{}) + + SchemeBuilder.Register(&StatusCheck{}, &StatusCheckList{}) + SchemeBuilder.Register(&StressChaos{}, &StressChaosList{}) all.register(KindStressChaos, &ChaosKind{ - Chaos: &StressChaos{}, - ChaosList: &StressChaosList{}, + chaos: &StressChaos{}, + list: &StressChaosList{}, }) SchemeBuilder.Register(&TimeChaos{}, &TimeChaosList{}) all.register(KindTimeChaos, &ChaosKind{ - Chaos: &TimeChaos{}, - ChaosList: &TimeChaosList{}, + chaos: &TimeChaos{}, + list: &TimeChaosList{}, }) -} -// GetChaosValidator returns chaos object by kind -func GetChaosValidator(chaosKind string) ChaosValidator { - switch chaosKind { + allScheduleItem.register(KindAWSChaos, &ChaosKind{ + chaos: &AWSChaos{}, + list: &AWSChaosList{}, + }) + + allScheduleItem.register(KindAzureChaos, &ChaosKind{ + chaos: &AzureChaos{}, + list: &AzureChaosList{}, + }) + + allScheduleItem.register(KindBlockChaos, &ChaosKind{ + chaos: &BlockChaos{}, + list: &BlockChaosList{}, + }) + + allScheduleItem.register(KindDNSChaos, &ChaosKind{ + chaos: &DNSChaos{}, + list: &DNSChaosList{}, + }) - case KindAwsChaos: - return &AwsChaos{} + allScheduleItem.register(KindGCPChaos, &ChaosKind{ + chaos: &GCPChaos{}, + list: &GCPChaosList{}, + }) - case KindDNSChaos: - return &DNSChaos{} + allScheduleItem.register(KindHTTPChaos, &ChaosKind{ + chaos: &HTTPChaos{}, + list: &HTTPChaosList{}, + }) - case KindGcpChaos: - return &GcpChaos{} + allScheduleItem.register(KindIOChaos, &ChaosKind{ + chaos: &IOChaos{}, + list: &IOChaosList{}, + }) - case KindHTTPChaos: - return &HTTPChaos{} + allScheduleItem.register(KindJVMChaos, &ChaosKind{ + chaos: &JVMChaos{}, + list: &JVMChaosList{}, + }) - case KindIoChaos: - return &IoChaos{} + allScheduleItem.register(KindKernelChaos, &ChaosKind{ + chaos: &KernelChaos{}, + list: &KernelChaosList{}, + }) - case KindJVMChaos: - return &JVMChaos{} + allScheduleItem.register(KindNetworkChaos, &ChaosKind{ + chaos: &NetworkChaos{}, + list: &NetworkChaosList{}, + }) - case KindKernelChaos: - return &KernelChaos{} + allScheduleItem.register(KindPhysicalMachineChaos, &ChaosKind{ + chaos: &PhysicalMachineChaos{}, + list: &PhysicalMachineChaosList{}, + }) - case KindNetworkChaos: - return &NetworkChaos{} + allScheduleItem.register(KindPodChaos, &ChaosKind{ + chaos: &PodChaos{}, + list: &PodChaosList{}, + }) - case KindPodChaos: - return &PodChaos{} + allScheduleItem.register(KindStressChaos, &ChaosKind{ + chaos: &StressChaos{}, + list: &StressChaosList{}, + }) - case KindStressChaos: - return &StressChaos{} + allScheduleItem.register(KindTimeChaos, &ChaosKind{ + chaos: &TimeChaos{}, + list: &TimeChaosList{}, + }) - case KindTimeChaos: - return &TimeChaos{} + allScheduleItem.register(KindWorkflow, &ChaosKind{ + chaos: &Workflow{}, + list: &WorkflowList{}, + }) - default: - return nil - } } diff --git a/api/v1alpha1/zz_generated.chaosmesh_test.go b/api/v1alpha1/zz_generated.chaosmesh_test.go index 47b2b3ddf9..f02e4631e7 100644 --- a/api/v1alpha1/zz_generated.chaosmesh_test.go +++ b/api/v1alpha1/zz_generated.chaosmesh_test.go @@ -1,31 +1,34 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// + +// Code generated by chaos-builder. DO NOT EDIT. package v1alpha1 import ( "reflect" "testing" - "time" "github.com/bxcodec/faker" . "github.com/onsi/gomega" ) -func TestAwsChaosIsDeleted(t *testing.T) { +func TestAWSChaosIsDeleted(t *testing.T) { g := NewGomegaWithT(t) - chaos := &AwsChaos{} + chaos := &AWSChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -33,10 +36,10 @@ func TestAwsChaosIsDeleted(t *testing.T) { chaos.IsDeleted() } -func TestAwsChaosIsIsPaused(t *testing.T) { +func TestAWSChaosIsIsPaused(t *testing.T) { g := NewGomegaWithT(t) - chaos := &AwsChaos{} + chaos := &AWSChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -44,87 +47,84 @@ func TestAwsChaosIsIsPaused(t *testing.T) { chaos.IsPaused() } -func TestAwsChaosGetDuration(t *testing.T) { +func TestAWSChaosGetDuration(t *testing.T) { g := NewGomegaWithT(t) - chaos := &AwsChaos{} + chaos := &AWSChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) - chaos.GetDuration() + chaos.Spec.GetDuration() } -func TestAwsChaosGetNextStart(t *testing.T) { +func TestAWSChaosGetStatus(t *testing.T) { g := NewGomegaWithT(t) - chaos := &AwsChaos{} + chaos := &AWSChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) - chaos.GetNextStart() + chaos.GetStatus() } -func TestAwsChaosSetNextStart(t *testing.T) { +func TestAWSChaosGetSpecAndMetaString(t *testing.T) { g := NewGomegaWithT(t) - - chaos := &AwsChaos{} + chaos := &AWSChaos{} err := faker.FakeData(chaos) - g.Expect(err).To(BeNil()) - - chaos.SetNextStart(time.Now()) + chaos.GetSpecAndMetaString() } -func TestAwsChaosGetNextRecover(t *testing.T) { +func TestAWSChaosListChaos(t *testing.T) { g := NewGomegaWithT(t) - chaos := &AwsChaos{} + chaos := &AWSChaosList{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) - chaos.GetNextRecover() + chaos.ListChaos() } -func TestAwsChaosSetNextRecover(t *testing.T) { +func TestAzureChaosIsDeleted(t *testing.T) { g := NewGomegaWithT(t) - chaos := &AwsChaos{} + chaos := &AzureChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) - chaos.SetNextRecover(time.Now()) + chaos.IsDeleted() } -func TestAwsChaosGetScheduler(t *testing.T) { +func TestAzureChaosIsIsPaused(t *testing.T) { g := NewGomegaWithT(t) - chaos := &AwsChaos{} + chaos := &AzureChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) - chaos.GetScheduler() + chaos.IsPaused() } -func TestAwsChaosGetChaos(t *testing.T) { +func TestAzureChaosGetDuration(t *testing.T) { g := NewGomegaWithT(t) - chaos := &AwsChaos{} + chaos := &AzureChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) - chaos.GetChaos() + chaos.Spec.GetDuration() } -func TestAwsChaosGetStatus(t *testing.T) { +func TestAzureChaosGetStatus(t *testing.T) { g := NewGomegaWithT(t) - chaos := &AwsChaos{} + chaos := &AzureChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -132,18 +132,18 @@ func TestAwsChaosGetStatus(t *testing.T) { chaos.GetStatus() } -func TestAwsChaosGetSpecAndMetaString(t *testing.T) { +func TestAzureChaosGetSpecAndMetaString(t *testing.T) { g := NewGomegaWithT(t) - chaos := &AwsChaos{} + chaos := &AzureChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) chaos.GetSpecAndMetaString() } -func TestAwsChaosListChaos(t *testing.T) { +func TestAzureChaosListChaos(t *testing.T) { g := NewGomegaWithT(t) - chaos := &AwsChaosList{} + chaos := &AzureChaosList{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -151,10 +151,10 @@ func TestAwsChaosListChaos(t *testing.T) { chaos.ListChaos() } -func TestDNSChaosIsDeleted(t *testing.T) { +func TestBlockChaosIsDeleted(t *testing.T) { g := NewGomegaWithT(t) - chaos := &DNSChaos{} + chaos := &BlockChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -162,10 +162,10 @@ func TestDNSChaosIsDeleted(t *testing.T) { chaos.IsDeleted() } -func TestDNSChaosIsIsPaused(t *testing.T) { +func TestBlockChaosIsIsPaused(t *testing.T) { g := NewGomegaWithT(t) - chaos := &DNSChaos{} + chaos := &BlockChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -173,51 +173,48 @@ func TestDNSChaosIsIsPaused(t *testing.T) { chaos.IsPaused() } -func TestDNSChaosGetDuration(t *testing.T) { +func TestBlockChaosGetDuration(t *testing.T) { g := NewGomegaWithT(t) - chaos := &DNSChaos{} + chaos := &BlockChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) - chaos.GetDuration() + chaos.Spec.GetDuration() } -func TestDNSChaosGetNextStart(t *testing.T) { +func TestBlockChaosGetStatus(t *testing.T) { g := NewGomegaWithT(t) - chaos := &DNSChaos{} + chaos := &BlockChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) - chaos.GetNextStart() + chaos.GetStatus() } -func TestDNSChaosSetNextStart(t *testing.T) { +func TestBlockChaosGetSpecAndMetaString(t *testing.T) { g := NewGomegaWithT(t) - - chaos := &DNSChaos{} + chaos := &BlockChaos{} err := faker.FakeData(chaos) - g.Expect(err).To(BeNil()) - - chaos.SetNextStart(time.Now()) + chaos.GetSpecAndMetaString() } -func TestDNSChaosGetNextRecover(t *testing.T) { +func TestBlockChaosListChaos(t *testing.T) { g := NewGomegaWithT(t) - chaos := &DNSChaos{} + chaos := &BlockChaosList{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) - chaos.GetNextRecover() + chaos.ListChaos() } -func TestDNSChaosSetNextRecover(t *testing.T) { +func TestDNSChaosIsDeleted(t *testing.T) { g := NewGomegaWithT(t) chaos := &DNSChaos{} @@ -225,10 +222,10 @@ func TestDNSChaosSetNextRecover(t *testing.T) { g.Expect(err).To(BeNil()) - chaos.SetNextRecover(time.Now()) + chaos.IsDeleted() } -func TestDNSChaosGetScheduler(t *testing.T) { +func TestDNSChaosIsIsPaused(t *testing.T) { g := NewGomegaWithT(t) chaos := &DNSChaos{} @@ -236,10 +233,10 @@ func TestDNSChaosGetScheduler(t *testing.T) { g.Expect(err).To(BeNil()) - chaos.GetScheduler() + chaos.IsPaused() } -func TestDNSChaosGetChaos(t *testing.T) { +func TestDNSChaosGetDuration(t *testing.T) { g := NewGomegaWithT(t) chaos := &DNSChaos{} @@ -247,7 +244,7 @@ func TestDNSChaosGetChaos(t *testing.T) { g.Expect(err).To(BeNil()) - chaos.GetChaos() + chaos.Spec.GetDuration() } func TestDNSChaosGetStatus(t *testing.T) { @@ -280,10 +277,10 @@ func TestDNSChaosListChaos(t *testing.T) { chaos.ListChaos() } -func TestGcpChaosIsDeleted(t *testing.T) { +func TestGCPChaosIsDeleted(t *testing.T) { g := NewGomegaWithT(t) - chaos := &GcpChaos{} + chaos := &GCPChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -291,10 +288,10 @@ func TestGcpChaosIsDeleted(t *testing.T) { chaos.IsDeleted() } -func TestGcpChaosIsIsPaused(t *testing.T) { +func TestGCPChaosIsIsPaused(t *testing.T) { g := NewGomegaWithT(t) - chaos := &GcpChaos{} + chaos := &GCPChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -302,87 +299,21 @@ func TestGcpChaosIsIsPaused(t *testing.T) { chaos.IsPaused() } -func TestGcpChaosGetDuration(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &GcpChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetDuration() -} - -func TestGcpChaosGetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &GcpChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextStart() -} - -func TestGcpChaosSetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &GcpChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextStart(time.Now()) -} - -func TestGcpChaosGetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &GcpChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextRecover() -} - -func TestGcpChaosSetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &GcpChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextRecover(time.Now()) -} - -func TestGcpChaosGetScheduler(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &GcpChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetScheduler() -} - -func TestGcpChaosGetChaos(t *testing.T) { +func TestGCPChaosGetDuration(t *testing.T) { g := NewGomegaWithT(t) - chaos := &GcpChaos{} + chaos := &GCPChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) - chaos.GetChaos() + chaos.Spec.GetDuration() } -func TestGcpChaosGetStatus(t *testing.T) { +func TestGCPChaosGetStatus(t *testing.T) { g := NewGomegaWithT(t) - chaos := &GcpChaos{} + chaos := &GCPChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -390,18 +321,18 @@ func TestGcpChaosGetStatus(t *testing.T) { chaos.GetStatus() } -func TestGcpChaosGetSpecAndMetaString(t *testing.T) { +func TestGCPChaosGetSpecAndMetaString(t *testing.T) { g := NewGomegaWithT(t) - chaos := &GcpChaos{} + chaos := &GCPChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) chaos.GetSpecAndMetaString() } -func TestGcpChaosListChaos(t *testing.T) { +func TestGCPChaosListChaos(t *testing.T) { g := NewGomegaWithT(t) - chaos := &GcpChaosList{} + chaos := &GCPChaosList{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -439,73 +370,7 @@ func TestHTTPChaosGetDuration(t *testing.T) { g.Expect(err).To(BeNil()) - chaos.GetDuration() -} - -func TestHTTPChaosGetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &HTTPChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextStart() -} - -func TestHTTPChaosSetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &HTTPChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextStart(time.Now()) -} - -func TestHTTPChaosGetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &HTTPChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextRecover() -} - -func TestHTTPChaosSetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &HTTPChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextRecover(time.Now()) -} - -func TestHTTPChaosGetScheduler(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &HTTPChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetScheduler() -} - -func TestHTTPChaosGetChaos(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &HTTPChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetChaos() + chaos.Spec.GetDuration() } func TestHTTPChaosGetStatus(t *testing.T) { @@ -538,10 +403,10 @@ func TestHTTPChaosListChaos(t *testing.T) { chaos.ListChaos() } -func TestIoChaosIsDeleted(t *testing.T) { +func TestIOChaosIsDeleted(t *testing.T) { g := NewGomegaWithT(t) - chaos := &IoChaos{} + chaos := &IOChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -549,10 +414,10 @@ func TestIoChaosIsDeleted(t *testing.T) { chaos.IsDeleted() } -func TestIoChaosIsIsPaused(t *testing.T) { +func TestIOChaosIsIsPaused(t *testing.T) { g := NewGomegaWithT(t) - chaos := &IoChaos{} + chaos := &IOChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -560,87 +425,21 @@ func TestIoChaosIsIsPaused(t *testing.T) { chaos.IsPaused() } -func TestIoChaosGetDuration(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &IoChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetDuration() -} - -func TestIoChaosGetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &IoChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextStart() -} - -func TestIoChaosSetNextStart(t *testing.T) { +func TestIOChaosGetDuration(t *testing.T) { g := NewGomegaWithT(t) - chaos := &IoChaos{} + chaos := &IOChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) - chaos.SetNextStart(time.Now()) + chaos.Spec.GetDuration() } -func TestIoChaosGetNextRecover(t *testing.T) { +func TestIOChaosGetStatus(t *testing.T) { g := NewGomegaWithT(t) - chaos := &IoChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextRecover() -} - -func TestIoChaosSetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &IoChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextRecover(time.Now()) -} - -func TestIoChaosGetScheduler(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &IoChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetScheduler() -} - -func TestIoChaosGetChaos(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &IoChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetChaos() -} - -func TestIoChaosGetStatus(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &IoChaos{} + chaos := &IOChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -648,18 +447,18 @@ func TestIoChaosGetStatus(t *testing.T) { chaos.GetStatus() } -func TestIoChaosGetSpecAndMetaString(t *testing.T) { +func TestIOChaosGetSpecAndMetaString(t *testing.T) { g := NewGomegaWithT(t) - chaos := &IoChaos{} + chaos := &IOChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) chaos.GetSpecAndMetaString() } -func TestIoChaosListChaos(t *testing.T) { +func TestIOChaosListChaos(t *testing.T) { g := NewGomegaWithT(t) - chaos := &IoChaosList{} + chaos := &IOChaosList{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -697,73 +496,7 @@ func TestJVMChaosGetDuration(t *testing.T) { g.Expect(err).To(BeNil()) - chaos.GetDuration() -} - -func TestJVMChaosGetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &JVMChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextStart() -} - -func TestJVMChaosSetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &JVMChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextStart(time.Now()) -} - -func TestJVMChaosGetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &JVMChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextRecover() -} - -func TestJVMChaosSetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &JVMChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextRecover(time.Now()) -} - -func TestJVMChaosGetScheduler(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &JVMChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetScheduler() -} - -func TestJVMChaosGetChaos(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &JVMChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetChaos() + chaos.Spec.GetDuration() } func TestJVMChaosGetStatus(t *testing.T) { @@ -826,73 +559,7 @@ func TestKernelChaosGetDuration(t *testing.T) { g.Expect(err).To(BeNil()) - chaos.GetDuration() -} - -func TestKernelChaosGetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &KernelChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextStart() -} - -func TestKernelChaosSetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &KernelChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextStart(time.Now()) -} - -func TestKernelChaosGetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &KernelChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextRecover() -} - -func TestKernelChaosSetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &KernelChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextRecover(time.Now()) -} - -func TestKernelChaosGetScheduler(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &KernelChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetScheduler() -} - -func TestKernelChaosGetChaos(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &KernelChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetChaos() + chaos.Spec.GetDuration() } func TestKernelChaosGetStatus(t *testing.T) { @@ -955,73 +622,7 @@ func TestNetworkChaosGetDuration(t *testing.T) { g.Expect(err).To(BeNil()) - chaos.GetDuration() -} - -func TestNetworkChaosGetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &NetworkChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextStart() -} - -func TestNetworkChaosSetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &NetworkChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextStart(time.Now()) -} - -func TestNetworkChaosGetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &NetworkChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextRecover() -} - -func TestNetworkChaosSetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &NetworkChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextRecover(time.Now()) -} - -func TestNetworkChaosGetScheduler(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &NetworkChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetScheduler() -} - -func TestNetworkChaosGetChaos(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &NetworkChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetChaos() + chaos.Spec.GetDuration() } func TestNetworkChaosGetStatus(t *testing.T) { @@ -1054,10 +655,10 @@ func TestNetworkChaosListChaos(t *testing.T) { chaos.ListChaos() } -func TestPodChaosIsDeleted(t *testing.T) { +func TestPhysicalMachineChaosIsDeleted(t *testing.T) { g := NewGomegaWithT(t) - chaos := &PodChaos{} + chaos := &PhysicalMachineChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -1065,10 +666,10 @@ func TestPodChaosIsDeleted(t *testing.T) { chaos.IsDeleted() } -func TestPodChaosIsIsPaused(t *testing.T) { +func TestPhysicalMachineChaosIsIsPaused(t *testing.T) { g := NewGomegaWithT(t) - chaos := &PodChaos{} + chaos := &PhysicalMachineChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) @@ -1076,51 +677,48 @@ func TestPodChaosIsIsPaused(t *testing.T) { chaos.IsPaused() } -func TestPodChaosGetDuration(t *testing.T) { +func TestPhysicalMachineChaosGetDuration(t *testing.T) { g := NewGomegaWithT(t) - chaos := &PodChaos{} + chaos := &PhysicalMachineChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) - chaos.GetDuration() + chaos.Spec.GetDuration() } -func TestPodChaosGetNextStart(t *testing.T) { +func TestPhysicalMachineChaosGetStatus(t *testing.T) { g := NewGomegaWithT(t) - chaos := &PodChaos{} + chaos := &PhysicalMachineChaos{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) - chaos.GetNextStart() + chaos.GetStatus() } -func TestPodChaosSetNextStart(t *testing.T) { +func TestPhysicalMachineChaosGetSpecAndMetaString(t *testing.T) { g := NewGomegaWithT(t) - - chaos := &PodChaos{} + chaos := &PhysicalMachineChaos{} err := faker.FakeData(chaos) - g.Expect(err).To(BeNil()) - - chaos.SetNextStart(time.Now()) + chaos.GetSpecAndMetaString() } -func TestPodChaosGetNextRecover(t *testing.T) { +func TestPhysicalMachineChaosListChaos(t *testing.T) { g := NewGomegaWithT(t) - chaos := &PodChaos{} + chaos := &PhysicalMachineChaosList{} err := faker.FakeData(chaos) g.Expect(err).To(BeNil()) - chaos.GetNextRecover() + chaos.ListChaos() } -func TestPodChaosSetNextRecover(t *testing.T) { +func TestPodChaosIsDeleted(t *testing.T) { g := NewGomegaWithT(t) chaos := &PodChaos{} @@ -1128,10 +726,10 @@ func TestPodChaosSetNextRecover(t *testing.T) { g.Expect(err).To(BeNil()) - chaos.SetNextRecover(time.Now()) + chaos.IsDeleted() } -func TestPodChaosGetScheduler(t *testing.T) { +func TestPodChaosIsIsPaused(t *testing.T) { g := NewGomegaWithT(t) chaos := &PodChaos{} @@ -1139,10 +737,10 @@ func TestPodChaosGetScheduler(t *testing.T) { g.Expect(err).To(BeNil()) - chaos.GetScheduler() + chaos.IsPaused() } -func TestPodChaosGetChaos(t *testing.T) { +func TestPodChaosGetDuration(t *testing.T) { g := NewGomegaWithT(t) chaos := &PodChaos{} @@ -1150,7 +748,7 @@ func TestPodChaosGetChaos(t *testing.T) { g.Expect(err).To(BeNil()) - chaos.GetChaos() + chaos.Spec.GetDuration() } func TestPodChaosGetStatus(t *testing.T) { @@ -1213,73 +811,7 @@ func TestStressChaosGetDuration(t *testing.T) { g.Expect(err).To(BeNil()) - chaos.GetDuration() -} - -func TestStressChaosGetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &StressChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextStart() -} - -func TestStressChaosSetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &StressChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextStart(time.Now()) -} - -func TestStressChaosGetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &StressChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextRecover() -} - -func TestStressChaosSetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &StressChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextRecover(time.Now()) -} - -func TestStressChaosGetScheduler(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &StressChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetScheduler() -} - -func TestStressChaosGetChaos(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &StressChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetChaos() + chaos.Spec.GetDuration() } func TestStressChaosGetStatus(t *testing.T) { @@ -1342,73 +874,7 @@ func TestTimeChaosGetDuration(t *testing.T) { g.Expect(err).To(BeNil()) - chaos.GetDuration() -} - -func TestTimeChaosGetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &TimeChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextStart() -} - -func TestTimeChaosSetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &TimeChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextStart(time.Now()) -} - -func TestTimeChaosGetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &TimeChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextRecover() -} - -func TestTimeChaosSetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &TimeChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextRecover(time.Now()) -} - -func TestTimeChaosGetScheduler(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &TimeChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetScheduler() -} - -func TestTimeChaosGetChaos(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &TimeChaos{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetChaos() + chaos.Spec.GetDuration() } func TestTimeChaosGetStatus(t *testing.T) { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index b442f6755c..6c086c2383 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1,4 +1,4 @@ -// +build !ignore_autogenerated +//go:build !ignore_autogenerated // Copyright Chaos Mesh Authors. // @@ -6,43 +6,153 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// // Code generated by controller-gen. DO NOT EDIT. package v1alpha1 import ( + "encoding/json" "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" + "net/http" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ActionParameterRules) DeepCopyInto(out *ActionParameterRules) { +func (in *AWSChaos) DeepCopyInto(out *AWSChaos) { *out = *in - if in.Flags != nil { - in, out := &in.Flags, &out.Flags - *out = make([]ParameterRules, len(*in)) - copy(*out, *in) + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSChaos. +func (in *AWSChaos) DeepCopy() *AWSChaos { + if in == nil { + return nil } - if in.Matchers != nil { - in, out := &in.Matchers, &out.Matchers - *out = make([]ParameterRules, len(*in)) - copy(*out, *in) + out := new(AWSChaos) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AWSChaos) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSChaosList) DeepCopyInto(out *AWSChaosList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AWSChaos, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSChaosList. +func (in *AWSChaosList) DeepCopy() *AWSChaosList { + if in == nil { + return nil + } + out := new(AWSChaosList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AWSChaosList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSChaosSpec) DeepCopyInto(out *AWSChaosSpec) { + *out = *in + if in.Duration != nil { + in, out := &in.Duration, &out.Duration + *out = new(string) + **out = **in + } + if in.SecretName != nil { + in, out := &in.SecretName, &out.SecretName + *out = new(string) + **out = **in + } + in.AWSSelector.DeepCopyInto(&out.AWSSelector) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSChaosSpec. +func (in *AWSChaosSpec) DeepCopy() *AWSChaosSpec { + if in == nil { + return nil + } + out := new(AWSChaosSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSChaosStatus) DeepCopyInto(out *AWSChaosStatus) { + *out = *in + in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSChaosStatus. +func (in *AWSChaosStatus) DeepCopy() *AWSChaosStatus { + if in == nil { + return nil + } + out := new(AWSChaosStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSSelector) DeepCopyInto(out *AWSSelector) { + *out = *in + if in.Endpoint != nil { + in, out := &in.Endpoint, &out.Endpoint + *out = new(string) + **out = **in + } + if in.EbsVolume != nil { + in, out := &in.EbsVolume, &out.EbsVolume + *out = new(string) + **out = **in + } + if in.DeviceName != nil { + in, out := &in.DeviceName, &out.DeviceName + *out = new(string) + **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionParameterRules. -func (in *ActionParameterRules) DeepCopy() *ActionParameterRules { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSSelector. +func (in *AWSSelector) DeepCopy() *AWSSelector { if in == nil { return nil } - out := new(ActionParameterRules) + out := new(AWSSelector) in.DeepCopyInto(out) return out } @@ -123,7 +233,7 @@ func (in *AttrOverrideSpec) DeepCopy() *AttrOverrideSpec { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AwsChaos) DeepCopyInto(out *AwsChaos) { +func (in *AzureChaos) DeepCopyInto(out *AzureChaos) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -131,18 +241,18 @@ func (in *AwsChaos) DeepCopyInto(out *AwsChaos) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsChaos. -func (in *AwsChaos) DeepCopy() *AwsChaos { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureChaos. +func (in *AzureChaos) DeepCopy() *AzureChaos { if in == nil { return nil } - out := new(AwsChaos) + out := new(AzureChaos) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *AwsChaos) DeepCopyObject() runtime.Object { +func (in *AzureChaos) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -150,31 +260,31 @@ func (in *AwsChaos) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AwsChaosList) DeepCopyInto(out *AwsChaosList) { +func (in *AzureChaosList) DeepCopyInto(out *AzureChaosList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]AwsChaos, len(*in)) + *out = make([]AzureChaos, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsChaosList. -func (in *AwsChaosList) DeepCopy() *AwsChaosList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureChaosList. +func (in *AzureChaosList) DeepCopy() *AzureChaosList { if in == nil { return nil } - out := new(AwsChaosList) + out := new(AzureChaosList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *AwsChaosList) DeepCopyObject() runtime.Object { +func (in *AzureChaosList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -182,151 +292,99 @@ func (in *AwsChaosList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AwsChaosSpec) DeepCopyInto(out *AwsChaosSpec) { +func (in *AzureChaosSpec) DeepCopyInto(out *AzureChaosSpec) { *out = *in if in.Duration != nil { in, out := &in.Duration, &out.Duration *out = new(string) **out = **in } - if in.Scheduler != nil { - in, out := &in.Scheduler, &out.Scheduler - *out = new(SchedulerSpec) - **out = **in - } - if in.SecretName != nil { - in, out := &in.SecretName, &out.SecretName - *out = new(string) - **out = **in - } - if in.EbsVolume != nil { - in, out := &in.EbsVolume, &out.EbsVolume - *out = new(string) - **out = **in - } - if in.DeviceName != nil { - in, out := &in.DeviceName, &out.DeviceName - *out = new(string) - **out = **in - } - if in.Endpoint != nil { - in, out := &in.Endpoint, &out.Endpoint - *out = new(string) - **out = **in - } + in.AzureSelector.DeepCopyInto(&out.AzureSelector) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsChaosSpec. -func (in *AwsChaosSpec) DeepCopy() *AwsChaosSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureChaosSpec. +func (in *AzureChaosSpec) DeepCopy() *AzureChaosSpec { if in == nil { return nil } - out := new(AwsChaosSpec) + out := new(AzureChaosSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AwsChaosStatus) DeepCopyInto(out *AwsChaosStatus) { +func (in *AzureChaosStatus) DeepCopyInto(out *AzureChaosStatus) { *out = *in in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsChaosStatus. -func (in *AwsChaosStatus) DeepCopy() *AwsChaosStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureChaosStatus. +func (in *AzureChaosStatus) DeepCopy() *AzureChaosStatus { if in == nil { return nil } - out := new(AwsChaosStatus) + out := new(AzureChaosStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *BandwidthSpec) DeepCopyInto(out *BandwidthSpec) { +func (in *AzureSelector) DeepCopyInto(out *AzureSelector) { *out = *in - if in.Peakrate != nil { - in, out := &in.Peakrate, &out.Peakrate - *out = new(uint64) - **out = **in - } - if in.Minburst != nil { - in, out := &in.Minburst, &out.Minburst - *out = new(uint32) + if in.DiskName != nil { + in, out := &in.DiskName, &out.DiskName + *out = new(string) **out = **in } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BandwidthSpec. -func (in *BandwidthSpec) DeepCopy() *BandwidthSpec { - if in == nil { - return nil - } - out := new(BandwidthSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CPUStressor) DeepCopyInto(out *CPUStressor) { - *out = *in - out.Stressor = in.Stressor - if in.Load != nil { - in, out := &in.Load, &out.Load + if in.LUN != nil { + in, out := &in.LUN, &out.LUN *out = new(int) **out = **in } - if in.Options != nil { - in, out := &in.Options, &out.Options - *out = make([]string, len(*in)) - copy(*out, *in) + if in.SecretName != nil { + in, out := &in.SecretName, &out.SecretName + *out = new(string) + **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CPUStressor. -func (in *CPUStressor) DeepCopy() *CPUStressor { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureSelector. +func (in *AzureSelector) DeepCopy() *AzureSelector { if in == nil { return nil } - out := new(CPUStressor) + out := new(AzureSelector) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ChaosStatus) DeepCopyInto(out *ChaosStatus) { +func (in *BandwidthSpec) DeepCopyInto(out *BandwidthSpec) { *out = *in - in.Scheduler.DeepCopyInto(&out.Scheduler) - in.Experiment.DeepCopyInto(&out.Experiment) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChaosStatus. -func (in *ChaosStatus) DeepCopy() *ChaosStatus { - if in == nil { - return nil + if in.Peakrate != nil { + in, out := &in.Peakrate, &out.Peakrate + *out = new(uint64) + **out = **in + } + if in.Minburst != nil { + in, out := &in.Minburst, &out.Minburst + *out = new(uint32) + **out = **in } - out := new(ChaosStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CorruptSpec) DeepCopyInto(out *CorruptSpec) { - *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CorruptSpec. -func (in *CorruptSpec) DeepCopy() *CorruptSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BandwidthSpec. +func (in *BandwidthSpec) DeepCopy() *BandwidthSpec { if in == nil { return nil } - out := new(CorruptSpec) + out := new(BandwidthSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DNSChaos) DeepCopyInto(out *DNSChaos) { +func (in *BlockChaos) DeepCopyInto(out *BlockChaos) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -334,18 +392,18 @@ func (in *DNSChaos) DeepCopyInto(out *DNSChaos) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSChaos. -func (in *DNSChaos) DeepCopy() *DNSChaos { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BlockChaos. +func (in *BlockChaos) DeepCopy() *BlockChaos { if in == nil { return nil } - out := new(DNSChaos) + out := new(BlockChaos) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *DNSChaos) DeepCopyObject() runtime.Object { +func (in *BlockChaos) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -353,31 +411,31 @@ func (in *DNSChaos) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DNSChaosList) DeepCopyInto(out *DNSChaosList) { +func (in *BlockChaosList) DeepCopyInto(out *BlockChaosList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]DNSChaos, len(*in)) + *out = make([]BlockChaos, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSChaosList. -func (in *DNSChaosList) DeepCopy() *DNSChaosList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BlockChaosList. +func (in *BlockChaosList) DeepCopy() *BlockChaosList { if in == nil { return nil } - out := new(DNSChaosList) + out := new(BlockChaosList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *DNSChaosList) DeepCopyObject() runtime.Object { +func (in *BlockChaosList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -385,357 +443,310 @@ func (in *DNSChaosList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DNSChaosSpec) DeepCopyInto(out *DNSChaosSpec) { +func (in *BlockChaosSpec) DeepCopyInto(out *BlockChaosSpec) { *out = *in - in.Selector.DeepCopyInto(&out.Selector) + if in.Delay != nil { + in, out := &in.Delay, &out.Delay + *out = new(BlockDelaySpec) + **out = **in + } + in.ContainerNodeVolumePathSelector.DeepCopyInto(&out.ContainerNodeVolumePathSelector) if in.Duration != nil { in, out := &in.Duration, &out.Duration *out = new(string) **out = **in } - if in.Scheduler != nil { - in, out := &in.Scheduler, &out.Scheduler - *out = new(SchedulerSpec) - **out = **in - } - if in.DomainNamePatterns != nil { - in, out := &in.DomainNamePatterns, &out.DomainNamePatterns - *out = make([]string, len(*in)) - copy(*out, *in) - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSChaosSpec. -func (in *DNSChaosSpec) DeepCopy() *DNSChaosSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BlockChaosSpec. +func (in *BlockChaosSpec) DeepCopy() *BlockChaosSpec { if in == nil { return nil } - out := new(DNSChaosSpec) + out := new(BlockChaosSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DNSChaosStatus) DeepCopyInto(out *DNSChaosStatus) { +func (in *BlockChaosStatus) DeepCopyInto(out *BlockChaosStatus) { *out = *in in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) + if in.InjectionIds != nil { + in, out := &in.InjectionIds, &out.InjectionIds + *out = make(map[string]int, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSChaosStatus. -func (in *DNSChaosStatus) DeepCopy() *DNSChaosStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BlockChaosStatus. +func (in *BlockChaosStatus) DeepCopy() *BlockChaosStatus { if in == nil { return nil } - out := new(DNSChaosStatus) + out := new(BlockChaosStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DelaySpec) DeepCopyInto(out *DelaySpec) { +func (in *BlockDelaySpec) DeepCopyInto(out *BlockDelaySpec) { *out = *in - if in.Reorder != nil { - in, out := &in.Reorder, &out.Reorder - *out = new(ReorderSpec) - **out = **in - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DelaySpec. -func (in *DelaySpec) DeepCopy() *DelaySpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BlockDelaySpec. +func (in *BlockDelaySpec) DeepCopy() *BlockDelaySpec { if in == nil { return nil } - out := new(DelaySpec) + out := new(BlockDelaySpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DuplicateSpec) DeepCopyInto(out *DuplicateSpec) { +func (in *CPUStressor) DeepCopyInto(out *CPUStressor) { *out = *in + out.Stressor = in.Stressor + if in.Load != nil { + in, out := &in.Load, &out.Load + *out = new(int) + **out = **in + } + if in.Options != nil { + in, out := &in.Options, &out.Options + *out = make([]string, len(*in)) + copy(*out, *in) + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DuplicateSpec. -func (in *DuplicateSpec) DeepCopy() *DuplicateSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CPUStressor. +func (in *CPUStressor) DeepCopy() *CPUStressor { if in == nil { return nil } - out := new(DuplicateSpec) + out := new(CPUStressor) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EmbedChaos) DeepCopyInto(out *EmbedChaos) { +func (in *ChaosCondition) DeepCopyInto(out *ChaosCondition) { *out = *in - if in.AwsChaos != nil { - in, out := &in.AwsChaos, &out.AwsChaos - *out = new(AwsChaosSpec) - (*in).DeepCopyInto(*out) - } - if in.DNSChaos != nil { - in, out := &in.DNSChaos, &out.DNSChaos - *out = new(DNSChaosSpec) - (*in).DeepCopyInto(*out) - } - if in.GcpChaos != nil { - in, out := &in.GcpChaos, &out.GcpChaos - *out = new(GcpChaosSpec) - (*in).DeepCopyInto(*out) - } - if in.HTTPChaos != nil { - in, out := &in.HTTPChaos, &out.HTTPChaos - *out = new(HTTPChaosSpec) - (*in).DeepCopyInto(*out) - } - if in.IoChaos != nil { - in, out := &in.IoChaos, &out.IoChaos - *out = new(IoChaosSpec) - (*in).DeepCopyInto(*out) - } - if in.JVMChaos != nil { - in, out := &in.JVMChaos, &out.JVMChaos - *out = new(JVMChaosSpec) - (*in).DeepCopyInto(*out) - } - if in.KernelChaos != nil { - in, out := &in.KernelChaos, &out.KernelChaos - *out = new(KernelChaosSpec) - (*in).DeepCopyInto(*out) - } - if in.NetworkChaos != nil { - in, out := &in.NetworkChaos, &out.NetworkChaos - *out = new(NetworkChaosSpec) - (*in).DeepCopyInto(*out) - } - if in.PodChaos != nil { - in, out := &in.PodChaos, &out.PodChaos - *out = new(PodChaosSpec) - (*in).DeepCopyInto(*out) - } - if in.StressChaos != nil { - in, out := &in.StressChaos, &out.StressChaos - *out = new(StressChaosSpec) - (*in).DeepCopyInto(*out) - } - if in.TimeChaos != nil { - in, out := &in.TimeChaos, &out.TimeChaos - *out = new(TimeChaosSpec) - (*in).DeepCopyInto(*out) - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmbedChaos. -func (in *EmbedChaos) DeepCopy() *EmbedChaos { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChaosCondition. +func (in *ChaosCondition) DeepCopy() *ChaosCondition { if in == nil { return nil } - out := new(EmbedChaos) + out := new(ChaosCondition) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ExperimentStatus) DeepCopyInto(out *ExperimentStatus) { +func (in *ChaosOnlyScheduleSpec) DeepCopyInto(out *ChaosOnlyScheduleSpec) { *out = *in - if in.StartTime != nil { - in, out := &in.StartTime, &out.StartTime - *out = (*in).DeepCopy() - } - if in.EndTime != nil { - in, out := &in.EndTime, &out.EndTime - *out = (*in).DeepCopy() - } - if in.PodRecords != nil { - in, out := &in.PodRecords, &out.PodRecords - *out = make([]PodStatus, len(*in)) - copy(*out, *in) + if in.StartingDeadlineSeconds != nil { + in, out := &in.StartingDeadlineSeconds, &out.StartingDeadlineSeconds + *out = new(int64) + **out = **in } + in.EmbedChaos.DeepCopyInto(&out.EmbedChaos) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExperimentStatus. -func (in *ExperimentStatus) DeepCopy() *ExperimentStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChaosOnlyScheduleSpec. +func (in *ChaosOnlyScheduleSpec) DeepCopy() *ChaosOnlyScheduleSpec { if in == nil { return nil } - out := new(ExperimentStatus) + out := new(ChaosOnlyScheduleSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FailKernRequest) DeepCopyInto(out *FailKernRequest) { +func (in *ChaosStatus) DeepCopyInto(out *ChaosStatus) { *out = *in - if in.Headers != nil { - in, out := &in.Headers, &out.Headers - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Callchain != nil { - in, out := &in.Callchain, &out.Callchain - *out = make([]Frame, len(*in)) + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]ChaosCondition, len(*in)) copy(*out, *in) } + in.Experiment.DeepCopyInto(&out.Experiment) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FailKernRequest. -func (in *FailKernRequest) DeepCopy() *FailKernRequest { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChaosStatus. +func (in *ChaosStatus) DeepCopy() *ChaosStatus { if in == nil { return nil } - out := new(FailKernRequest) + out := new(ChaosStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Filter) DeepCopyInto(out *Filter) { +func (in *CidrAndPort) DeepCopyInto(out *CidrAndPort) { *out = *in - if in.Methods != nil { - in, out := &in.Methods, &out.Methods - *out = make([]IoMethod, len(*in)) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CidrAndPort. +func (in *CidrAndPort) DeepCopy() *CidrAndPort { + if in == nil { + return nil + } + out := new(CidrAndPort) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in ClockIds) DeepCopyInto(out *ClockIds) { + { + in := &in + *out = make(ClockIds, len(*in)) copy(*out, *in) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Filter. -func (in *Filter) DeepCopy() *Filter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClockIds. +func (in ClockIds) DeepCopy() ClockIds { if in == nil { return nil } - out := new(Filter) + out := new(ClockIds) in.DeepCopyInto(out) - return out + return *out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Frame) DeepCopyInto(out *Frame) { +func (in *ClockSpec) DeepCopyInto(out *ClockSpec) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Frame. -func (in *Frame) DeepCopy() *Frame { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClockSpec. +func (in *ClockSpec) DeepCopy() *ClockSpec { if in == nil { return nil } - out := new(Frame) + out := new(ClockSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GcpChaos) DeepCopyInto(out *GcpChaos) { +func (in *ConditionalBranch) DeepCopyInto(out *ConditionalBranch) { *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GcpChaos. -func (in *GcpChaos) DeepCopy() *GcpChaos { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConditionalBranch. +func (in *ConditionalBranch) DeepCopy() *ConditionalBranch { if in == nil { return nil } - out := new(GcpChaos) + out := new(ConditionalBranch) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *GcpChaos) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConditionalBranchStatus) DeepCopyInto(out *ConditionalBranchStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConditionalBranchStatus. +func (in *ConditionalBranchStatus) DeepCopy() *ConditionalBranchStatus { + if in == nil { + return nil } - return nil + out := new(ConditionalBranchStatus) + in.DeepCopyInto(out) + return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GcpChaosList) DeepCopyInto(out *GcpChaosList) { +func (in *ConditionalBranchesStatus) DeepCopyInto(out *ConditionalBranchesStatus) { *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]GcpChaos, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } + if in.Branches != nil { + in, out := &in.Branches, &out.Branches + *out = make([]ConditionalBranchStatus, len(*in)) + copy(*out, *in) + } + if in.Context != nil { + in, out := &in.Context, &out.Context + *out = make([]string, len(*in)) + copy(*out, *in) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GcpChaosList. -func (in *GcpChaosList) DeepCopy() *GcpChaosList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConditionalBranchesStatus. +func (in *ConditionalBranchesStatus) DeepCopy() *ConditionalBranchesStatus { if in == nil { return nil } - out := new(GcpChaosList) + out := new(ConditionalBranchesStatus) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *GcpChaosList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerNodeVolumePathSelector) DeepCopyInto(out *ContainerNodeVolumePathSelector) { + *out = *in + in.ContainerSelector.DeepCopyInto(&out.ContainerSelector) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerNodeVolumePathSelector. +func (in *ContainerNodeVolumePathSelector) DeepCopy() *ContainerNodeVolumePathSelector { + if in == nil { + return nil } - return nil + out := new(ContainerNodeVolumePathSelector) + in.DeepCopyInto(out) + return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GcpChaosSpec) DeepCopyInto(out *GcpChaosSpec) { +func (in *ContainerSelector) DeepCopyInto(out *ContainerSelector) { *out = *in - if in.Duration != nil { - in, out := &in.Duration, &out.Duration - *out = new(string) - **out = **in - } - if in.Scheduler != nil { - in, out := &in.Scheduler, &out.Scheduler - *out = new(SchedulerSpec) - **out = **in - } - if in.SecretName != nil { - in, out := &in.SecretName, &out.SecretName - *out = new(string) - **out = **in - } - if in.DeviceName != nil { - in, out := &in.DeviceName, &out.DeviceName - *out = new(string) - **out = **in + in.PodSelector.DeepCopyInto(&out.PodSelector) + if in.ContainerNames != nil { + in, out := &in.ContainerNames, &out.ContainerNames + *out = make([]string, len(*in)) + copy(*out, *in) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GcpChaosSpec. -func (in *GcpChaosSpec) DeepCopy() *GcpChaosSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSelector. +func (in *ContainerSelector) DeepCopy() *ContainerSelector { if in == nil { return nil } - out := new(GcpChaosSpec) + out := new(ContainerSelector) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GcpChaosStatus) DeepCopyInto(out *GcpChaosStatus) { +func (in *CorruptSpec) DeepCopyInto(out *CorruptSpec) { *out = *in - in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GcpChaosStatus. -func (in *GcpChaosStatus) DeepCopy() *GcpChaosStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CorruptSpec. +func (in *CorruptSpec) DeepCopy() *CorruptSpec { if in == nil { return nil } - out := new(GcpChaosStatus) + out := new(CorruptSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *HTTPChaos) DeepCopyInto(out *HTTPChaos) { +func (in *DNSChaos) DeepCopyInto(out *DNSChaos) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -743,18 +754,18 @@ func (in *HTTPChaos) DeepCopyInto(out *HTTPChaos) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPChaos. -func (in *HTTPChaos) DeepCopy() *HTTPChaos { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSChaos. +func (in *DNSChaos) DeepCopy() *DNSChaos { if in == nil { return nil } - out := new(HTTPChaos) + out := new(DNSChaos) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *HTTPChaos) DeepCopyObject() runtime.Object { +func (in *DNSChaos) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -762,31 +773,31 @@ func (in *HTTPChaos) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *HTTPChaosList) DeepCopyInto(out *HTTPChaosList) { +func (in *DNSChaosList) DeepCopyInto(out *DNSChaosList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]HTTPChaos, len(*in)) + *out = make([]DNSChaos, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPChaosList. -func (in *HTTPChaosList) DeepCopy() *HTTPChaosList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSChaosList. +func (in *DNSChaosList) DeepCopy() *DNSChaosList { if in == nil { return nil } - out := new(HTTPChaosList) + out := new(DNSChaosList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *HTTPChaosList) DeepCopyObject() runtime.Object { +func (in *DNSChaosList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -794,138 +805,2341 @@ func (in *HTTPChaosList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *HTTPChaosSpec) DeepCopyInto(out *HTTPChaosSpec) { +func (in *DNSChaosSpec) DeepCopyInto(out *DNSChaosSpec) { *out = *in - in.Selector.DeepCopyInto(&out.Selector) - if in.Scheduler != nil { - in, out := &in.Scheduler, &out.Scheduler - *out = new(SchedulerSpec) - **out = **in - } + in.ContainerSelector.DeepCopyInto(&out.ContainerSelector) if in.Duration != nil { in, out := &in.Duration, &out.Duration *out = new(string) **out = **in } - if in.Headers != nil { - in, out := &in.Headers, &out.Headers - *out = make([]Matcher, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } + if in.DomainNamePatterns != nil { + in, out := &in.DomainNamePatterns, &out.DomainNamePatterns + *out = make([]string, len(*in)) + copy(*out, *in) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPChaosSpec. -func (in *HTTPChaosSpec) DeepCopy() *HTTPChaosSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSChaosSpec. +func (in *DNSChaosSpec) DeepCopy() *DNSChaosSpec { if in == nil { return nil } - out := new(HTTPChaosSpec) + out := new(DNSChaosSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *HTTPChaosStatus) DeepCopyInto(out *HTTPChaosStatus) { +func (in *DNSChaosStatus) DeepCopyInto(out *DNSChaosStatus) { *out = *in in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPChaosStatus. -func (in *HTTPChaosStatus) DeepCopy() *HTTPChaosStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSChaosStatus. +func (in *DNSChaosStatus) DeepCopy() *DNSChaosStatus { if in == nil { return nil } - out := new(HTTPChaosStatus) + out := new(DNSChaosStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IoChaos) DeepCopyInto(out *IoChaos) { +func (in *DelaySpec) DeepCopyInto(out *DelaySpec) { *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) + if in.Reorder != nil { + in, out := &in.Reorder, &out.Reorder + *out = new(ReorderSpec) + **out = **in + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IoChaos. -func (in *IoChaos) DeepCopy() *IoChaos { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DelaySpec. +func (in *DelaySpec) DeepCopy() *DelaySpec { if in == nil { return nil } - out := new(IoChaos) + out := new(DelaySpec) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *IoChaos) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IoChaosAction) DeepCopyInto(out *IoChaosAction) { +func (in *DiskFileSpec) DeepCopyInto(out *DiskFileSpec) { *out = *in - in.Filter.DeepCopyInto(&out.Filter) - if in.Faults != nil { - in, out := &in.Faults, &out.Faults - *out = make([]IoFault, len(*in)) - copy(*out, *in) - } - if in.AttrOverrideSpec != nil { - in, out := &in.AttrOverrideSpec, &out.AttrOverrideSpec - *out = new(AttrOverrideSpec) - (*in).DeepCopyInto(*out) - } - if in.MistakeSpec != nil { - in, out := &in.MistakeSpec, &out.MistakeSpec - *out = new(MistakeSpec) - **out = **in - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IoChaosAction. -func (in *IoChaosAction) DeepCopy() *IoChaosAction { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DiskFileSpec. +func (in *DiskFileSpec) DeepCopy() *DiskFileSpec { if in == nil { return nil } - out := new(IoChaosAction) + out := new(DiskFileSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IoChaosList) DeepCopyInto(out *IoChaosList) { +func (in *DiskFillSpec) DeepCopyInto(out *DiskFillSpec) { *out = *in - out.TypeMeta = in.TypeMeta + out.DiskFileSpec = in.DiskFileSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DiskFillSpec. +func (in *DiskFillSpec) DeepCopy() *DiskFillSpec { + if in == nil { + return nil + } + out := new(DiskFillSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DiskPayloadSpec) DeepCopyInto(out *DiskPayloadSpec) { + *out = *in + out.DiskFileSpec = in.DiskFileSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DiskPayloadSpec. +func (in *DiskPayloadSpec) DeepCopy() *DiskPayloadSpec { + if in == nil { + return nil + } + out := new(DiskPayloadSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DuplicateSpec) DeepCopyInto(out *DuplicateSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DuplicateSpec. +func (in *DuplicateSpec) DeepCopy() *DuplicateSpec { + if in == nil { + return nil + } + out := new(DuplicateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EmbedChaos) DeepCopyInto(out *EmbedChaos) { + *out = *in + if in.AWSChaos != nil { + in, out := &in.AWSChaos, &out.AWSChaos + *out = new(AWSChaosSpec) + (*in).DeepCopyInto(*out) + } + if in.AzureChaos != nil { + in, out := &in.AzureChaos, &out.AzureChaos + *out = new(AzureChaosSpec) + (*in).DeepCopyInto(*out) + } + if in.BlockChaos != nil { + in, out := &in.BlockChaos, &out.BlockChaos + *out = new(BlockChaosSpec) + (*in).DeepCopyInto(*out) + } + if in.DNSChaos != nil { + in, out := &in.DNSChaos, &out.DNSChaos + *out = new(DNSChaosSpec) + (*in).DeepCopyInto(*out) + } + if in.GCPChaos != nil { + in, out := &in.GCPChaos, &out.GCPChaos + *out = new(GCPChaosSpec) + (*in).DeepCopyInto(*out) + } + if in.HTTPChaos != nil { + in, out := &in.HTTPChaos, &out.HTTPChaos + *out = new(HTTPChaosSpec) + (*in).DeepCopyInto(*out) + } + if in.IOChaos != nil { + in, out := &in.IOChaos, &out.IOChaos + *out = new(IOChaosSpec) + (*in).DeepCopyInto(*out) + } + if in.JVMChaos != nil { + in, out := &in.JVMChaos, &out.JVMChaos + *out = new(JVMChaosSpec) + (*in).DeepCopyInto(*out) + } + if in.KernelChaos != nil { + in, out := &in.KernelChaos, &out.KernelChaos + *out = new(KernelChaosSpec) + (*in).DeepCopyInto(*out) + } + if in.NetworkChaos != nil { + in, out := &in.NetworkChaos, &out.NetworkChaos + *out = new(NetworkChaosSpec) + (*in).DeepCopyInto(*out) + } + if in.PhysicalMachineChaos != nil { + in, out := &in.PhysicalMachineChaos, &out.PhysicalMachineChaos + *out = new(PhysicalMachineChaosSpec) + (*in).DeepCopyInto(*out) + } + if in.PodChaos != nil { + in, out := &in.PodChaos, &out.PodChaos + *out = new(PodChaosSpec) + (*in).DeepCopyInto(*out) + } + if in.StressChaos != nil { + in, out := &in.StressChaos, &out.StressChaos + *out = new(StressChaosSpec) + (*in).DeepCopyInto(*out) + } + if in.TimeChaos != nil { + in, out := &in.TimeChaos, &out.TimeChaos + *out = new(TimeChaosSpec) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmbedChaos. +func (in *EmbedChaos) DeepCopy() *EmbedChaos { + if in == nil { + return nil + } + out := new(EmbedChaos) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EmbedStatusCheck) DeepCopyInto(out *EmbedStatusCheck) { + *out = *in + if in.HTTPStatusCheck != nil { + in, out := &in.HTTPStatusCheck, &out.HTTPStatusCheck + *out = new(HTTPStatusCheck) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmbedStatusCheck. +func (in *EmbedStatusCheck) DeepCopy() *EmbedStatusCheck { + if in == nil { + return nil + } + out := new(EmbedStatusCheck) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExpInfo) DeepCopyInto(out *ExpInfo) { + *out = *in + if in.StressCPU != nil { + in, out := &in.StressCPU, &out.StressCPU + *out = new(StressCPUSpec) + (*in).DeepCopyInto(*out) + } + if in.StressMemory != nil { + in, out := &in.StressMemory, &out.StressMemory + *out = new(StressMemorySpec) + (*in).DeepCopyInto(*out) + } + if in.DiskReadPayload != nil { + in, out := &in.DiskReadPayload, &out.DiskReadPayload + *out = new(DiskPayloadSpec) + **out = **in + } + if in.DiskWritePayload != nil { + in, out := &in.DiskWritePayload, &out.DiskWritePayload + *out = new(DiskPayloadSpec) + **out = **in + } + if in.DiskFill != nil { + in, out := &in.DiskFill, &out.DiskFill + *out = new(DiskFillSpec) + **out = **in + } + if in.NetworkCorrupt != nil { + in, out := &in.NetworkCorrupt, &out.NetworkCorrupt + *out = new(NetworkCorruptSpec) + **out = **in + } + if in.NetworkDuplicate != nil { + in, out := &in.NetworkDuplicate, &out.NetworkDuplicate + *out = new(NetworkDuplicateSpec) + **out = **in + } + if in.NetworkLoss != nil { + in, out := &in.NetworkLoss, &out.NetworkLoss + *out = new(NetworkLossSpec) + **out = **in + } + if in.NetworkDelay != nil { + in, out := &in.NetworkDelay, &out.NetworkDelay + *out = new(NetworkDelaySpec) + **out = **in + } + if in.NetworkPartition != nil { + in, out := &in.NetworkPartition, &out.NetworkPartition + *out = new(NetworkPartitionSpec) + **out = **in + } + if in.NetworkDNS != nil { + in, out := &in.NetworkDNS, &out.NetworkDNS + *out = new(NetworkDNSSpec) + **out = **in + } + if in.NetworkBandwidth != nil { + in, out := &in.NetworkBandwidth, &out.NetworkBandwidth + *out = new(NetworkBandwidthSpec) + (*in).DeepCopyInto(*out) + } + if in.NetworkFlood != nil { + in, out := &in.NetworkFlood, &out.NetworkFlood + *out = new(NetworkFloodSpec) + **out = **in + } + if in.NetworkDown != nil { + in, out := &in.NetworkDown, &out.NetworkDown + *out = new(NetworkDownSpec) + **out = **in + } + if in.Process != nil { + in, out := &in.Process, &out.Process + *out = new(ProcessSpec) + **out = **in + } + if in.JVMException != nil { + in, out := &in.JVMException, &out.JVMException + *out = new(JVMExceptionSpec) + **out = **in + } + if in.JVMGC != nil { + in, out := &in.JVMGC, &out.JVMGC + *out = new(JVMGCSpec) + **out = **in + } + if in.JVMLatency != nil { + in, out := &in.JVMLatency, &out.JVMLatency + *out = new(JVMLatencySpec) + **out = **in + } + if in.JVMReturn != nil { + in, out := &in.JVMReturn, &out.JVMReturn + *out = new(JVMReturnSpec) + **out = **in + } + if in.JVMStress != nil { + in, out := &in.JVMStress, &out.JVMStress + *out = new(JVMStressSpec) + **out = **in + } + if in.JVMRuleData != nil { + in, out := &in.JVMRuleData, &out.JVMRuleData + *out = new(JVMRuleDataSpec) + **out = **in + } + if in.JVMMySQL != nil { + in, out := &in.JVMMySQL, &out.JVMMySQL + *out = new(PMJVMMySQLSpec) + **out = **in + } + if in.Clock != nil { + in, out := &in.Clock, &out.Clock + *out = new(ClockSpec) + **out = **in + } + if in.RedisExpiration != nil { + in, out := &in.RedisExpiration, &out.RedisExpiration + *out = new(RedisExpirationSpec) + **out = **in + } + if in.RedisPenetration != nil { + in, out := &in.RedisPenetration, &out.RedisPenetration + *out = new(RedisPenetrationSpec) + **out = **in + } + if in.RedisCacheLimit != nil { + in, out := &in.RedisCacheLimit, &out.RedisCacheLimit + *out = new(RedisCacheLimitSpec) + **out = **in + } + if in.RedisSentinelRestart != nil { + in, out := &in.RedisSentinelRestart, &out.RedisSentinelRestart + *out = new(RedisSentinelRestartSpec) + **out = **in + } + if in.RedisSentinelStop != nil { + in, out := &in.RedisSentinelStop, &out.RedisSentinelStop + *out = new(RedisSentinelStopSpec) + **out = **in + } + if in.KafkaFill != nil { + in, out := &in.KafkaFill, &out.KafkaFill + *out = new(KafkaFillSpec) + **out = **in + } + if in.KafkaFlood != nil { + in, out := &in.KafkaFlood, &out.KafkaFlood + *out = new(KafkaFloodSpec) + **out = **in + } + if in.KafkaIO != nil { + in, out := &in.KafkaIO, &out.KafkaIO + *out = new(KafkaIOSpec) + **out = **in + } + if in.HTTPAbort != nil { + in, out := &in.HTTPAbort, &out.HTTPAbort + *out = new(HTTPAbortSpec) + (*in).DeepCopyInto(*out) + } + if in.HTTPDelay != nil { + in, out := &in.HTTPDelay, &out.HTTPDelay + *out = new(HTTPDelaySpec) + (*in).DeepCopyInto(*out) + } + if in.HTTPConfig != nil { + in, out := &in.HTTPConfig, &out.HTTPConfig + *out = new(HTTPConfigSpec) + **out = **in + } + if in.HTTPRequest != nil { + in, out := &in.HTTPRequest, &out.HTTPRequest + *out = new(HTTPRequestSpec) + **out = **in + } + if in.FileCreate != nil { + in, out := &in.FileCreate, &out.FileCreate + *out = new(FileCreateSpec) + **out = **in + } + if in.FileModifyPrivilege != nil { + in, out := &in.FileModifyPrivilege, &out.FileModifyPrivilege + *out = new(FileModifyPrivilegeSpec) + **out = **in + } + if in.FileDelete != nil { + in, out := &in.FileDelete, &out.FileDelete + *out = new(FileDeleteSpec) + **out = **in + } + if in.FileRename != nil { + in, out := &in.FileRename, &out.FileRename + *out = new(FileRenameSpec) + **out = **in + } + if in.FileAppend != nil { + in, out := &in.FileAppend, &out.FileAppend + *out = new(FileAppendSpec) + **out = **in + } + if in.FileReplace != nil { + in, out := &in.FileReplace, &out.FileReplace + *out = new(FileReplaceSpec) + **out = **in + } + if in.VM != nil { + in, out := &in.VM, &out.VM + *out = new(VMSpec) + **out = **in + } + if in.UserDefined != nil { + in, out := &in.UserDefined, &out.UserDefined + *out = new(UserDefinedSpec) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpInfo. +func (in *ExpInfo) DeepCopy() *ExpInfo { + if in == nil { + return nil + } + out := new(ExpInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExperimentStatus) DeepCopyInto(out *ExperimentStatus) { + *out = *in + if in.Records != nil { + in, out := &in.Records, &out.Records + *out = make([]*Record, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Record) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExperimentStatus. +func (in *ExperimentStatus) DeepCopy() *ExperimentStatus { + if in == nil { + return nil + } + out := new(ExperimentStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FailKernRequest) DeepCopyInto(out *FailKernRequest) { + *out = *in + if in.Headers != nil { + in, out := &in.Headers, &out.Headers + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Callchain != nil { + in, out := &in.Callchain, &out.Callchain + *out = make([]Frame, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FailKernRequest. +func (in *FailKernRequest) DeepCopy() *FailKernRequest { + if in == nil { + return nil + } + out := new(FailKernRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FileAppendSpec) DeepCopyInto(out *FileAppendSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileAppendSpec. +func (in *FileAppendSpec) DeepCopy() *FileAppendSpec { + if in == nil { + return nil + } + out := new(FileAppendSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FileCreateSpec) DeepCopyInto(out *FileCreateSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileCreateSpec. +func (in *FileCreateSpec) DeepCopy() *FileCreateSpec { + if in == nil { + return nil + } + out := new(FileCreateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FileDeleteSpec) DeepCopyInto(out *FileDeleteSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileDeleteSpec. +func (in *FileDeleteSpec) DeepCopy() *FileDeleteSpec { + if in == nil { + return nil + } + out := new(FileDeleteSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FileModifyPrivilegeSpec) DeepCopyInto(out *FileModifyPrivilegeSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileModifyPrivilegeSpec. +func (in *FileModifyPrivilegeSpec) DeepCopy() *FileModifyPrivilegeSpec { + if in == nil { + return nil + } + out := new(FileModifyPrivilegeSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FileRenameSpec) DeepCopyInto(out *FileRenameSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileRenameSpec. +func (in *FileRenameSpec) DeepCopy() *FileRenameSpec { + if in == nil { + return nil + } + out := new(FileRenameSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FileReplaceSpec) DeepCopyInto(out *FileReplaceSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileReplaceSpec. +func (in *FileReplaceSpec) DeepCopy() *FileReplaceSpec { + if in == nil { + return nil + } + out := new(FileReplaceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Filter) DeepCopyInto(out *Filter) { + *out = *in + if in.Methods != nil { + in, out := &in.Methods, &out.Methods + *out = make([]IoMethod, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Filter. +func (in *Filter) DeepCopy() *Filter { + if in == nil { + return nil + } + out := new(Filter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Frame) DeepCopyInto(out *Frame) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Frame. +func (in *Frame) DeepCopy() *Frame { + if in == nil { + return nil + } + out := new(Frame) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GCPChaos) DeepCopyInto(out *GCPChaos) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCPChaos. +func (in *GCPChaos) DeepCopy() *GCPChaos { + if in == nil { + return nil + } + out := new(GCPChaos) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *GCPChaos) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GCPChaosList) DeepCopyInto(out *GCPChaosList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]GCPChaos, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCPChaosList. +func (in *GCPChaosList) DeepCopy() *GCPChaosList { + if in == nil { + return nil + } + out := new(GCPChaosList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *GCPChaosList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GCPChaosSpec) DeepCopyInto(out *GCPChaosSpec) { + *out = *in + if in.Duration != nil { + in, out := &in.Duration, &out.Duration + *out = new(string) + **out = **in + } + if in.SecretName != nil { + in, out := &in.SecretName, &out.SecretName + *out = new(string) + **out = **in + } + in.GCPSelector.DeepCopyInto(&out.GCPSelector) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCPChaosSpec. +func (in *GCPChaosSpec) DeepCopy() *GCPChaosSpec { + if in == nil { + return nil + } + out := new(GCPChaosSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GCPChaosStatus) DeepCopyInto(out *GCPChaosStatus) { + *out = *in + in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) + if in.AttachedDisksStrings != nil { + in, out := &in.AttachedDisksStrings, &out.AttachedDisksStrings + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCPChaosStatus. +func (in *GCPChaosStatus) DeepCopy() *GCPChaosStatus { + if in == nil { + return nil + } + out := new(GCPChaosStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in GCPDeviceNames) DeepCopyInto(out *GCPDeviceNames) { + { + in := &in + *out = make(GCPDeviceNames, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCPDeviceNames. +func (in GCPDeviceNames) DeepCopy() GCPDeviceNames { + if in == nil { + return nil + } + out := new(GCPDeviceNames) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GCPSelector) DeepCopyInto(out *GCPSelector) { + *out = *in + if in.DeviceNames != nil { + in, out := &in.DeviceNames, &out.DeviceNames + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCPSelector. +func (in *GCPSelector) DeepCopy() *GCPSelector { + if in == nil { + return nil + } + out := new(GCPSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GenericSelectorSpec) DeepCopyInto(out *GenericSelectorSpec) { + *out = *in + if in.Namespaces != nil { + in, out := &in.Namespaces, &out.Namespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.FieldSelectors != nil { + in, out := &in.FieldSelectors, &out.FieldSelectors + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.LabelSelectors != nil { + in, out := &in.LabelSelectors, &out.LabelSelectors + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.ExpressionSelectors != nil { + in, out := &in.ExpressionSelectors, &out.ExpressionSelectors + *out = make(LabelSelectorRequirements, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.AnnotationSelectors != nil { + in, out := &in.AnnotationSelectors, &out.AnnotationSelectors + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericSelectorSpec. +func (in *GenericSelectorSpec) DeepCopy() *GenericSelectorSpec { + if in == nil { + return nil + } + out := new(GenericSelectorSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPAbortSpec) DeepCopyInto(out *HTTPAbortSpec) { + *out = *in + in.HTTPCommonSpec.DeepCopyInto(&out.HTTPCommonSpec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPAbortSpec. +func (in *HTTPAbortSpec) DeepCopy() *HTTPAbortSpec { + if in == nil { + return nil + } + out := new(HTTPAbortSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPChaos) DeepCopyInto(out *HTTPChaos) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPChaos. +func (in *HTTPChaos) DeepCopy() *HTTPChaos { + if in == nil { + return nil + } + out := new(HTTPChaos) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HTTPChaos) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPChaosList) DeepCopyInto(out *HTTPChaosList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]HTTPChaos, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPChaosList. +func (in *HTTPChaosList) DeepCopy() *HTTPChaosList { + if in == nil { + return nil + } + out := new(HTTPChaosList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HTTPChaosList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPChaosSpec) DeepCopyInto(out *HTTPChaosSpec) { + *out = *in + in.PodSelector.DeepCopyInto(&out.PodSelector) + in.PodHttpChaosActions.DeepCopyInto(&out.PodHttpChaosActions) + if in.Path != nil { + in, out := &in.Path, &out.Path + *out = new(string) + **out = **in + } + if in.Method != nil { + in, out := &in.Method, &out.Method + *out = new(string) + **out = **in + } + if in.Code != nil { + in, out := &in.Code, &out.Code + *out = new(int32) + **out = **in + } + if in.RequestHeaders != nil { + in, out := &in.RequestHeaders, &out.RequestHeaders + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.ResponseHeaders != nil { + in, out := &in.ResponseHeaders, &out.ResponseHeaders + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.TLS != nil { + in, out := &in.TLS, &out.TLS + *out = new(PodHttpChaosTLS) + (*in).DeepCopyInto(*out) + } + if in.Duration != nil { + in, out := &in.Duration, &out.Duration + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPChaosSpec. +func (in *HTTPChaosSpec) DeepCopy() *HTTPChaosSpec { + if in == nil { + return nil + } + out := new(HTTPChaosSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPChaosStatus) DeepCopyInto(out *HTTPChaosStatus) { + *out = *in + in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) + if in.Instances != nil { + in, out := &in.Instances, &out.Instances + *out = make(map[string]int64, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPChaosStatus. +func (in *HTTPChaosStatus) DeepCopy() *HTTPChaosStatus { + if in == nil { + return nil + } + out := new(HTTPChaosStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPCommonSpec) DeepCopyInto(out *HTTPCommonSpec) { + *out = *in + if in.ProxyPorts != nil { + in, out := &in.ProxyPorts, &out.ProxyPorts + *out = make([]uint, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPCommonSpec. +func (in *HTTPCommonSpec) DeepCopy() *HTTPCommonSpec { + if in == nil { + return nil + } + out := new(HTTPCommonSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPConfigSpec) DeepCopyInto(out *HTTPConfigSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPConfigSpec. +func (in *HTTPConfigSpec) DeepCopy() *HTTPConfigSpec { + if in == nil { + return nil + } + out := new(HTTPConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPCriteria) DeepCopyInto(out *HTTPCriteria) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPCriteria. +func (in *HTTPCriteria) DeepCopy() *HTTPCriteria { + if in == nil { + return nil + } + out := new(HTTPCriteria) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPDelaySpec) DeepCopyInto(out *HTTPDelaySpec) { + *out = *in + in.HTTPCommonSpec.DeepCopyInto(&out.HTTPCommonSpec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPDelaySpec. +func (in *HTTPDelaySpec) DeepCopy() *HTTPDelaySpec { + if in == nil { + return nil + } + out := new(HTTPDelaySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPRequestSpec) DeepCopyInto(out *HTTPRequestSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRequestSpec. +func (in *HTTPRequestSpec) DeepCopy() *HTTPRequestSpec { + if in == nil { + return nil + } + out := new(HTTPRequestSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPStatusCheck) DeepCopyInto(out *HTTPStatusCheck) { + *out = *in + if in.RequestHeaders != nil { + in, out := &in.RequestHeaders, &out.RequestHeaders + *out = make(http.Header, len(*in)) + for key, val := range *in { + var outVal []string + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = make([]string, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } + out.Criteria = in.Criteria +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPStatusCheck. +func (in *HTTPStatusCheck) DeepCopy() *HTTPStatusCheck { + if in == nil { + return nil + } + out := new(HTTPStatusCheck) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IOChaos) DeepCopyInto(out *IOChaos) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IOChaos. +func (in *IOChaos) DeepCopy() *IOChaos { + if in == nil { + return nil + } + out := new(IOChaos) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IOChaos) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IOChaosAction) DeepCopyInto(out *IOChaosAction) { + *out = *in + in.Filter.DeepCopyInto(&out.Filter) + if in.Faults != nil { + in, out := &in.Faults, &out.Faults + *out = make([]IoFault, len(*in)) + copy(*out, *in) + } + if in.AttrOverrideSpec != nil { + in, out := &in.AttrOverrideSpec, &out.AttrOverrideSpec + *out = new(AttrOverrideSpec) + (*in).DeepCopyInto(*out) + } + if in.MistakeSpec != nil { + in, out := &in.MistakeSpec, &out.MistakeSpec + *out = new(MistakeSpec) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IOChaosAction. +func (in *IOChaosAction) DeepCopy() *IOChaosAction { + if in == nil { + return nil + } + out := new(IOChaosAction) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IOChaosList) DeepCopyInto(out *IOChaosList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]IOChaos, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IOChaosList. +func (in *IOChaosList) DeepCopy() *IOChaosList { + if in == nil { + return nil + } + out := new(IOChaosList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IOChaosList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IOChaosSpec) DeepCopyInto(out *IOChaosSpec) { + *out = *in + in.ContainerSelector.DeepCopyInto(&out.ContainerSelector) + if in.Attr != nil { + in, out := &in.Attr, &out.Attr + *out = new(AttrOverrideSpec) + (*in).DeepCopyInto(*out) + } + if in.Mistake != nil { + in, out := &in.Mistake, &out.Mistake + *out = new(MistakeSpec) + **out = **in + } + if in.Methods != nil { + in, out := &in.Methods, &out.Methods + *out = make([]IoMethod, len(*in)) + copy(*out, *in) + } + if in.Duration != nil { + in, out := &in.Duration, &out.Duration + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IOChaosSpec. +func (in *IOChaosSpec) DeepCopy() *IOChaosSpec { + if in == nil { + return nil + } + out := new(IOChaosSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IOChaosStatus) DeepCopyInto(out *IOChaosStatus) { + *out = *in + in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) + if in.Instances != nil { + in, out := &in.Instances, &out.Instances + *out = make(map[string]int64, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IOChaosStatus. +func (in *IOChaosStatus) DeepCopy() *IOChaosStatus { + if in == nil { + return nil + } + out := new(IOChaosStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IoFault) DeepCopyInto(out *IoFault) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IoFault. +func (in *IoFault) DeepCopy() *IoFault { + if in == nil { + return nil + } + out := new(IoFault) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMChaos) DeepCopyInto(out *JVMChaos) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMChaos. +func (in *JVMChaos) DeepCopy() *JVMChaos { + if in == nil { + return nil + } + out := new(JVMChaos) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *JVMChaos) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMChaosList) DeepCopyInto(out *JVMChaosList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]JVMChaos, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMChaosList. +func (in *JVMChaosList) DeepCopy() *JVMChaosList { + if in == nil { + return nil + } + out := new(JVMChaosList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *JVMChaosList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMChaosSpec) DeepCopyInto(out *JVMChaosSpec) { + *out = *in + in.ContainerSelector.DeepCopyInto(&out.ContainerSelector) + if in.Duration != nil { + in, out := &in.Duration, &out.Duration + *out = new(string) + **out = **in + } + out.JVMParameter = in.JVMParameter +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMChaosSpec. +func (in *JVMChaosSpec) DeepCopy() *JVMChaosSpec { + if in == nil { + return nil + } + out := new(JVMChaosSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMChaosStatus) DeepCopyInto(out *JVMChaosStatus) { + *out = *in + in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMChaosStatus. +func (in *JVMChaosStatus) DeepCopy() *JVMChaosStatus { + if in == nil { + return nil + } + out := new(JVMChaosStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMClassMethodSpec) DeepCopyInto(out *JVMClassMethodSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMClassMethodSpec. +func (in *JVMClassMethodSpec) DeepCopy() *JVMClassMethodSpec { + if in == nil { + return nil + } + out := new(JVMClassMethodSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMCommonSpec) DeepCopyInto(out *JVMCommonSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMCommonSpec. +func (in *JVMCommonSpec) DeepCopy() *JVMCommonSpec { + if in == nil { + return nil + } + out := new(JVMCommonSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMExceptionSpec) DeepCopyInto(out *JVMExceptionSpec) { + *out = *in + out.JVMCommonSpec = in.JVMCommonSpec + out.JVMClassMethodSpec = in.JVMClassMethodSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMExceptionSpec. +func (in *JVMExceptionSpec) DeepCopy() *JVMExceptionSpec { + if in == nil { + return nil + } + out := new(JVMExceptionSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMGCSpec) DeepCopyInto(out *JVMGCSpec) { + *out = *in + out.JVMCommonSpec = in.JVMCommonSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMGCSpec. +func (in *JVMGCSpec) DeepCopy() *JVMGCSpec { + if in == nil { + return nil + } + out := new(JVMGCSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMLatencySpec) DeepCopyInto(out *JVMLatencySpec) { + *out = *in + out.JVMCommonSpec = in.JVMCommonSpec + out.JVMClassMethodSpec = in.JVMClassMethodSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMLatencySpec. +func (in *JVMLatencySpec) DeepCopy() *JVMLatencySpec { + if in == nil { + return nil + } + out := new(JVMLatencySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMMySQLSpec) DeepCopyInto(out *JVMMySQLSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMMySQLSpec. +func (in *JVMMySQLSpec) DeepCopy() *JVMMySQLSpec { + if in == nil { + return nil + } + out := new(JVMMySQLSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMParameter) DeepCopyInto(out *JVMParameter) { + *out = *in + out.JVMCommonSpec = in.JVMCommonSpec + out.JVMClassMethodSpec = in.JVMClassMethodSpec + out.JVMStressCfgSpec = in.JVMStressCfgSpec + out.JVMMySQLSpec = in.JVMMySQLSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMParameter. +func (in *JVMParameter) DeepCopy() *JVMParameter { + if in == nil { + return nil + } + out := new(JVMParameter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMReturnSpec) DeepCopyInto(out *JVMReturnSpec) { + *out = *in + out.JVMCommonSpec = in.JVMCommonSpec + out.JVMClassMethodSpec = in.JVMClassMethodSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMReturnSpec. +func (in *JVMReturnSpec) DeepCopy() *JVMReturnSpec { + if in == nil { + return nil + } + out := new(JVMReturnSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMRuleDataSpec) DeepCopyInto(out *JVMRuleDataSpec) { + *out = *in + out.JVMCommonSpec = in.JVMCommonSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMRuleDataSpec. +func (in *JVMRuleDataSpec) DeepCopy() *JVMRuleDataSpec { + if in == nil { + return nil + } + out := new(JVMRuleDataSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMStressCfgSpec) DeepCopyInto(out *JVMStressCfgSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMStressCfgSpec. +func (in *JVMStressCfgSpec) DeepCopy() *JVMStressCfgSpec { + if in == nil { + return nil + } + out := new(JVMStressCfgSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JVMStressSpec) DeepCopyInto(out *JVMStressSpec) { + *out = *in + out.JVMCommonSpec = in.JVMCommonSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMStressSpec. +func (in *JVMStressSpec) DeepCopy() *JVMStressSpec { + if in == nil { + return nil + } + out := new(JVMStressSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KafkaCommonSpec) DeepCopyInto(out *KafkaCommonSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KafkaCommonSpec. +func (in *KafkaCommonSpec) DeepCopy() *KafkaCommonSpec { + if in == nil { + return nil + } + out := new(KafkaCommonSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KafkaFillSpec) DeepCopyInto(out *KafkaFillSpec) { + *out = *in + out.KafkaCommonSpec = in.KafkaCommonSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KafkaFillSpec. +func (in *KafkaFillSpec) DeepCopy() *KafkaFillSpec { + if in == nil { + return nil + } + out := new(KafkaFillSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KafkaFloodSpec) DeepCopyInto(out *KafkaFloodSpec) { + *out = *in + out.KafkaCommonSpec = in.KafkaCommonSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KafkaFloodSpec. +func (in *KafkaFloodSpec) DeepCopy() *KafkaFloodSpec { + if in == nil { + return nil + } + out := new(KafkaFloodSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KafkaIOSpec) DeepCopyInto(out *KafkaIOSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KafkaIOSpec. +func (in *KafkaIOSpec) DeepCopy() *KafkaIOSpec { + if in == nil { + return nil + } + out := new(KafkaIOSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KernelChaos) DeepCopyInto(out *KernelChaos) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KernelChaos. +func (in *KernelChaos) DeepCopy() *KernelChaos { + if in == nil { + return nil + } + out := new(KernelChaos) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KernelChaos) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KernelChaosList) DeepCopyInto(out *KernelChaosList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]KernelChaos, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KernelChaosList. +func (in *KernelChaosList) DeepCopy() *KernelChaosList { + if in == nil { + return nil + } + out := new(KernelChaosList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KernelChaosList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KernelChaosSpec) DeepCopyInto(out *KernelChaosSpec) { + *out = *in + in.ContainerSelector.DeepCopyInto(&out.ContainerSelector) + in.FailKernRequest.DeepCopyInto(&out.FailKernRequest) + if in.Duration != nil { + in, out := &in.Duration, &out.Duration + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KernelChaosSpec. +func (in *KernelChaosSpec) DeepCopy() *KernelChaosSpec { + if in == nil { + return nil + } + out := new(KernelChaosSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KernelChaosStatus) DeepCopyInto(out *KernelChaosStatus) { + *out = *in + in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KernelChaosStatus. +func (in *KernelChaosStatus) DeepCopy() *KernelChaosStatus { + if in == nil { + return nil + } + out := new(KernelChaosStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in LabelSelectorRequirements) DeepCopyInto(out *LabelSelectorRequirements) { + { + in := &in + *out = make(LabelSelectorRequirements, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LabelSelectorRequirements. +func (in LabelSelectorRequirements) DeepCopy() LabelSelectorRequirements { + if in == nil { + return nil + } + out := new(LabelSelectorRequirements) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LossSpec) DeepCopyInto(out *LossSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LossSpec. +func (in *LossSpec) DeepCopy() *LossSpec { + if in == nil { + return nil + } + out := new(LossSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MemoryStressor) DeepCopyInto(out *MemoryStressor) { + *out = *in + out.Stressor = in.Stressor + if in.Options != nil { + in, out := &in.Options, &out.Options + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MemoryStressor. +func (in *MemoryStressor) DeepCopy() *MemoryStressor { + if in == nil { + return nil + } + out := new(MemoryStressor) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MistakeSpec) DeepCopyInto(out *MistakeSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MistakeSpec. +func (in *MistakeSpec) DeepCopy() *MistakeSpec { + if in == nil { + return nil + } + out := new(MistakeSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkBandwidthSpec) DeepCopyInto(out *NetworkBandwidthSpec) { + *out = *in + if in.Peakrate != nil { + in, out := &in.Peakrate, &out.Peakrate + *out = new(uint64) + **out = **in + } + if in.Minburst != nil { + in, out := &in.Minburst, &out.Minburst + *out = new(uint32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkBandwidthSpec. +func (in *NetworkBandwidthSpec) DeepCopy() *NetworkBandwidthSpec { + if in == nil { + return nil + } + out := new(NetworkBandwidthSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkChaos) DeepCopyInto(out *NetworkChaos) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkChaos. +func (in *NetworkChaos) DeepCopy() *NetworkChaos { + if in == nil { + return nil + } + out := new(NetworkChaos) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NetworkChaos) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkChaosList) DeepCopyInto(out *NetworkChaosList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]NetworkChaos, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkChaosList. +func (in *NetworkChaosList) DeepCopy() *NetworkChaosList { + if in == nil { + return nil + } + out := new(NetworkChaosList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NetworkChaosList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkChaosSpec) DeepCopyInto(out *NetworkChaosSpec) { + *out = *in + in.PodSelector.DeepCopyInto(&out.PodSelector) + if in.Duration != nil { + in, out := &in.Duration, &out.Duration + *out = new(string) + **out = **in + } + in.TcParameter.DeepCopyInto(&out.TcParameter) + if in.Target != nil { + in, out := &in.Target, &out.Target + *out = new(PodSelector) + (*in).DeepCopyInto(*out) + } + if in.ExternalTargets != nil { + in, out := &in.ExternalTargets, &out.ExternalTargets + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkChaosSpec. +func (in *NetworkChaosSpec) DeepCopy() *NetworkChaosSpec { + if in == nil { + return nil + } + out := new(NetworkChaosSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkChaosStatus) DeepCopyInto(out *NetworkChaosStatus) { + *out = *in + in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) + if in.Instances != nil { + in, out := &in.Instances, &out.Instances + *out = make(map[string]int64, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkChaosStatus. +func (in *NetworkChaosStatus) DeepCopy() *NetworkChaosStatus { + if in == nil { + return nil + } + out := new(NetworkChaosStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkCommonSpec) DeepCopyInto(out *NetworkCommonSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkCommonSpec. +func (in *NetworkCommonSpec) DeepCopy() *NetworkCommonSpec { + if in == nil { + return nil + } + out := new(NetworkCommonSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkCorruptSpec) DeepCopyInto(out *NetworkCorruptSpec) { + *out = *in + out.NetworkCommonSpec = in.NetworkCommonSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkCorruptSpec. +func (in *NetworkCorruptSpec) DeepCopy() *NetworkCorruptSpec { + if in == nil { + return nil + } + out := new(NetworkCorruptSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkDNSSpec) DeepCopyInto(out *NetworkDNSSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkDNSSpec. +func (in *NetworkDNSSpec) DeepCopy() *NetworkDNSSpec { + if in == nil { + return nil + } + out := new(NetworkDNSSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkDelaySpec) DeepCopyInto(out *NetworkDelaySpec) { + *out = *in + out.NetworkCommonSpec = in.NetworkCommonSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkDelaySpec. +func (in *NetworkDelaySpec) DeepCopy() *NetworkDelaySpec { + if in == nil { + return nil + } + out := new(NetworkDelaySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkDownSpec) DeepCopyInto(out *NetworkDownSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkDownSpec. +func (in *NetworkDownSpec) DeepCopy() *NetworkDownSpec { + if in == nil { + return nil + } + out := new(NetworkDownSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkDuplicateSpec) DeepCopyInto(out *NetworkDuplicateSpec) { + *out = *in + out.NetworkCommonSpec = in.NetworkCommonSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkDuplicateSpec. +func (in *NetworkDuplicateSpec) DeepCopy() *NetworkDuplicateSpec { + if in == nil { + return nil + } + out := new(NetworkDuplicateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkFloodSpec) DeepCopyInto(out *NetworkFloodSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkFloodSpec. +func (in *NetworkFloodSpec) DeepCopy() *NetworkFloodSpec { + if in == nil { + return nil + } + out := new(NetworkFloodSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLossSpec) DeepCopyInto(out *NetworkLossSpec) { + *out = *in + out.NetworkCommonSpec = in.NetworkCommonSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLossSpec. +func (in *NetworkLossSpec) DeepCopy() *NetworkLossSpec { + if in == nil { + return nil + } + out := new(NetworkLossSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkPartitionSpec) DeepCopyInto(out *NetworkPartitionSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkPartitionSpec. +func (in *NetworkPartitionSpec) DeepCopy() *NetworkPartitionSpec { + if in == nil { + return nil + } + out := new(NetworkPartitionSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PMJVMMySQLSpec) DeepCopyInto(out *PMJVMMySQLSpec) { + *out = *in + out.JVMCommonSpec = in.JVMCommonSpec + out.JVMMySQLSpec = in.JVMMySQLSpec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PMJVMMySQLSpec. +func (in *PMJVMMySQLSpec) DeepCopy() *PMJVMMySQLSpec { + if in == nil { + return nil + } + out := new(PMJVMMySQLSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PhysicalMachine) DeepCopyInto(out *PhysicalMachine) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhysicalMachine. +func (in *PhysicalMachine) DeepCopy() *PhysicalMachine { + if in == nil { + return nil + } + out := new(PhysicalMachine) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PhysicalMachine) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PhysicalMachineChaos) DeepCopyInto(out *PhysicalMachineChaos) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhysicalMachineChaos. +func (in *PhysicalMachineChaos) DeepCopy() *PhysicalMachineChaos { + if in == nil { + return nil + } + out := new(PhysicalMachineChaos) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PhysicalMachineChaos) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PhysicalMachineChaosList) DeepCopyInto(out *PhysicalMachineChaosList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PhysicalMachineChaos, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhysicalMachineChaosList. +func (in *PhysicalMachineChaosList) DeepCopy() *PhysicalMachineChaosList { + if in == nil { + return nil + } + out := new(PhysicalMachineChaosList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PhysicalMachineChaosList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PhysicalMachineChaosSpec) DeepCopyInto(out *PhysicalMachineChaosSpec) { + *out = *in + in.PhysicalMachineSelector.DeepCopyInto(&out.PhysicalMachineSelector) + in.ExpInfo.DeepCopyInto(&out.ExpInfo) + if in.Duration != nil { + in, out := &in.Duration, &out.Duration + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhysicalMachineChaosSpec. +func (in *PhysicalMachineChaosSpec) DeepCopy() *PhysicalMachineChaosSpec { + if in == nil { + return nil + } + out := new(PhysicalMachineChaosSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PhysicalMachineChaosStatus) DeepCopyInto(out *PhysicalMachineChaosStatus) { + *out = *in + in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhysicalMachineChaosStatus. +func (in *PhysicalMachineChaosStatus) DeepCopy() *PhysicalMachineChaosStatus { + if in == nil { + return nil + } + out := new(PhysicalMachineChaosStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PhysicalMachineList) DeepCopyInto(out *PhysicalMachineList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PhysicalMachine, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhysicalMachineList. +func (in *PhysicalMachineList) DeepCopy() *PhysicalMachineList { + if in == nil { + return nil + } + out := new(PhysicalMachineList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PhysicalMachineList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PhysicalMachineSelector) DeepCopyInto(out *PhysicalMachineSelector) { + *out = *in + if in.Address != nil { + in, out := &in.Address, &out.Address + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.Selector.DeepCopyInto(&out.Selector) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhysicalMachineSelector. +func (in *PhysicalMachineSelector) DeepCopy() *PhysicalMachineSelector { + if in == nil { + return nil + } + out := new(PhysicalMachineSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PhysicalMachineSelectorSpec) DeepCopyInto(out *PhysicalMachineSelectorSpec) { + *out = *in + in.GenericSelectorSpec.DeepCopyInto(&out.GenericSelectorSpec) + if in.PhysicalMachines != nil { + in, out := &in.PhysicalMachines, &out.PhysicalMachines + *out = make(map[string][]string, len(*in)) + for key, val := range *in { + var outVal []string + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = make([]string, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhysicalMachineSelectorSpec. +func (in *PhysicalMachineSelectorSpec) DeepCopy() *PhysicalMachineSelectorSpec { + if in == nil { + return nil + } + out := new(PhysicalMachineSelectorSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PhysicalMachineSpec) DeepCopyInto(out *PhysicalMachineSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhysicalMachineSpec. +func (in *PhysicalMachineSpec) DeepCopy() *PhysicalMachineSpec { + if in == nil { + return nil + } + out := new(PhysicalMachineSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodChaos) DeepCopyInto(out *PodChaos) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodChaos. +func (in *PodChaos) DeepCopy() *PodChaos { + if in == nil { + return nil + } + out := new(PodChaos) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodChaos) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodChaosList) DeepCopyInto(out *PodChaosList) { + *out = *in + out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]IoChaos, len(*in)) + *out = make([]PodChaos, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IoChaosList. -func (in *IoChaosList) DeepCopy() *IoChaosList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodChaosList. +func (in *PodChaosList) DeepCopy() *PodChaosList { if in == nil { return nil } - out := new(IoChaosList) + out := new(PodChaosList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *IoChaosList) DeepCopyObject() runtime.Object { +func (in *PodChaosList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -933,103 +3147,407 @@ func (in *IoChaosList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IoChaosSpec) DeepCopyInto(out *IoChaosSpec) { +func (in *PodChaosSpec) DeepCopyInto(out *PodChaosSpec) { *out = *in - in.Selector.DeepCopyInto(&out.Selector) - if in.Attr != nil { - in, out := &in.Attr, &out.Attr - *out = new(AttrOverrideSpec) + in.ContainerSelector.DeepCopyInto(&out.ContainerSelector) + if in.Duration != nil { + in, out := &in.Duration, &out.Duration + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodChaosSpec. +func (in *PodChaosSpec) DeepCopy() *PodChaosSpec { + if in == nil { + return nil + } + out := new(PodChaosSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodChaosStatus) DeepCopyInto(out *PodChaosStatus) { + *out = *in + in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodChaosStatus. +func (in *PodChaosStatus) DeepCopy() *PodChaosStatus { + if in == nil { + return nil + } + out := new(PodChaosStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodHttpChaos) DeepCopyInto(out *PodHttpChaos) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodHttpChaos. +func (in *PodHttpChaos) DeepCopy() *PodHttpChaos { + if in == nil { + return nil + } + out := new(PodHttpChaos) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodHttpChaos) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodHttpChaosActions) DeepCopyInto(out *PodHttpChaosActions) { + *out = *in + if in.Abort != nil { + in, out := &in.Abort, &out.Abort + *out = new(bool) + **out = **in + } + if in.Delay != nil { + in, out := &in.Delay, &out.Delay + *out = new(string) + **out = **in + } + if in.Replace != nil { + in, out := &in.Replace, &out.Replace + *out = new(PodHttpChaosReplaceActions) (*in).DeepCopyInto(*out) } - if in.Mistake != nil { - in, out := &in.Mistake, &out.Mistake - *out = new(MistakeSpec) + if in.Patch != nil { + in, out := &in.Patch, &out.Patch + *out = new(PodHttpChaosPatchActions) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodHttpChaosActions. +func (in *PodHttpChaosActions) DeepCopy() *PodHttpChaosActions { + if in == nil { + return nil + } + out := new(PodHttpChaosActions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodHttpChaosBaseRule) DeepCopyInto(out *PodHttpChaosBaseRule) { + *out = *in + in.Selector.DeepCopyInto(&out.Selector) + in.Actions.DeepCopyInto(&out.Actions) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodHttpChaosBaseRule. +func (in *PodHttpChaosBaseRule) DeepCopy() *PodHttpChaosBaseRule { + if in == nil { + return nil + } + out := new(PodHttpChaosBaseRule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodHttpChaosList) DeepCopyInto(out *PodHttpChaosList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PodHttpChaos, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodHttpChaosList. +func (in *PodHttpChaosList) DeepCopy() *PodHttpChaosList { + if in == nil { + return nil + } + out := new(PodHttpChaosList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodHttpChaosList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodHttpChaosPatchActions) DeepCopyInto(out *PodHttpChaosPatchActions) { + *out = *in + if in.Body != nil { + in, out := &in.Body, &out.Body + *out = new(PodHttpChaosPatchBodyAction) **out = **in } - if in.Methods != nil { - in, out := &in.Methods, &out.Methods - *out = make([]IoMethod, len(*in)) - copy(*out, *in) + if in.Queries != nil { + in, out := &in.Queries, &out.Queries + *out = make([][]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + } + if in.Headers != nil { + in, out := &in.Headers, &out.Headers + *out = make([][]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodHttpChaosPatchActions. +func (in *PodHttpChaosPatchActions) DeepCopy() *PodHttpChaosPatchActions { + if in == nil { + return nil + } + out := new(PodHttpChaosPatchActions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodHttpChaosPatchBodyAction) DeepCopyInto(out *PodHttpChaosPatchBodyAction) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodHttpChaosPatchBodyAction. +func (in *PodHttpChaosPatchBodyAction) DeepCopy() *PodHttpChaosPatchBodyAction { + if in == nil { + return nil } - if in.ContainerName != nil { - in, out := &in.ContainerName, &out.ContainerName + out := new(PodHttpChaosPatchBodyAction) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodHttpChaosReplaceActions) DeepCopyInto(out *PodHttpChaosReplaceActions) { + *out = *in + if in.Path != nil { + in, out := &in.Path, &out.Path *out = new(string) **out = **in } - if in.Scheduler != nil { - in, out := &in.Scheduler, &out.Scheduler - *out = new(SchedulerSpec) + if in.Method != nil { + in, out := &in.Method, &out.Method + *out = new(string) **out = **in } - if in.Duration != nil { - in, out := &in.Duration, &out.Duration + if in.Code != nil { + in, out := &in.Code, &out.Code + *out = new(int32) + **out = **in + } + if in.Body != nil { + in, out := &in.Body, &out.Body + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.Queries != nil { + in, out := &in.Queries, &out.Queries + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Headers != nil { + in, out := &in.Headers, &out.Headers + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodHttpChaosReplaceActions. +func (in *PodHttpChaosReplaceActions) DeepCopy() *PodHttpChaosReplaceActions { + if in == nil { + return nil + } + out := new(PodHttpChaosReplaceActions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodHttpChaosRule) DeepCopyInto(out *PodHttpChaosRule) { + *out = *in + in.PodHttpChaosBaseRule.DeepCopyInto(&out.PodHttpChaosBaseRule) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodHttpChaosRule. +func (in *PodHttpChaosRule) DeepCopy() *PodHttpChaosRule { + if in == nil { + return nil + } + out := new(PodHttpChaosRule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodHttpChaosSelector) DeepCopyInto(out *PodHttpChaosSelector) { + *out = *in + if in.Port != nil { + in, out := &in.Port, &out.Port + *out = new(int32) + **out = **in + } + if in.Path != nil { + in, out := &in.Path, &out.Path + *out = new(string) + **out = **in + } + if in.Method != nil { + in, out := &in.Method, &out.Method *out = new(string) **out = **in } + if in.Code != nil { + in, out := &in.Code, &out.Code + *out = new(int32) + **out = **in + } + if in.RequestHeaders != nil { + in, out := &in.RequestHeaders, &out.RequestHeaders + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.ResponseHeaders != nil { + in, out := &in.ResponseHeaders, &out.ResponseHeaders + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IoChaosSpec. -func (in *IoChaosSpec) DeepCopy() *IoChaosSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodHttpChaosSelector. +func (in *PodHttpChaosSelector) DeepCopy() *PodHttpChaosSelector { if in == nil { return nil } - out := new(IoChaosSpec) + out := new(PodHttpChaosSelector) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IoChaosStatus) DeepCopyInto(out *IoChaosStatus) { +func (in *PodHttpChaosSpec) DeepCopyInto(out *PodHttpChaosSpec) { *out = *in - in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) + if in.Rules != nil { + in, out := &in.Rules, &out.Rules + *out = make([]PodHttpChaosRule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.TLS != nil { + in, out := &in.TLS, &out.TLS + *out = new(PodHttpChaosTLS) + (*in).DeepCopyInto(*out) + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IoChaosStatus. -func (in *IoChaosStatus) DeepCopy() *IoChaosStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodHttpChaosSpec. +func (in *PodHttpChaosSpec) DeepCopy() *PodHttpChaosSpec { if in == nil { return nil } - out := new(IoChaosStatus) + out := new(PodHttpChaosSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IoFault) DeepCopyInto(out *IoFault) { +func (in *PodHttpChaosStatus) DeepCopyInto(out *PodHttpChaosStatus) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IoFault. -func (in *IoFault) DeepCopy() *IoFault { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodHttpChaosStatus. +func (in *PodHttpChaosStatus) DeepCopy() *PodHttpChaosStatus { if in == nil { return nil } - out := new(IoFault) + out := new(PodHttpChaosStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JVMChaos) DeepCopyInto(out *JVMChaos) { +func (in *PodHttpChaosTLS) DeepCopyInto(out *PodHttpChaosTLS) { + *out = *in + if in.CAName != nil { + in, out := &in.CAName, &out.CAName + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodHttpChaosTLS. +func (in *PodHttpChaosTLS) DeepCopy() *PodHttpChaosTLS { + if in == nil { + return nil + } + out := new(PodHttpChaosTLS) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodIOChaos) DeepCopyInto(out *PodIOChaos) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) + out.Status = in.Status } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMChaos. -func (in *JVMChaos) DeepCopy() *JVMChaos { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodIOChaos. +func (in *PodIOChaos) DeepCopy() *PodIOChaos { if in == nil { return nil } - out := new(JVMChaos) + out := new(PodIOChaos) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *JVMChaos) DeepCopyObject() runtime.Object { +func (in *PodIOChaos) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1037,31 +3555,31 @@ func (in *JVMChaos) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JVMChaosList) DeepCopyInto(out *JVMChaosList) { +func (in *PodIOChaosList) DeepCopyInto(out *PodIOChaosList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]JVMChaos, len(*in)) + *out = make([]PodIOChaos, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMChaosList. -func (in *JVMChaosList) DeepCopy() *JVMChaosList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodIOChaosList. +func (in *PodIOChaosList) DeepCopy() *PodIOChaosList { if in == nil { return nil } - out := new(JVMChaosList) + out := new(PodIOChaosList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *JVMChaosList) DeepCopyObject() runtime.Object { +func (in *PodIOChaosList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1069,98 +3587,68 @@ func (in *JVMChaosList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JVMChaosSpec) DeepCopyInto(out *JVMChaosSpec) { +func (in *PodIOChaosSpec) DeepCopyInto(out *PodIOChaosSpec) { *out = *in - in.Selector.DeepCopyInto(&out.Selector) - if in.Duration != nil { - in, out := &in.Duration, &out.Duration + if in.Container != nil { + in, out := &in.Container, &out.Container *out = new(string) **out = **in } - if in.Scheduler != nil { - in, out := &in.Scheduler, &out.Scheduler - *out = new(SchedulerSpec) - **out = **in - } - in.JVMParameter.DeepCopyInto(&out.JVMParameter) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMChaosSpec. -func (in *JVMChaosSpec) DeepCopy() *JVMChaosSpec { - if in == nil { - return nil + if in.Actions != nil { + in, out := &in.Actions, &out.Actions + *out = make([]IOChaosAction, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } - out := new(JVMChaosSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JVMChaosStatus) DeepCopyInto(out *JVMChaosStatus) { - *out = *in - in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMChaosStatus. -func (in *JVMChaosStatus) DeepCopy() *JVMChaosStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodIOChaosSpec. +func (in *PodIOChaosSpec) DeepCopy() *PodIOChaosSpec { if in == nil { return nil } - out := new(JVMChaosStatus) + out := new(PodIOChaosSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JVMParameter) DeepCopyInto(out *JVMParameter) { +func (in *PodIOChaosStatus) DeepCopyInto(out *PodIOChaosStatus) { *out = *in - if in.Flags != nil { - in, out := &in.Flags, &out.Flags - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.Matchers != nil { - in, out := &in.Matchers, &out.Matchers - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMParameter. -func (in *JVMParameter) DeepCopy() *JVMParameter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodIOChaosStatus. +func (in *PodIOChaosStatus) DeepCopy() *PodIOChaosStatus { if in == nil { return nil } - out := new(JVMParameter) + out := new(PodIOChaosStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KernelChaos) DeepCopyInto(out *KernelChaos) { +func (in *PodNetworkChaos) DeepCopyInto(out *PodNetworkChaos) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) + out.Status = in.Status } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KernelChaos. -func (in *KernelChaos) DeepCopy() *KernelChaos { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodNetworkChaos. +func (in *PodNetworkChaos) DeepCopy() *PodNetworkChaos { if in == nil { return nil } - out := new(KernelChaos) + out := new(PodNetworkChaos) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *KernelChaos) DeepCopyObject() runtime.Object { +func (in *PodNetworkChaos) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1168,31 +3656,31 @@ func (in *KernelChaos) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KernelChaosList) DeepCopyInto(out *KernelChaosList) { +func (in *PodNetworkChaosList) DeepCopyInto(out *PodNetworkChaosList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]KernelChaos, len(*in)) + *out = make([]PodNetworkChaos, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KernelChaosList. -func (in *KernelChaosList) DeepCopy() *KernelChaosList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodNetworkChaosList. +func (in *PodNetworkChaosList) DeepCopy() *PodNetworkChaosList { if in == nil { return nil } - out := new(KernelChaosList) + out := new(PodNetworkChaosList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *KernelChaosList) DeepCopyObject() runtime.Object { +func (in *PodNetworkChaosList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1200,423 +3688,391 @@ func (in *KernelChaosList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KernelChaosSpec) DeepCopyInto(out *KernelChaosSpec) { +func (in *PodNetworkChaosSpec) DeepCopyInto(out *PodNetworkChaosSpec) { *out = *in - in.Selector.DeepCopyInto(&out.Selector) - in.FailKernRequest.DeepCopyInto(&out.FailKernRequest) - if in.Duration != nil { - in, out := &in.Duration, &out.Duration - *out = new(string) - **out = **in + if in.IPSets != nil { + in, out := &in.IPSets, &out.IPSets + *out = make([]RawIPSet, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } - if in.Scheduler != nil { - in, out := &in.Scheduler, &out.Scheduler - *out = new(SchedulerSpec) - **out = **in + if in.Iptables != nil { + in, out := &in.Iptables, &out.Iptables + *out = make([]RawIptables, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.TrafficControls != nil { + in, out := &in.TrafficControls, &out.TrafficControls + *out = make([]RawTrafficControl, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KernelChaosSpec. -func (in *KernelChaosSpec) DeepCopy() *KernelChaosSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodNetworkChaosSpec. +func (in *PodNetworkChaosSpec) DeepCopy() *PodNetworkChaosSpec { if in == nil { return nil } - out := new(KernelChaosSpec) + out := new(PodNetworkChaosSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KernelChaosStatus) DeepCopyInto(out *KernelChaosStatus) { +func (in *PodNetworkChaosStatus) DeepCopyInto(out *PodNetworkChaosStatus) { *out = *in - in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KernelChaosStatus. -func (in *KernelChaosStatus) DeepCopy() *KernelChaosStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodNetworkChaosStatus. +func (in *PodNetworkChaosStatus) DeepCopy() *PodNetworkChaosStatus { if in == nil { return nil } - out := new(KernelChaosStatus) + out := new(PodNetworkChaosStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in LabelSelectorRequirements) DeepCopyInto(out *LabelSelectorRequirements) { - { - in := &in - *out = make(LabelSelectorRequirements, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) +func (in *PodSelector) DeepCopyInto(out *PodSelector) { + *out = *in + in.Selector.DeepCopyInto(&out.Selector) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodSelector. +func (in *PodSelector) DeepCopy() *PodSelector { + if in == nil { + return nil + } + out := new(PodSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodSelectorSpec) DeepCopyInto(out *PodSelectorSpec) { + *out = *in + in.GenericSelectorSpec.DeepCopyInto(&out.GenericSelectorSpec) + if in.Nodes != nil { + in, out := &in.Nodes, &out.Nodes + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Pods != nil { + in, out := &in.Pods, &out.Pods + *out = make(map[string][]string, len(*in)) + for key, val := range *in { + var outVal []string + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = make([]string, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal } } + if in.NodeSelectors != nil { + in, out := &in.NodeSelectors, &out.NodeSelectors + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.PodPhaseSelectors != nil { + in, out := &in.PodPhaseSelectors, &out.PodPhaseSelectors + *out = make([]string, len(*in)) + copy(*out, *in) + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LabelSelectorRequirements. -func (in LabelSelectorRequirements) DeepCopy() LabelSelectorRequirements { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodSelectorSpec. +func (in *PodSelectorSpec) DeepCopy() *PodSelectorSpec { if in == nil { return nil } - out := new(LabelSelectorRequirements) + out := new(PodSelectorSpec) in.DeepCopyInto(out) - return *out + return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LossSpec) DeepCopyInto(out *LossSpec) { +func (in *ProcessSpec) DeepCopyInto(out *ProcessSpec) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LossSpec. -func (in *LossSpec) DeepCopy() *LossSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProcessSpec. +func (in *ProcessSpec) DeepCopy() *ProcessSpec { if in == nil { return nil } - out := new(LossSpec) + out := new(ProcessSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Matcher) DeepCopyInto(out *Matcher) { +func (in *RateSpec) DeepCopyInto(out *RateSpec) { *out = *in - if in.ExactMatch != nil { - in, out := &in.ExactMatch, &out.ExactMatch - *out = new(string) - **out = **in - } - if in.RegexMatch != nil { - in, out := &in.RegexMatch, &out.RegexMatch - *out = new(string) - **out = **in - } - if in.SafeRegexMatch != nil { - in, out := &in.SafeRegexMatch, &out.SafeRegexMatch - *out = new(string) - **out = **in - } - if in.RangeMatch != nil { - in, out := &in.RangeMatch, &out.RangeMatch - *out = new(string) - **out = **in - } - if in.PresentMatch != nil { - in, out := &in.PresentMatch, &out.PresentMatch - *out = new(string) - **out = **in - } - if in.PrefixMatch != nil { - in, out := &in.PrefixMatch, &out.PrefixMatch - *out = new(string) - **out = **in - } - if in.SuffixMatch != nil { - in, out := &in.SuffixMatch, &out.SuffixMatch - *out = new(string) - **out = **in - } - if in.InvertMatch != nil { - in, out := &in.InvertMatch, &out.InvertMatch - *out = new(string) - **out = **in - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Matcher. -func (in *Matcher) DeepCopy() *Matcher { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateSpec. +func (in *RateSpec) DeepCopy() *RateSpec { if in == nil { return nil } - out := new(Matcher) + out := new(RateSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MemoryStressor) DeepCopyInto(out *MemoryStressor) { +func (in *RawIPSet) DeepCopyInto(out *RawIPSet) { *out = *in - out.Stressor = in.Stressor - if in.Options != nil { - in, out := &in.Options, &out.Options + if in.Cidrs != nil { + in, out := &in.Cidrs, &out.Cidrs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.CidrAndPorts != nil { + in, out := &in.CidrAndPorts, &out.CidrAndPorts + *out = make([]CidrAndPort, len(*in)) + copy(*out, *in) + } + if in.SetNames != nil { + in, out := &in.SetNames, &out.SetNames *out = make([]string, len(*in)) copy(*out, *in) } + out.RawRuleSource = in.RawRuleSource } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MemoryStressor. -func (in *MemoryStressor) DeepCopy() *MemoryStressor { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RawIPSet. +func (in *RawIPSet) DeepCopy() *RawIPSet { if in == nil { return nil } - out := new(MemoryStressor) + out := new(RawIPSet) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MistakeSpec) DeepCopyInto(out *MistakeSpec) { +func (in *RawIptables) DeepCopyInto(out *RawIptables) { *out = *in + if in.IPSets != nil { + in, out := &in.IPSets, &out.IPSets + *out = make([]string, len(*in)) + copy(*out, *in) + } + out.RawRuleSource = in.RawRuleSource } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MistakeSpec. -func (in *MistakeSpec) DeepCopy() *MistakeSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RawIptables. +func (in *RawIptables) DeepCopy() *RawIptables { if in == nil { return nil } - out := new(MistakeSpec) + out := new(RawIptables) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkChaos) DeepCopyInto(out *NetworkChaos) { +func (in *RawRuleSource) DeepCopyInto(out *RawRuleSource) { *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkChaos. -func (in *NetworkChaos) DeepCopy() *NetworkChaos { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RawRuleSource. +func (in *RawRuleSource) DeepCopy() *RawRuleSource { if in == nil { return nil } - out := new(NetworkChaos) + out := new(RawRuleSource) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NetworkChaos) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RawTrafficControl) DeepCopyInto(out *RawTrafficControl) { + *out = *in + in.TcParameter.DeepCopyInto(&out.TcParameter) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RawTrafficControl. +func (in *RawTrafficControl) DeepCopy() *RawTrafficControl { + if in == nil { + return nil } - return nil + out := new(RawTrafficControl) + in.DeepCopyInto(out) + return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkChaosList) DeepCopyInto(out *NetworkChaosList) { +func (in *Record) DeepCopyInto(out *Record) { *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]NetworkChaos, len(*in)) + if in.Events != nil { + in, out := &in.Events, &out.Events + *out = make([]RecordEvent, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkChaosList. -func (in *NetworkChaosList) DeepCopy() *NetworkChaosList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Record. +func (in *Record) DeepCopy() *Record { if in == nil { return nil } - out := new(NetworkChaosList) + out := new(Record) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NetworkChaosList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkChaosSpec) DeepCopyInto(out *NetworkChaosSpec) { +func (in *RecordEvent) DeepCopyInto(out *RecordEvent) { *out = *in - in.Selector.DeepCopyInto(&out.Selector) - if in.Duration != nil { - in, out := &in.Duration, &out.Duration - *out = new(string) - **out = **in - } - if in.Scheduler != nil { - in, out := &in.Scheduler, &out.Scheduler - *out = new(SchedulerSpec) - **out = **in - } - in.TcParameter.DeepCopyInto(&out.TcParameter) - if in.Target != nil { - in, out := &in.Target, &out.Target - *out = new(Target) - (*in).DeepCopyInto(*out) - } - if in.ExternalTargets != nil { - in, out := &in.ExternalTargets, &out.ExternalTargets - *out = make([]string, len(*in)) - copy(*out, *in) + if in.Timestamp != nil { + in, out := &in.Timestamp, &out.Timestamp + *out = (*in).DeepCopy() } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkChaosSpec. -func (in *NetworkChaosSpec) DeepCopy() *NetworkChaosSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecordEvent. +func (in *RecordEvent) DeepCopy() *RecordEvent { if in == nil { return nil } - out := new(NetworkChaosSpec) + out := new(RecordEvent) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkChaosStatus) DeepCopyInto(out *NetworkChaosStatus) { +func (in *RedisCacheLimitSpec) DeepCopyInto(out *RedisCacheLimitSpec) { *out = *in - in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) + out.RedisCommonSpec = in.RedisCommonSpec } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkChaosStatus. -func (in *NetworkChaosStatus) DeepCopy() *NetworkChaosStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RedisCacheLimitSpec. +func (in *RedisCacheLimitSpec) DeepCopy() *RedisCacheLimitSpec { if in == nil { return nil } - out := new(NetworkChaosStatus) + out := new(RedisCacheLimitSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ParameterRules) DeepCopyInto(out *ParameterRules) { +func (in *RedisCommonSpec) DeepCopyInto(out *RedisCommonSpec) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParameterRules. -func (in *ParameterRules) DeepCopy() *ParameterRules { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RedisCommonSpec. +func (in *RedisCommonSpec) DeepCopy() *RedisCommonSpec { if in == nil { return nil } - out := new(ParameterRules) + out := new(RedisCommonSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PodChaos) DeepCopyInto(out *PodChaos) { +func (in *RedisExpirationSpec) DeepCopyInto(out *RedisExpirationSpec) { *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) + out.RedisCommonSpec = in.RedisCommonSpec } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodChaos. -func (in *PodChaos) DeepCopy() *PodChaos { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RedisExpirationSpec. +func (in *RedisExpirationSpec) DeepCopy() *RedisExpirationSpec { if in == nil { return nil } - out := new(PodChaos) + out := new(RedisExpirationSpec) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PodChaos) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PodChaosList) DeepCopyInto(out *PodChaosList) { +func (in *RedisPenetrationSpec) DeepCopyInto(out *RedisPenetrationSpec) { *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]PodChaos, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } + out.RedisCommonSpec = in.RedisCommonSpec } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodChaosList. -func (in *PodChaosList) DeepCopy() *PodChaosList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RedisPenetrationSpec. +func (in *RedisPenetrationSpec) DeepCopy() *RedisPenetrationSpec { if in == nil { return nil } - out := new(PodChaosList) + out := new(RedisPenetrationSpec) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PodChaosList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PodChaosSpec) DeepCopyInto(out *PodChaosSpec) { +func (in *RedisSentinelRestartSpec) DeepCopyInto(out *RedisSentinelRestartSpec) { *out = *in - in.Selector.DeepCopyInto(&out.Selector) - if in.Scheduler != nil { - in, out := &in.Scheduler, &out.Scheduler - *out = new(SchedulerSpec) - **out = **in - } - if in.Duration != nil { - in, out := &in.Duration, &out.Duration - *out = new(string) - **out = **in - } + out.RedisCommonSpec = in.RedisCommonSpec } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodChaosSpec. -func (in *PodChaosSpec) DeepCopy() *PodChaosSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RedisSentinelRestartSpec. +func (in *RedisSentinelRestartSpec) DeepCopy() *RedisSentinelRestartSpec { if in == nil { return nil } - out := new(PodChaosSpec) + out := new(RedisSentinelRestartSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PodChaosStatus) DeepCopyInto(out *PodChaosStatus) { +func (in *RedisSentinelStopSpec) DeepCopyInto(out *RedisSentinelStopSpec) { *out = *in - in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) + out.RedisCommonSpec = in.RedisCommonSpec } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodChaosStatus. -func (in *PodChaosStatus) DeepCopy() *PodChaosStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RedisSentinelStopSpec. +func (in *RedisSentinelStopSpec) DeepCopy() *RedisSentinelStopSpec { if in == nil { return nil } - out := new(PodChaosStatus) + out := new(RedisSentinelStopSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PodIoChaos) DeepCopyInto(out *PodIoChaos) { +func (in *RemoteCluster) DeepCopyInto(out *RemoteCluster) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodIoChaos. -func (in *PodIoChaos) DeepCopy() *PodIoChaos { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteCluster. +func (in *RemoteCluster) DeepCopy() *RemoteCluster { if in == nil { return nil } - out := new(PodIoChaos) + out := new(RemoteCluster) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PodIoChaos) DeepCopyObject() runtime.Object { +func (in *RemoteCluster) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1624,31 +4080,62 @@ func (in *PodIoChaos) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PodIoChaosList) DeepCopyInto(out *PodIoChaosList) { +func (in *RemoteClusterCondition) DeepCopyInto(out *RemoteClusterCondition) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteClusterCondition. +func (in *RemoteClusterCondition) DeepCopy() *RemoteClusterCondition { + if in == nil { + return nil + } + out := new(RemoteClusterCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RemoteClusterKubeConfig) DeepCopyInto(out *RemoteClusterKubeConfig) { + *out = *in + out.SecretRef = in.SecretRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteClusterKubeConfig. +func (in *RemoteClusterKubeConfig) DeepCopy() *RemoteClusterKubeConfig { + if in == nil { + return nil + } + out := new(RemoteClusterKubeConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RemoteClusterList) DeepCopyInto(out *RemoteClusterList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]PodIoChaos, len(*in)) + *out = make([]RemoteCluster, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodIoChaosList. -func (in *PodIoChaosList) DeepCopy() *PodIoChaosList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteClusterList. +func (in *RemoteClusterList) DeepCopy() *RemoteClusterList { if in == nil { return nil } - out := new(PodIoChaosList) + out := new(RemoteClusterList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PodIoChaosList) DeepCopyObject() runtime.Object { +func (in *RemoteClusterList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1656,85 +4143,97 @@ func (in *PodIoChaosList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PodIoChaosSpec) DeepCopyInto(out *PodIoChaosSpec) { +func (in *RemoteClusterSecretRef) DeepCopyInto(out *RemoteClusterSecretRef) { *out = *in - if in.Container != nil { - in, out := &in.Container, &out.Container - *out = new(string) - **out = **in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteClusterSecretRef. +func (in *RemoteClusterSecretRef) DeepCopy() *RemoteClusterSecretRef { + if in == nil { + return nil } - if in.Actions != nil { - in, out := &in.Actions, &out.Actions - *out = make([]IoChaosAction, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } + out := new(RemoteClusterSecretRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RemoteClusterSpec) DeepCopyInto(out *RemoteClusterSpec) { + *out = *in + out.KubeConfig = in.KubeConfig + if in.ConfigOverride != nil { + in, out := &in.ConfigOverride, &out.ConfigOverride + *out = make(json.RawMessage, len(*in)) + copy(*out, *in) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodIoChaosSpec. -func (in *PodIoChaosSpec) DeepCopy() *PodIoChaosSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteClusterSpec. +func (in *RemoteClusterSpec) DeepCopy() *RemoteClusterSpec { if in == nil { return nil } - out := new(PodIoChaosSpec) + out := new(RemoteClusterSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PodNetworkChaos) DeepCopyInto(out *PodNetworkChaos) { +func (in *RemoteClusterStatus) DeepCopyInto(out *RemoteClusterStatus) { *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]RemoteClusterCondition, len(*in)) + copy(*out, *in) + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodNetworkChaos. -func (in *PodNetworkChaos) DeepCopy() *PodNetworkChaos { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteClusterStatus. +func (in *RemoteClusterStatus) DeepCopy() *RemoteClusterStatus { if in == nil { return nil } - out := new(PodNetworkChaos) + out := new(RemoteClusterStatus) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PodNetworkChaos) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReorderSpec) DeepCopyInto(out *ReorderSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReorderSpec. +func (in *ReorderSpec) DeepCopy() *ReorderSpec { + if in == nil { + return nil } - return nil + out := new(ReorderSpec) + in.DeepCopyInto(out) + return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PodNetworkChaosList) DeepCopyInto(out *PodNetworkChaosList) { +func (in *Schedule) DeepCopyInto(out *Schedule) { *out = *in out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]PodNetworkChaos, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodNetworkChaosList. -func (in *PodNetworkChaosList) DeepCopy() *PodNetworkChaosList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Schedule. +func (in *Schedule) DeepCopy() *Schedule { if in == nil { return nil } - out := new(PodNetworkChaosList) + out := new(Schedule) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PodNetworkChaosList) DeepCopyObject() runtime.Object { +func (in *Schedule) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1742,274 +4241,279 @@ func (in *PodNetworkChaosList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PodNetworkChaosSpec) DeepCopyInto(out *PodNetworkChaosSpec) { +func (in *ScheduleItem) DeepCopyInto(out *ScheduleItem) { *out = *in - if in.IPSets != nil { - in, out := &in.IPSets, &out.IPSets - *out = make([]RawIPSet, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Iptables != nil { - in, out := &in.Iptables, &out.Iptables - *out = make([]RawIptables, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.TrafficControls != nil { - in, out := &in.TrafficControls, &out.TrafficControls - *out = make([]RawTrafficControl, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } + in.EmbedChaos.DeepCopyInto(&out.EmbedChaos) + if in.Workflow != nil { + in, out := &in.Workflow, &out.Workflow + *out = new(WorkflowSpec) + (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodNetworkChaosSpec. -func (in *PodNetworkChaosSpec) DeepCopy() *PodNetworkChaosSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScheduleItem. +func (in *ScheduleItem) DeepCopy() *ScheduleItem { if in == nil { return nil } - out := new(PodNetworkChaosSpec) + out := new(ScheduleItem) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PodNetworkChaosStatus) DeepCopyInto(out *PodNetworkChaosStatus) { +func (in *ScheduleList) DeepCopyInto(out *ScheduleList) { *out = *in - in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Schedule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodNetworkChaosStatus. -func (in *PodNetworkChaosStatus) DeepCopy() *PodNetworkChaosStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScheduleList. +func (in *ScheduleList) DeepCopy() *ScheduleList { if in == nil { return nil } - out := new(PodNetworkChaosStatus) + out := new(ScheduleList) in.DeepCopyInto(out) return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PodStatus) DeepCopyInto(out *PodStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodStatus. -func (in *PodStatus) DeepCopy() *PodStatus { - if in == nil { - return nil +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ScheduleList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c } - out := new(PodStatus) - in.DeepCopyInto(out) - return out + return nil } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RawIPSet) DeepCopyInto(out *RawIPSet) { +func (in *ScheduleSpec) DeepCopyInto(out *ScheduleSpec) { *out = *in - if in.Cidrs != nil { - in, out := &in.Cidrs, &out.Cidrs - *out = make([]string, len(*in)) - copy(*out, *in) + if in.StartingDeadlineSeconds != nil { + in, out := &in.StartingDeadlineSeconds, &out.StartingDeadlineSeconds + *out = new(int64) + **out = **in } - out.RawRuleSource = in.RawRuleSource + in.ScheduleItem.DeepCopyInto(&out.ScheduleItem) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RawIPSet. -func (in *RawIPSet) DeepCopy() *RawIPSet { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScheduleSpec. +func (in *ScheduleSpec) DeepCopy() *ScheduleSpec { if in == nil { return nil } - out := new(RawIPSet) + out := new(ScheduleSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RawIptables) DeepCopyInto(out *RawIptables) { - *out = *in - if in.IPSets != nil { - in, out := &in.IPSets, &out.IPSets - *out = make([]string, len(*in)) +func (in *ScheduleStatus) DeepCopyInto(out *ScheduleStatus) { + *out = *in + if in.Active != nil { + in, out := &in.Active, &out.Active + *out = make([]v1.ObjectReference, len(*in)) copy(*out, *in) } - out.RawRuleSource = in.RawRuleSource + in.LastScheduleTime.DeepCopyInto(&out.LastScheduleTime) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RawIptables. -func (in *RawIptables) DeepCopy() *RawIptables { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScheduleStatus. +func (in *ScheduleStatus) DeepCopy() *ScheduleStatus { if in == nil { return nil } - out := new(RawIptables) + out := new(ScheduleStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RawRuleSource) DeepCopyInto(out *RawRuleSource) { +func (in *StatusCheck) DeepCopyInto(out *StatusCheck) { *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RawRuleSource. -func (in *RawRuleSource) DeepCopy() *RawRuleSource { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatusCheck. +func (in *StatusCheck) DeepCopy() *StatusCheck { if in == nil { return nil } - out := new(RawRuleSource) + out := new(StatusCheck) in.DeepCopyInto(out) return out } +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *StatusCheck) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RawTrafficControl) DeepCopyInto(out *RawTrafficControl) { +func (in *StatusCheckCondition) DeepCopyInto(out *StatusCheckCondition) { *out = *in - in.TcParameter.DeepCopyInto(&out.TcParameter) + if in.LastProbeTime != nil { + in, out := &in.LastProbeTime, &out.LastProbeTime + *out = (*in).DeepCopy() + } + if in.LastTransitionTime != nil { + in, out := &in.LastTransitionTime, &out.LastTransitionTime + *out = (*in).DeepCopy() + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RawTrafficControl. -func (in *RawTrafficControl) DeepCopy() *RawTrafficControl { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatusCheckCondition. +func (in *StatusCheckCondition) DeepCopy() *StatusCheckCondition { if in == nil { return nil } - out := new(RawTrafficControl) + out := new(StatusCheckCondition) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ReorderSpec) DeepCopyInto(out *ReorderSpec) { +func (in *StatusCheckList) DeepCopyInto(out *StatusCheckList) { *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]StatusCheck, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReorderSpec. -func (in *ReorderSpec) DeepCopy() *ReorderSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatusCheckList. +func (in *StatusCheckList) DeepCopy() *StatusCheckList { if in == nil { return nil } - out := new(ReorderSpec) + out := new(StatusCheckList) in.DeepCopyInto(out) return out } +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *StatusCheckList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ScheduleStatus) DeepCopyInto(out *ScheduleStatus) { +func (in *StatusCheckRecord) DeepCopyInto(out *StatusCheckRecord) { *out = *in - if in.NextStart != nil { - in, out := &in.NextStart, &out.NextStart - *out = (*in).DeepCopy() - } - if in.NextRecover != nil { - in, out := &in.NextRecover, &out.NextRecover + if in.StartTime != nil { + in, out := &in.StartTime, &out.StartTime *out = (*in).DeepCopy() } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScheduleStatus. -func (in *ScheduleStatus) DeepCopy() *ScheduleStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatusCheckRecord. +func (in *StatusCheckRecord) DeepCopy() *StatusCheckRecord { if in == nil { return nil } - out := new(ScheduleStatus) + out := new(StatusCheckRecord) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SchedulerSpec) DeepCopyInto(out *SchedulerSpec) { +func (in *StatusCheckSpec) DeepCopyInto(out *StatusCheckSpec) { *out = *in + if in.Duration != nil { + in, out := &in.Duration, &out.Duration + *out = new(string) + **out = **in + } + if in.EmbedStatusCheck != nil { + in, out := &in.EmbedStatusCheck, &out.EmbedStatusCheck + *out = new(EmbedStatusCheck) + (*in).DeepCopyInto(*out) + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SchedulerSpec. -func (in *SchedulerSpec) DeepCopy() *SchedulerSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatusCheckSpec. +func (in *StatusCheckSpec) DeepCopy() *StatusCheckSpec { if in == nil { return nil } - out := new(SchedulerSpec) + out := new(StatusCheckSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SelectorSpec) DeepCopyInto(out *SelectorSpec) { +func (in *StatusCheckStatus) DeepCopyInto(out *StatusCheckStatus) { *out = *in - if in.Namespaces != nil { - in, out := &in.Namespaces, &out.Namespaces - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Nodes != nil { - in, out := &in.Nodes, &out.Nodes - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Pods != nil { - in, out := &in.Pods, &out.Pods - *out = make(map[string][]string, len(*in)) - for key, val := range *in { - var outVal []string - if val == nil { - (*out)[key] = nil - } else { - in, out := &val, &outVal - *out = make([]string, len(*in)) - copy(*out, *in) - } - (*out)[key] = outVal - } - } - if in.NodeSelectors != nil { - in, out := &in.NodeSelectors, &out.NodeSelectors - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } + if in.StartTime != nil { + in, out := &in.StartTime, &out.StartTime + *out = (*in).DeepCopy() } - if in.FieldSelectors != nil { - in, out := &in.FieldSelectors, &out.FieldSelectors - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } + if in.CompletionTime != nil { + in, out := &in.CompletionTime, &out.CompletionTime + *out = (*in).DeepCopy() } - if in.LabelSelectors != nil { - in, out := &in.LabelSelectors, &out.LabelSelectors - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]StatusCheckCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.ExpressionSelectors != nil { - in, out := &in.ExpressionSelectors, &out.ExpressionSelectors - *out = make(LabelSelectorRequirements, len(*in)) + if in.Records != nil { + in, out := &in.Records, &out.Records + *out = make([]StatusCheckRecord, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.AnnotationSelectors != nil { - in, out := &in.AnnotationSelectors, &out.AnnotationSelectors - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatusCheckStatus. +func (in *StatusCheckStatus) DeepCopy() *StatusCheckStatus { + if in == nil { + return nil } - if in.PodPhaseSelectors != nil { - in, out := &in.PodPhaseSelectors, &out.PodPhaseSelectors + out := new(StatusCheckStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StressCPUSpec) DeepCopyInto(out *StressCPUSpec) { + *out = *in + if in.Options != nil { + in, out := &in.Options, &out.Options *out = make([]string, len(*in)) copy(*out, *in) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SelectorSpec. -func (in *SelectorSpec) DeepCopy() *SelectorSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StressCPUSpec. +func (in *StressCPUSpec) DeepCopy() *StressCPUSpec { if in == nil { return nil } - out := new(SelectorSpec) + out := new(StressCPUSpec) in.DeepCopyInto(out) return out } @@ -2076,27 +4580,17 @@ func (in *StressChaosList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *StressChaosSpec) DeepCopyInto(out *StressChaosSpec) { *out = *in - in.Selector.DeepCopyInto(&out.Selector) + in.ContainerSelector.DeepCopyInto(&out.ContainerSelector) if in.Stressors != nil { in, out := &in.Stressors, &out.Stressors *out = new(Stressors) (*in).DeepCopyInto(*out) } - if in.ContainerName != nil { - in, out := &in.ContainerName, &out.ContainerName - *out = new(string) - **out = **in - } if in.Duration != nil { in, out := &in.Duration, &out.Duration *out = new(string) **out = **in } - if in.Scheduler != nil { - in, out := &in.Scheduler, &out.Scheduler - *out = new(SchedulerSpec) - **out = **in - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StressChaosSpec. @@ -2139,6 +4633,10 @@ func (in *StressInstance) DeepCopyInto(out *StressInstance) { in, out := &in.StartTime, &out.StartTime *out = (*in).DeepCopy() } + if in.MemoryStartTime != nil { + in, out := &in.MemoryStartTime, &out.MemoryStartTime + *out = (*in).DeepCopy() + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StressInstance. @@ -2151,6 +4649,26 @@ func (in *StressInstance) DeepCopy() *StressInstance { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StressMemorySpec) DeepCopyInto(out *StressMemorySpec) { + *out = *in + if in.Options != nil { + in, out := &in.Options, &out.Options + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StressMemorySpec. +func (in *StressMemorySpec) DeepCopy() *StressMemorySpec { + if in == nil { + return nil + } + out := new(StressMemorySpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Stressor) DeepCopyInto(out *Stressor) { *out = *in @@ -2192,17 +4710,28 @@ func (in *Stressors) DeepCopy() *Stressors { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Target) DeepCopyInto(out *Target) { +func (in *Task) DeepCopyInto(out *Task) { *out = *in - in.TargetSelector.DeepCopyInto(&out.TargetSelector) + if in.Container != nil { + in, out := &in.Container, &out.Container + *out = new(v1.Container) + (*in).DeepCopyInto(*out) + } + if in.Volumes != nil { + in, out := &in.Volumes, &out.Volumes + *out = make([]v1.Volume, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Target. -func (in *Target) DeepCopy() *Target { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Task. +func (in *Task) DeepCopy() *Task { if in == nil { return nil } - out := new(Target) + out := new(Task) in.DeepCopyInto(out) return out } @@ -2235,6 +4764,11 @@ func (in *TcParameter) DeepCopyInto(out *TcParameter) { *out = new(BandwidthSpec) (*in).DeepCopyInto(*out) } + if in.Rate != nil { + in, out := &in.Rate, &out.Rate + *out = new(RateSpec) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcParameter. @@ -2250,21 +4784,41 @@ func (in *TcParameter) DeepCopy() *TcParameter { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Template) DeepCopyInto(out *Template) { *out = *in - if in.Duration != nil { - in, out := &in.Duration, &out.Duration + if in.Deadline != nil { + in, out := &in.Deadline, &out.Deadline *out = new(string) **out = **in } - if in.Tasks != nil { - in, out := &in.Tasks, &out.Tasks + if in.Task != nil { + in, out := &in.Task, &out.Task + *out = new(Task) + (*in).DeepCopyInto(*out) + } + if in.Children != nil { + in, out := &in.Children, &out.Children *out = make([]string, len(*in)) copy(*out, *in) } + if in.ConditionalBranches != nil { + in, out := &in.ConditionalBranches, &out.ConditionalBranches + *out = make([]ConditionalBranch, len(*in)) + copy(*out, *in) + } if in.EmbedChaos != nil { in, out := &in.EmbedChaos, &out.EmbedChaos *out = new(EmbedChaos) (*in).DeepCopyInto(*out) } + if in.Schedule != nil { + in, out := &in.Schedule, &out.Schedule + *out = new(ChaosOnlyScheduleSpec) + (*in).DeepCopyInto(*out) + } + if in.StatusCheck != nil { + in, out := &in.StatusCheck, &out.StatusCheck + *out = new(StatusCheckSpec) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Template. @@ -2339,27 +4893,17 @@ func (in *TimeChaosList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TimeChaosSpec) DeepCopyInto(out *TimeChaosSpec) { *out = *in - in.Selector.DeepCopyInto(&out.Selector) + in.ContainerSelector.DeepCopyInto(&out.ContainerSelector) if in.ClockIds != nil { in, out := &in.ClockIds, &out.ClockIds *out = make([]string, len(*in)) copy(*out, *in) } - if in.ContainerNames != nil { - in, out := &in.ContainerNames, &out.ContainerNames - *out = make([]string, len(*in)) - copy(*out, *in) - } if in.Duration != nil { in, out := &in.Duration, &out.Duration *out = new(string) **out = **in } - if in.Scheduler != nil { - in, out := &in.Scheduler, &out.Scheduler - *out = new(SchedulerSpec) - **out = **in - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TimeChaosSpec. @@ -2403,6 +4947,36 @@ func (in *Timespec) DeepCopy() *Timespec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UserDefinedSpec) DeepCopyInto(out *UserDefinedSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserDefinedSpec. +func (in *UserDefinedSpec) DeepCopy() *UserDefinedSpec { + if in == nil { + return nil + } + out := new(UserDefinedSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VMSpec) DeepCopyInto(out *VMSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VMSpec. +func (in *VMSpec) DeepCopy() *VMSpec { + if in == nil { + return nil + } + out := new(VMSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Workflow) DeepCopyInto(out *Workflow) { *out = *in @@ -2430,6 +5004,25 @@ func (in *Workflow) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkflowCondition) DeepCopyInto(out *WorkflowCondition) { + *out = *in + if in.StartTime != nil { + in, out := &in.StartTime, &out.StartTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowCondition. +func (in *WorkflowCondition) DeepCopy() *WorkflowCondition { + if in == nil { + return nil + } + out := new(WorkflowCondition) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WorkflowList) DeepCopyInto(out *WorkflowList) { *out = *in @@ -2547,16 +5140,36 @@ func (in *WorkflowNodeSpec) DeepCopyInto(out *WorkflowNodeSpec) { in, out := &in.Deadline, &out.Deadline *out = (*in).DeepCopy() } - if in.Tasks != nil { - in, out := &in.Tasks, &out.Tasks + if in.Task != nil { + in, out := &in.Task, &out.Task + *out = new(Task) + (*in).DeepCopyInto(*out) + } + if in.Children != nil { + in, out := &in.Children, &out.Children *out = make([]string, len(*in)) copy(*out, *in) } + if in.ConditionalBranches != nil { + in, out := &in.ConditionalBranches, &out.ConditionalBranches + *out = make([]ConditionalBranch, len(*in)) + copy(*out, *in) + } if in.EmbedChaos != nil { in, out := &in.EmbedChaos, &out.EmbedChaos *out = new(EmbedChaos) (*in).DeepCopyInto(*out) } + if in.Schedule != nil { + in, out := &in.Schedule, &out.Schedule + *out = new(ScheduleSpec) + (*in).DeepCopyInto(*out) + } + if in.StatusCheck != nil { + in, out := &in.StatusCheck, &out.StatusCheck + *out = new(StatusCheckSpec) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowNodeSpec. @@ -2572,16 +5185,16 @@ func (in *WorkflowNodeSpec) DeepCopy() *WorkflowNodeSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WorkflowNodeStatus) DeepCopyInto(out *WorkflowNodeStatus) { *out = *in - if in.ExpectedChildrenNum != nil { - in, out := &in.ExpectedChildrenNum, &out.ExpectedChildrenNum - *out = new(int) - **out = **in - } if in.ChaosResource != nil { in, out := &in.ChaosResource, &out.ChaosResource *out = new(v1.TypedLocalObjectReference) (*in).DeepCopyInto(*out) } + if in.ConditionalBranchesStatus != nil { + in, out := &in.ConditionalBranchesStatus, &out.ConditionalBranchesStatus + *out = new(ConditionalBranchesStatus) + (*in).DeepCopyInto(*out) + } if in.ActiveChildren != nil { in, out := &in.ActiveChildren, &out.ActiveChildren *out = make([]v1.LocalObjectReference, len(*in)) @@ -2639,6 +5252,21 @@ func (in *WorkflowStatus) DeepCopyInto(out *WorkflowStatus) { *out = new(string) **out = **in } + if in.StartTime != nil { + in, out := &in.StartTime, &out.StartTime + *out = (*in).DeepCopy() + } + if in.EndTime != nil { + in, out := &in.EndTime, &out.EndTime + *out = (*in).DeepCopy() + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]WorkflowCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowStatus. diff --git a/api/v1alpha1/zz_generated.schedule.chaosmesh.go b/api/v1alpha1/zz_generated.schedule.chaosmesh.go new file mode 100644 index 0000000000..e8ab865c4d --- /dev/null +++ b/api/v1alpha1/zz_generated.schedule.chaosmesh.go @@ -0,0 +1,183 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Code generated by chaos-builder. DO NOT EDIT. + +package v1alpha1 + + +import ( + "github.com/pkg/errors" +) + + +const ( + ScheduleTypeAWSChaos ScheduleTemplateType = "AWSChaos" + ScheduleTypeAzureChaos ScheduleTemplateType = "AzureChaos" + ScheduleTypeBlockChaos ScheduleTemplateType = "BlockChaos" + ScheduleTypeDNSChaos ScheduleTemplateType = "DNSChaos" + ScheduleTypeGCPChaos ScheduleTemplateType = "GCPChaos" + ScheduleTypeHTTPChaos ScheduleTemplateType = "HTTPChaos" + ScheduleTypeIOChaos ScheduleTemplateType = "IOChaos" + ScheduleTypeJVMChaos ScheduleTemplateType = "JVMChaos" + ScheduleTypeKernelChaos ScheduleTemplateType = "KernelChaos" + ScheduleTypeNetworkChaos ScheduleTemplateType = "NetworkChaos" + ScheduleTypePhysicalMachineChaos ScheduleTemplateType = "PhysicalMachineChaos" + ScheduleTypePodChaos ScheduleTemplateType = "PodChaos" + ScheduleTypeStressChaos ScheduleTemplateType = "StressChaos" + ScheduleTypeTimeChaos ScheduleTemplateType = "TimeChaos" + ScheduleTypeWorkflow ScheduleTemplateType = "Workflow" + +) + +var allScheduleTemplateType = []ScheduleTemplateType{ + ScheduleTypeAWSChaos, + ScheduleTypeAzureChaos, + ScheduleTypeBlockChaos, + ScheduleTypeDNSChaos, + ScheduleTypeGCPChaos, + ScheduleTypeHTTPChaos, + ScheduleTypeIOChaos, + ScheduleTypeJVMChaos, + ScheduleTypeKernelChaos, + ScheduleTypeNetworkChaos, + ScheduleTypePhysicalMachineChaos, + ScheduleTypePodChaos, + ScheduleTypeStressChaos, + ScheduleTypeTimeChaos, + ScheduleTypeWorkflow, + +} + +func (it *ScheduleItem) SpawnNewObject(templateType ScheduleTemplateType) (GenericChaos, error) { + switch templateType { + case ScheduleTypeAWSChaos: + result := AWSChaos{} + result.Spec = *it.AWSChaos + return &result, nil + case ScheduleTypeAzureChaos: + result := AzureChaos{} + result.Spec = *it.AzureChaos + return &result, nil + case ScheduleTypeBlockChaos: + result := BlockChaos{} + result.Spec = *it.BlockChaos + return &result, nil + case ScheduleTypeDNSChaos: + result := DNSChaos{} + result.Spec = *it.DNSChaos + return &result, nil + case ScheduleTypeGCPChaos: + result := GCPChaos{} + result.Spec = *it.GCPChaos + return &result, nil + case ScheduleTypeHTTPChaos: + result := HTTPChaos{} + result.Spec = *it.HTTPChaos + return &result, nil + case ScheduleTypeIOChaos: + result := IOChaos{} + result.Spec = *it.IOChaos + return &result, nil + case ScheduleTypeJVMChaos: + result := JVMChaos{} + result.Spec = *it.JVMChaos + return &result, nil + case ScheduleTypeKernelChaos: + result := KernelChaos{} + result.Spec = *it.KernelChaos + return &result, nil + case ScheduleTypeNetworkChaos: + result := NetworkChaos{} + result.Spec = *it.NetworkChaos + return &result, nil + case ScheduleTypePhysicalMachineChaos: + result := PhysicalMachineChaos{} + result.Spec = *it.PhysicalMachineChaos + return &result, nil + case ScheduleTypePodChaos: + result := PodChaos{} + result.Spec = *it.PodChaos + return &result, nil + case ScheduleTypeStressChaos: + result := StressChaos{} + result.Spec = *it.StressChaos + return &result, nil + case ScheduleTypeTimeChaos: + result := TimeChaos{} + result.Spec = *it.TimeChaos + return &result, nil + case ScheduleTypeWorkflow: + result := Workflow{} + result.Spec = *it.Workflow + return &result, nil + + default: + return nil, errors.Wrapf(errInvalidValue, "unknown template type %s", templateType) + } +} + +func (it *ScheduleItem) RestoreChaosSpec(root interface{}) error { + switch chaos := root.(type) { + case *AWSChaos: + *it.AWSChaos = chaos.Spec + return nil + case *AzureChaos: + *it.AzureChaos = chaos.Spec + return nil + case *BlockChaos: + *it.BlockChaos = chaos.Spec + return nil + case *DNSChaos: + *it.DNSChaos = chaos.Spec + return nil + case *GCPChaos: + *it.GCPChaos = chaos.Spec + return nil + case *HTTPChaos: + *it.HTTPChaos = chaos.Spec + return nil + case *IOChaos: + *it.IOChaos = chaos.Spec + return nil + case *JVMChaos: + *it.JVMChaos = chaos.Spec + return nil + case *KernelChaos: + *it.KernelChaos = chaos.Spec + return nil + case *NetworkChaos: + *it.NetworkChaos = chaos.Spec + return nil + case *PhysicalMachineChaos: + *it.PhysicalMachineChaos = chaos.Spec + return nil + case *PodChaos: + *it.PodChaos = chaos.Spec + return nil + case *StressChaos: + *it.StressChaos = chaos.Spec + return nil + case *TimeChaos: + *it.TimeChaos = chaos.Spec + return nil + case *Workflow: + *it.Workflow = chaos.Spec + return nil + + default: + return errors.Wrapf(errInvalidValue, "unknown chaos %#v", root) + } +} diff --git a/api/v1alpha1/zz_generated.workflow.chaosmesh.go b/api/v1alpha1/zz_generated.workflow.chaosmesh.go index 3ad11b4248..f9525bdeeb 100644 --- a/api/v1alpha1/zz_generated.workflow.chaosmesh.go +++ b/api/v1alpha1/zz_generated.workflow.chaosmesh.go @@ -1,35 +1,40 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// + +// Code generated by chaos-builder. DO NOT EDIT. package v1alpha1 import ( - "fmt" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" + "github.com/pkg/errors" ) const ( - TypeAwsChaos TemplateType = "AwsChaos" + TypeAWSChaos TemplateType = "AWSChaos" + TypeAzureChaos TemplateType = "AzureChaos" + TypeBlockChaos TemplateType = "BlockChaos" TypeDNSChaos TemplateType = "DNSChaos" - TypeGcpChaos TemplateType = "GcpChaos" + TypeGCPChaos TemplateType = "GCPChaos" TypeHTTPChaos TemplateType = "HTTPChaos" - TypeIoChaos TemplateType = "IoChaos" + TypeIOChaos TemplateType = "IOChaos" TypeJVMChaos TemplateType = "JVMChaos" TypeKernelChaos TemplateType = "KernelChaos" TypeNetworkChaos TemplateType = "NetworkChaos" + TypePhysicalMachineChaos TemplateType = "PhysicalMachineChaos" TypePodChaos TemplateType = "PodChaos" TypeStressChaos TemplateType = "StressChaos" TypeTimeChaos TemplateType = "TimeChaos" @@ -37,14 +42,18 @@ const ( ) var allChaosTemplateType = []TemplateType{ - TypeAwsChaos, + TypeSchedule, + TypeAWSChaos, + TypeAzureChaos, + TypeBlockChaos, TypeDNSChaos, - TypeGcpChaos, + TypeGCPChaos, TypeHTTPChaos, - TypeIoChaos, + TypeIOChaos, TypeJVMChaos, TypeKernelChaos, TypeNetworkChaos, + TypePhysicalMachineChaos, TypePodChaos, TypeStressChaos, TypeTimeChaos, @@ -53,81 +62,310 @@ var allChaosTemplateType = []TemplateType{ type EmbedChaos struct { // +optional - AwsChaos *AwsChaosSpec `json:"aws_chaos,omitempty"` + AWSChaos *AWSChaosSpec `json:"awsChaos,omitempty"` + // +optional + AzureChaos *AzureChaosSpec `json:"azureChaos,omitempty"` + // +optional + BlockChaos *BlockChaosSpec `json:"blockChaos,omitempty"` // +optional - DNSChaos *DNSChaosSpec `json:"dns_chaos,omitempty"` + DNSChaos *DNSChaosSpec `json:"dnsChaos,omitempty"` // +optional - GcpChaos *GcpChaosSpec `json:"gcp_chaos,omitempty"` + GCPChaos *GCPChaosSpec `json:"gcpChaos,omitempty"` // +optional - HTTPChaos *HTTPChaosSpec `json:"http_chaos,omitempty"` + HTTPChaos *HTTPChaosSpec `json:"httpChaos,omitempty"` // +optional - IoChaos *IoChaosSpec `json:"io_chaos,omitempty"` + IOChaos *IOChaosSpec `json:"ioChaos,omitempty"` // +optional - JVMChaos *JVMChaosSpec `json:"jvm_chaos,omitempty"` + JVMChaos *JVMChaosSpec `json:"jvmChaos,omitempty"` // +optional - KernelChaos *KernelChaosSpec `json:"kernel_chaos,omitempty"` + KernelChaos *KernelChaosSpec `json:"kernelChaos,omitempty"` // +optional - NetworkChaos *NetworkChaosSpec `json:"network_chaos,omitempty"` + NetworkChaos *NetworkChaosSpec `json:"networkChaos,omitempty"` // +optional - PodChaos *PodChaosSpec `json:"pod_chaos,omitempty"` + PhysicalMachineChaos *PhysicalMachineChaosSpec `json:"physicalmachineChaos,omitempty"` // +optional - StressChaos *StressChaosSpec `json:"stress_chaos,omitempty"` + PodChaos *PodChaosSpec `json:"podChaos,omitempty"` // +optional - TimeChaos *TimeChaosSpec `json:"time_chaos,omitempty"` + StressChaos *StressChaosSpec `json:"stressChaos,omitempty"` + // +optional + TimeChaos *TimeChaosSpec `json:"timeChaos,omitempty"` } -func (it *EmbedChaos) SpawnNewObject(templateType TemplateType) (runtime.Object, metav1.Object, error) { - +func (it *EmbedChaos) SpawnNewObject(templateType TemplateType) (GenericChaos, error) { switch templateType { - case TypeAwsChaos: - result := AwsChaos{} - result.Spec = *it.AwsChaos - return &result, result.GetObjectMeta(), nil + case TypeAWSChaos: + result := AWSChaos{} + result.Spec = *it.AWSChaos + return &result, nil + case TypeAzureChaos: + result := AzureChaos{} + result.Spec = *it.AzureChaos + return &result, nil + case TypeBlockChaos: + result := BlockChaos{} + result.Spec = *it.BlockChaos + return &result, nil case TypeDNSChaos: result := DNSChaos{} result.Spec = *it.DNSChaos - return &result, result.GetObjectMeta(), nil - case TypeGcpChaos: - result := GcpChaos{} - result.Spec = *it.GcpChaos - return &result, result.GetObjectMeta(), nil + return &result, nil + case TypeGCPChaos: + result := GCPChaos{} + result.Spec = *it.GCPChaos + return &result, nil case TypeHTTPChaos: result := HTTPChaos{} result.Spec = *it.HTTPChaos - return &result, result.GetObjectMeta(), nil - case TypeIoChaos: - result := IoChaos{} - result.Spec = *it.IoChaos - return &result, result.GetObjectMeta(), nil + return &result, nil + case TypeIOChaos: + result := IOChaos{} + result.Spec = *it.IOChaos + return &result, nil case TypeJVMChaos: result := JVMChaos{} result.Spec = *it.JVMChaos - return &result, result.GetObjectMeta(), nil + return &result, nil case TypeKernelChaos: result := KernelChaos{} result.Spec = *it.KernelChaos - return &result, result.GetObjectMeta(), nil + return &result, nil case TypeNetworkChaos: result := NetworkChaos{} result.Spec = *it.NetworkChaos - return &result, result.GetObjectMeta(), nil + return &result, nil + case TypePhysicalMachineChaos: + result := PhysicalMachineChaos{} + result.Spec = *it.PhysicalMachineChaos + return &result, nil case TypePodChaos: result := PodChaos{} result.Spec = *it.PodChaos - return &result, result.GetObjectMeta(), nil + return &result, nil case TypeStressChaos: result := StressChaos{} result.Spec = *it.StressChaos - return &result, result.GetObjectMeta(), nil + return &result, nil case TypeTimeChaos: result := TimeChaos{} result.Spec = *it.TimeChaos - return &result, result.GetObjectMeta(), nil + return &result, nil + + default: + return nil, errors.Wrapf(errInvalidValue, "unknown template type %s", templateType) + } +} + +func (it *EmbedChaos) RestoreChaosSpec(root interface{}) error { + switch chaos := root.(type) { + case *AWSChaos: + *it.AWSChaos = chaos.Spec + return nil + case *AzureChaos: + *it.AzureChaos = chaos.Spec + return nil + case *BlockChaos: + *it.BlockChaos = chaos.Spec + return nil + case *DNSChaos: + *it.DNSChaos = chaos.Spec + return nil + case *GCPChaos: + *it.GCPChaos = chaos.Spec + return nil + case *HTTPChaos: + *it.HTTPChaos = chaos.Spec + return nil + case *IOChaos: + *it.IOChaos = chaos.Spec + return nil + case *JVMChaos: + *it.JVMChaos = chaos.Spec + return nil + case *KernelChaos: + *it.KernelChaos = chaos.Spec + return nil + case *NetworkChaos: + *it.NetworkChaos = chaos.Spec + return nil + case *PhysicalMachineChaos: + *it.PhysicalMachineChaos = chaos.Spec + return nil + case *PodChaos: + *it.PodChaos = chaos.Spec + return nil + case *StressChaos: + *it.StressChaos = chaos.Spec + return nil + case *TimeChaos: + *it.TimeChaos = chaos.Spec + return nil default: - return nil, nil, fmt.Errorf("unsupported template type %s", templateType) + return errors.Wrapf(errInvalidValue, "unknown chaos %#v", root) } +} - return nil, &metav1.ObjectMeta{}, nil +func (it *EmbedChaos) SpawnNewList(templateType TemplateType) (GenericChaosList, error) { + switch templateType { + case TypeAWSChaos: + result := AWSChaosList{} + return &result, nil + case TypeAzureChaos: + result := AzureChaosList{} + return &result, nil + case TypeBlockChaos: + result := BlockChaosList{} + return &result, nil + case TypeDNSChaos: + result := DNSChaosList{} + return &result, nil + case TypeGCPChaos: + result := GCPChaosList{} + return &result, nil + case TypeHTTPChaos: + result := HTTPChaosList{} + return &result, nil + case TypeIOChaos: + result := IOChaosList{} + return &result, nil + case TypeJVMChaos: + result := JVMChaosList{} + return &result, nil + case TypeKernelChaos: + result := KernelChaosList{} + return &result, nil + case TypeNetworkChaos: + result := NetworkChaosList{} + return &result, nil + case TypePhysicalMachineChaos: + result := PhysicalMachineChaosList{} + return &result, nil + case TypePodChaos: + result := PodChaosList{} + return &result, nil + case TypeStressChaos: + result := StressChaosList{} + return &result, nil + case TypeTimeChaos: + result := TimeChaosList{} + return &result, nil + + default: + return nil, errors.Wrapf(errInvalidValue, "unknown template type %s", templateType) + } +} + +func (in *AWSChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result } +func (in *AzureChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} +func (in *BlockChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} +func (in *DNSChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} +func (in *GCPChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} +func (in *HTTPChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} +func (in *IOChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} +func (in *JVMChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} +func (in *KernelChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} +func (in *NetworkChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} +func (in *PhysicalMachineChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} +func (in *PodChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} +func (in *StressChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} +func (in *TimeChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} + diff --git a/api/v1alpha1/zz_generated.workflow.chaosmesh_test.go b/api/v1alpha1/zz_generated.workflow.chaosmesh_test.go index cea2af79a6..b2cc8f488a 100644 --- a/api/v1alpha1/zz_generated.workflow.chaosmesh_test.go +++ b/api/v1alpha1/zz_generated.workflow.chaosmesh_test.go @@ -1,15 +1,19 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// + +// Code generated by chaos-builder. DO NOT EDIT. package v1alpha1 @@ -19,10 +23,26 @@ import ( "testing" ) -func TestChaosKindMapShouldContainsAwsChaos(t *testing.T) { +func TestChaosKindMapShouldContainsAWSChaos(t *testing.T) { + g := NewGomegaWithT(t) + var requiredType TemplateType + requiredType = TypeAWSChaos + + _, ok := all.kinds[string(requiredType)] + g.Expect(ok).To(Equal(true), "all kinds map should contains this type", requiredType) +} +func TestChaosKindMapShouldContainsAzureChaos(t *testing.T) { + g := NewGomegaWithT(t) + var requiredType TemplateType + requiredType = TypeAzureChaos + + _, ok := all.kinds[string(requiredType)] + g.Expect(ok).To(Equal(true), "all kinds map should contains this type", requiredType) +} +func TestChaosKindMapShouldContainsBlockChaos(t *testing.T) { g := NewGomegaWithT(t) var requiredType TemplateType - requiredType = TypeAwsChaos + requiredType = TypeBlockChaos _, ok := all.kinds[string(requiredType)] g.Expect(ok).To(Equal(true), "all kinds map should contains this type", requiredType) @@ -35,10 +55,10 @@ func TestChaosKindMapShouldContainsDNSChaos(t *testing.T) { _, ok := all.kinds[string(requiredType)] g.Expect(ok).To(Equal(true), "all kinds map should contains this type", requiredType) } -func TestChaosKindMapShouldContainsGcpChaos(t *testing.T) { +func TestChaosKindMapShouldContainsGCPChaos(t *testing.T) { g := NewGomegaWithT(t) var requiredType TemplateType - requiredType = TypeGcpChaos + requiredType = TypeGCPChaos _, ok := all.kinds[string(requiredType)] g.Expect(ok).To(Equal(true), "all kinds map should contains this type", requiredType) @@ -51,10 +71,10 @@ func TestChaosKindMapShouldContainsHTTPChaos(t *testing.T) { _, ok := all.kinds[string(requiredType)] g.Expect(ok).To(Equal(true), "all kinds map should contains this type", requiredType) } -func TestChaosKindMapShouldContainsIoChaos(t *testing.T) { +func TestChaosKindMapShouldContainsIOChaos(t *testing.T) { g := NewGomegaWithT(t) var requiredType TemplateType - requiredType = TypeIoChaos + requiredType = TypeIOChaos _, ok := all.kinds[string(requiredType)] g.Expect(ok).To(Equal(true), "all kinds map should contains this type", requiredType) @@ -83,6 +103,14 @@ func TestChaosKindMapShouldContainsNetworkChaos(t *testing.T) { _, ok := all.kinds[string(requiredType)] g.Expect(ok).To(Equal(true), "all kinds map should contains this type", requiredType) } +func TestChaosKindMapShouldContainsPhysicalMachineChaos(t *testing.T) { + g := NewGomegaWithT(t) + var requiredType TemplateType + requiredType = TypePhysicalMachineChaos + + _, ok := all.kinds[string(requiredType)] + g.Expect(ok).To(Equal(true), "all kinds map should contains this type", requiredType) +} func TestChaosKindMapShouldContainsPodChaos(t *testing.T) { g := NewGomegaWithT(t) var requiredType TemplateType diff --git a/api/webhook/inject.go b/api/webhook/inject.go deleted file mode 100644 index b4028751f9..0000000000 --- a/api/webhook/inject.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package webhook - -import ( - "context" - "net/http" - - "github.com/chaos-mesh/chaos-mesh/controllers/metrics" - controllerCfg "github.com/chaos-mesh/chaos-mesh/pkg/config" - "github.com/chaos-mesh/chaos-mesh/pkg/webhook/config" - "github.com/chaos-mesh/chaos-mesh/pkg/webhook/inject" - - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - - v1 "k8s.io/api/core/v1" -) - -var log = ctrl.Log.WithName("inject-webhook") - -// +kubebuilder:webhook:path=/inject-v1-pod,mutating=false,failurePolicy=fail,groups="",resources=pods,verbs=create;update,versions=v1,name=vpod.kb.io - -// PodInjector is pod template config injector -type PodInjector struct { - client client.Client - decoder *admission.Decoder - Config *config.Config - ControllerCfg *controllerCfg.ChaosControllerConfig - Metrics *metrics.ChaosCollector -} - -// Handle is pod injector handler -func (v *PodInjector) Handle(ctx context.Context, req admission.Request) admission.Response { - pod := &v1.Pod{} - - err := v.decoder.Decode(req, pod) - if err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - log.Info("Get request from pod:", "pod", pod) - - return admission.Response{ - AdmissionResponse: *inject.Inject(&req.AdmissionRequest, v.client, v.Config, v.ControllerCfg, v.Metrics), - } -} - -// InjectClient is pod injector client -func (v *PodInjector) InjectClient(c client.Client) error { - v.client = c - return nil -} - -// InjectDecoder is pod injector decoder -func (v *PodInjector) InjectDecoder(d *admission.Decoder) error { - v.decoder = d - return nil -} diff --git a/api/webhook/validate_auth.go b/api/webhook/validate_auth.go deleted file mode 100644 index c47d44a12b..0000000000 --- a/api/webhook/validate_auth.go +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package webhook - -import ( - "context" - "fmt" - "net/http" - "strings" - - authv1 "k8s.io/api/authorization/v1" - authorizationv1 "k8s.io/client-go/kubernetes/typed/authorization/v1" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -var alwaysAllowedKind = []string{ - v1alpha1.KindAwsChaos, - v1alpha1.KindPodNetworkChaos, - v1alpha1.KindPodIoChaos, - v1alpha1.KindGcpChaos, - "Workflow", - "WorkflowNode", -} - -var authLog = ctrl.Log.WithName("validate-auth") - -// +kubebuilder:webhook:path=/validate-auth,mutating=false,failurePolicy=fail,groups=chaos-mesh.org,resources=*,verbs=create;update,versions=v1alpha1,name=vauth.kb.io - -// AuthValidator validates the authority -type AuthValidator struct { - enabled bool - client client.Client - reader client.Reader - authCli *authorizationv1.AuthorizationV1Client - - decoder *admission.Decoder - - clusterScoped bool - targetNamespace string - enableFilterNamespace bool -} - -// NewAuthValidator returns a new AuthValidator -func NewAuthValidator(enabled bool, client client.Client, reader client.Reader, authCli *authorizationv1.AuthorizationV1Client, - clusterScoped bool, targetNamespace string, enableFilterNamespace bool) *AuthValidator { - return &AuthValidator{ - enabled: enabled, - client: client, - reader: reader, - authCli: authCli, - clusterScoped: clusterScoped, - targetNamespace: targetNamespace, - enableFilterNamespace: enableFilterNamespace, - } -} - -// AuthValidator admits a pod iff a specific annotation exists. -func (v *AuthValidator) Handle(ctx context.Context, req admission.Request) admission.Response { - if !v.enabled { - return admission.Allowed("") - } - - username := req.UserInfo.Username - groups := req.UserInfo.Groups - requestKind := req.Kind.Kind - - if contains(alwaysAllowedKind, requestKind) { - return admission.Allowed(fmt.Sprintf("skip the RBAC check for type %s", requestKind)) - } - - chaos := v1alpha1.GetChaosValidator(requestKind) - if chaos == nil { - err := fmt.Errorf("kind %s is not support", requestKind) - return admission.Errored(http.StatusBadRequest, err) - } - - err := v.decoder.Decode(req, chaos) - if err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - specs := chaos.GetSelectSpec() - - requireClusterPrivileges := false - affectedNamespaces := make(map[string]struct{}) - - for _, spec := range specs { - if spec.GetSelector().ClusterScoped() { - requireClusterPrivileges = true - } - - for _, namespace := range spec.GetSelector().AffectedNamespaces() { - affectedNamespaces[namespace] = struct{}{} - } - } - - if requireClusterPrivileges { - allow, err := v.auth(username, groups, "", requestKind) - if err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - if !allow { - return admission.Denied(fmt.Sprintf("%s is forbidden on cluster", username)) - } - authLog.Info("user have the privileges on cluster, auth validate passed", "user", username, "groups", groups, "namespace", affectedNamespaces) - } else { - for namespace := range affectedNamespaces { - allow, err := v.auth(username, groups, namespace, requestKind) - if err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - if !allow { - return admission.Denied(fmt.Sprintf("%s is forbidden on namespace %s", username, namespace)) - } - } - - authLog.Info("user have the privileges on namespace, auth validate passed", "user", username, "groups", groups, "namespace", affectedNamespaces) - } - - return admission.Allowed("") -} - -// AuthValidator implements admission.DecoderInjector. -// A decoder will be automatically injected. - -// InjectDecoder injects the decoder. -func (v *AuthValidator) InjectDecoder(d *admission.Decoder) error { - v.decoder = d - return nil -} - -func (v *AuthValidator) auth(username string, groups []string, namespace string, chaosKind string) (bool, error) { - resourceName, err := v.resourceFor(chaosKind) - if err != nil { - return false, err - } - sar := authv1.SubjectAccessReview{ - Spec: authv1.SubjectAccessReviewSpec{ - ResourceAttributes: &authv1.ResourceAttributes{ - Namespace: namespace, - Verb: "create", - Group: "chaos-mesh.org", - Resource: resourceName, - }, - User: username, - Groups: groups, - }, - } - - response, err := v.authCli.SubjectAccessReviews().Create(&sar) - if err != nil { - return false, err - } - - return response.Status.Allowed, nil -} - -func (v *AuthValidator) resourceFor(name string) (string, error) { - // TODO: we should use RESTMapper, but it relates to many dependencies - return strings.ToLower(name), nil -} - -func contains(arr []string, target string) bool { - for _, item := range arr { - if item == target { - return true - } - } - return false -} diff --git a/binary.generated.mk b/binary.generated.mk new file mode 100644 index 0000000000..cd2e98217a --- /dev/null +++ b/binary.generated.mk @@ -0,0 +1,30 @@ +# Generated by ./cmd/generate-makefile. DO NOT EDIT. + +##@ Generated targets in binary.generated.mk + +.PHONY: images/chaos-mesh/bin/chaos-controller-manager +images/chaos-mesh/bin/chaos-controller-manager: SHELL:=$(RUN_IN_BUILD_SHELL) +images/chaos-mesh/bin/chaos-controller-manager: image-build-env ## Build binary chaos-controller-manager + $(GO) build -ldflags "$(LDFLAGS)" -tags "${BUILD_TAGS}" -o images/chaos-mesh/bin/chaos-controller-manager cmd/chaos-controller-manager/main.go + +.PHONY: images/chaos-daemon/bin/chaos-daemon +images/chaos-daemon/bin/chaos-daemon: SHELL:=$(RUN_IN_BUILD_SHELL) +images/chaos-daemon/bin/chaos-daemon: image-build-env pkg/time/fakeclock/fake_clock_gettime.o pkg/time/fakeclock/fake_gettimeofday.o ## Build binary chaos-daemon + $(CGO) build -ldflags "$(LDFLAGS)" -tags "${BUILD_TAGS}" -o images/chaos-daemon/bin/chaos-daemon cmd/chaos-daemon/main.go + +.PHONY: images/chaos-dashboard/bin/chaos-dashboard +images/chaos-dashboard/bin/chaos-dashboard: SHELL:=$(RUN_IN_BUILD_SHELL) +images/chaos-dashboard/bin/chaos-dashboard: image-build-env ui ## Build binary chaos-dashboard + $(CGO) build -ldflags "$(LDFLAGS)" -tags "${BUILD_TAGS}" -o images/chaos-dashboard/bin/chaos-dashboard cmd/chaos-dashboard/main.go + +.PHONY: images/chaos-daemon/bin/cdh +images/chaos-daemon/bin/cdh: SHELL:=$(RUN_IN_BUILD_SHELL) +images/chaos-daemon/bin/cdh: image-build-env ## Build binary chaos-daemon-helper + $(CGO) build -ldflags "$(LDFLAGS)" -tags "${BUILD_TAGS}" -o images/chaos-daemon/bin/cdh cmd/chaos-daemon-helper/main.go + +.PHONY: clean-binary +clean-binary: + rm -f images/chaos-mesh/bin/chaos-controller-manager + rm -f images/chaos-daemon/bin/chaos-daemon + rm -f images/chaos-dashboard/bin/chaos-dashboard + rm -f images/chaos-daemon/bin/cdh diff --git a/build/build_image.py b/build/build_image.py new file mode 100755 index 0000000000..dc00f38399 --- /dev/null +++ b/build/build_image.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +""" +build an image in the given path with the given name and environment +configuration +""" + +import os +import argparse +import subprocess +import pathlib + +import utils +import common + + +def get_image_env(name, env): + """ + get environment variable related with an image according to the priority: + 1. IMAGE__ + 2. IMAGE_ + + the image name will be automatically converted to the unserscore_uppsercase + format, for example, "chaos-mesh" will be converted to "CHAOS_MESH" + """ + default_env = os.getenv("IMAGE_" + env) + env_mid_name = utils.underscore_uppercase(name) + + env = os.getenv(f"IMAGE_{env_mid_name}_{env}", default_env) + if env == "": + env = default_env + return env + + +def get_image_tag(name): + """ + get the tag of the image + """ + return get_image_env(name, "TAG") + + +def get_image_build(name): + """ + get whether this image should be built + """ + return get_image_env(name, "BUILD") + + +def get_image_full_name(name): + """ + get the full tag of an image + """ + tag = get_image_tag(name) + return f"ghcr.io/chaos-mesh/{name}:{tag}" + + +def pass_env_to_build_arg(cmd, arg_name): + """ + pass the environment variable to the build arguments + """ + if os.getenv(arg_name) is not None: + cmd += ["--build-arg", f"{arg_name}={os.getenv(arg_name)}"] + + +def main(): + """ + entrypoint of this script + """ + cmd_parser = argparse.ArgumentParser( + description='Helper script to build Chaos Mesh image.') + cmd_parser.add_argument( + 'name', + metavar="NAME", + type=str, + nargs=1, + help="the name of image") + cmd_parser.add_argument( + 'path', + metavar="PATH", + type=str, + nargs=1, + help="the path of the Dockerfile build directory") + + args = cmd_parser.parse_args() + name = args.name[0] + image_full_name = get_image_full_name(name) + + env = os.environ.copy() + cmd = [] + if get_image_build(name) == "1": + if os.getenv("DOCKER_CACHE") == "1": + env.update({"DOCKER_BUILDKIT": "1", + "DOCKER_CLI_EXPERIMENTAL": "enabled"}) + cache_dir = os.path.join( + os.getenv("DOCKER_CACHE_DIR", f"{os.getcwd()}/.cache/"), + f"image-{name}" + ) + pathlib.Path(cache_dir).mkdir(parents=True, exist_ok=True) + cmd = [ + "docker", + "buildx", + "build", + "--load", + "--cache-to", + f"type=local,dest={cache_dir}"] + if os.getenv("DISABLE_CACHE_FROM") != "1": + cmd += ["--cache-from", f"type=local,src={cache_dir}"] + else: + if os.getenv("TARGET_PLATFORM") is not None: + env.update({"DOCKER_BUILDKIT": "1"}) + cmd = [ + "docker", + "buildx", + "build", + "--load", + "--platform", + f"linux/{os.getenv('TARGET_PLATFORM')}"] + else: + # This branch is split to avoid to use `buildx`, as `buildx` is + # not supported on some CI environment + env.update({"DOCKER_BUILDKIT": "1"}) + cmd = ["docker", "build"] + + for env_key in common.export_env_variables: + pass_env_to_build_arg(cmd, env_key) + + target_platform = utils.get_target_platform() + cmd += ["--build-arg", f"TARGET_PLATFORM={target_platform.platform}"] + cmd += ["-t", image_full_name, args.path[0]] + else: + cmd = ["docker", "pull", image_full_name] + + print(" ".join(cmd)) + subprocess.run(cmd, env=env, check=True) + + +if __name__ == '__main__': + main() diff --git a/build/common.py b/build/common.py new file mode 100644 index 0000000000..f2ac8de685 --- /dev/null +++ b/build/common.py @@ -0,0 +1,28 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +""" +varaibles used commonly in multiple scripts +""" + +export_env_variables = [ + "HTTP_PROXY", + "HTTPS_PROXY", + "GOPROXY", + "UI", + "LDFLAGS", + "CRATES_MIRROR", + "GO_BUILD_CACHE", +] diff --git a/build/get_env_shell.py b/build/get_env_shell.py new file mode 100755 index 0000000000..086d7bed4a --- /dev/null +++ b/build/get_env_shell.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +""" +print the `docker run` command to run `Make` commands in a container +the arguments of `docker run` is based on the environment variables +""" + +import argparse +import os +import sys +import pathlib + +import build_image +import common +import utils + + +def pass_env_to_docker_arg(cmd, arg_name): + """ + pass environment variable to the docker run command + """ + if os.getenv(arg_name) is not None and os.getenv(arg_name) != "": + cmd += ["-e", f"{arg_name}"] + + +def main(): + """ + entrypoint of this script + """ + cmd_parser = argparse.ArgumentParser( + description='Helper script to run make in docker env.') + cmd_parser.add_argument( + '--interactive', + action='store_true', + dest='interactive', + help='Run in interactive mode') + cmd_parser.set_defaults(interactive=False) + + cmd_parser.add_argument( + '--no-check', + action='store_false', + dest='check', + help='Check the return value and exit') + cmd_parser.set_defaults(check=True) + + cmd_parser.add_argument( + 'env_name', + metavar="ENV_NAME", + type=str, + nargs=1, + help="the name of environment image") + + args = cmd_parser.parse_args() + + if os.path.exists("/.dockerenv"): + print("bash") + sys.exit(0) + + env_image_full_name = build_image.get_image_full_name(args.env_name[0]) + + cmd = ["docker", "run", "--rm", "--privileged"] + if args.interactive: + cmd += ["-it"] + + cwd = os.getcwd() + cmd += ["--volume", f"{cwd}:{cwd}"] + # HACK: if you have permission issues when using Docker Desktop for Mac, you can try removing this line to see if it works. + cmd += ["--user", f"{os.getuid()}:{os.getgid()}"] + + target_platform = utils.get_target_platform() + # If the environment variable is not set, don't pass `--platform` argument, + # as it's not supported on some docker build environment. + if target_platform.from_env: + cmd += ["--platform", f"linux/{target_platform.platform}"] + else: + cmd += ["--env", f"TARGET_PLATFORM={target_platform.platform}"] + + # For testing on arm64. + # See https://etcd.io/docs/v3.5/op-guide/supported-platform/#unsupported-platforms. + if target_platform.platform == "arm64": + cmd += ["--env", "ETCD_UNSUPPORTED_ARCH=arm64"] + + if os.getenv("GO_BUILD_CACHE") is not None and os.getenv( + "GO_BUILD_CACHE") != "": + tmp_go_dir = f"{os.getenv('GO_BUILD_CACHE')}/chaos-mesh-gopath" + tmp_go_build_dir = f"{os.getenv('GO_BUILD_CACHE')}/chaos-mesh-gobuild" + + pathlib.Path(tmp_go_dir).mkdir(parents=True, exist_ok=True) + pathlib.Path(tmp_go_build_dir).mkdir(parents=True, exist_ok=True) + cmd += ["--volume", f"{tmp_go_dir}:/tmp/go"] + cmd += ["--volume", f"{tmp_go_build_dir}:/tmp/go-build"] + + for env_key in common.export_env_variables: + pass_env_to_docker_arg(cmd, env_key) + + cmd += ["--workdir", cwd] + cmd += [env_image_full_name] + cmd += ["/bin/bash"] + + print(" ".join(cmd)) + + +if __name__ == '__main__': + main() diff --git a/build/utils.py b/build/utils.py new file mode 100644 index 0000000000..1a2974d07a --- /dev/null +++ b/build/utils.py @@ -0,0 +1,55 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +""" +functions used in multiple scripts +""" + +import os +import sys +from collections import namedtuple + + +def underscore_uppercase(name): + """ + convert the given name to the underscore_uppercase format + """ + return name.replace('-', '_').upper() + + +def get_target_platform(): + """ + get the target platform according to the `TARGET_PLATFORM` variable or the + `uname` syscall + """ + Platform = namedtuple('Platform', ['platform', 'from_env']) + + if os.getenv("TARGET_PLATFORM") is not None and os.getenv("TARGET_PLATFORM") != "": + return Platform(os.getenv("TARGET_PLATFORM"), True) + + machine = os.uname().machine + if machine == "x86_64": + return Platform("amd64", False) + + if machine == "amd64": + return Platform("amd64", False) + + if machine == "arm64": + return Platform("arm64", False) + + if machine == "aarch64": + return Platform("arm64", False) + + sys.exit("Please run this script on amd64 or arm64 machines.") diff --git a/ci/builder.toml b/ci/builder.toml deleted file mode 100644 index 8416bb22e5..0000000000 --- a/ci/builder.toml +++ /dev/null @@ -1,2 +0,0 @@ -[registry."docker.io"] - mirrors = ["registry-mirror.pingcap.net"] \ No newline at end of file diff --git a/ci/pingcap_chaos_mesh_build_kind.groovy b/ci/pingcap_chaos_mesh_build_kind.groovy deleted file mode 100644 index 7e83a52420..0000000000 --- a/ci/pingcap_chaos_mesh_build_kind.groovy +++ /dev/null @@ -1,267 +0,0 @@ -// -// E2E Jenkins file. -// - -import groovy.transform.Field - -@Field -def podYAML = ''' -apiVersion: v1 -kind: Pod -metadata: - labels: - # we pretend as tidb-operator in order not to meet chaos-mesh-e2e job in the same node - app: chaos-mesh-e2e -spec: - containers: - - name: main - image: hub.pingcap.net/yangkeao/chaos-mesh-e2e-base - command: - - runner.sh - # Clean containers on TERM signal in root process to avoid cgroup leaking. - # https://github.com/pingcap/tidb-operator/issues/1603#issuecomment-582402196 - - exec - - bash - - -c - - | - function clean() { - echo "info: clean all containers to avoid cgroup leaking" - docker kill $(docker ps -q) || true - docker system prune -af || true - } - trap clean TERM - sleep 1d & wait - # we need privileged mode in order to do docker in docker - securityContext: - privileged: true - env: - - name: DOCKER_IN_DOCKER_ENABLED - value: "true" - resources: - requests: - memory: "4Gi" - cpu: 4 - ephemeral-storage: "10Gi" - limits: - memory: "8Gi" - cpu: 8 - ephemeral-storage: "50Gi" - # kind needs /lib/modules and cgroups from the host - volumeMounts: - - mountPath: /lib/modules - name: modules - readOnly: true - - mountPath: /sys/fs/cgroup - name: cgroup - # dind expects /var/lib/docker to be volume - - name: docker-root - mountPath: /var/lib/docker - # legacy docker path for cr.io/k8s-testimages/kubekins-e2e - - name: docker-graph - mountPath: /docker-graph - volumes: - - name: modules - hostPath: - path: /lib/modules - type: Directory - - name: cgroup - hostPath: - path: /sys/fs/cgroup - type: Directory - - name: docker-root - emptyDir: {} - - name: docker-graph - emptyDir: {} - affinity: - # running on nodes for chaos-mesh only - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: ci.pingcap.com - operator: In - values: - # we pretend as tidb-operator in order not to meet chaos-mesh-e2e job in the same node - - tidb-operator - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 100 - podAffinityTerm: - labelSelector: - matchExpressions: - - key: app - operator: In - values: - # we pretend as tidb-operator in order not to meet chaos-mesh-e2e job in the same node - - chaos-mesh-e2e - topologyKey: kubernetes.io/hostname -''' - -def build(String name, String code) { - podTemplate(yaml: podYAML) { - node(POD_LABEL) { - container('main') { - def WORKSPACE = pwd() - def ARTIFACTS = "${WORKSPACE}/go/src/github.com/chaos-mesh/chaos-mesh/_artifacts" - try { - dir("${WORKSPACE}/go/src/github.com/chaos-mesh/chaos-mesh") { - unstash 'chaos-mesh' - stage("Debug Info") { - println "debug host: 172.16.5.15" - println "debug command: kubectl -n jenkins-ci exec -ti ${NODE_NAME} bash" - sh """ - echo "====== shell env ======" - echo "pwd: \$(pwd)" - env - echo "====== go env ======" - go env - echo "====== docker version ======" - docker version - """ - } - stage('Extract docker cache') { - ansiColor('xterm') { - sh """ - tar xvf /cache.tar.gz - """ - } - } - stage('Copy binary tools') { - ansiColor('xterm') { - sh """ - mkdir output - cp -r /usr/local/bin/chaos-mesh-e2e output/bin - """ - } - } - stage('Build image') { - ansiColor('xterm') { - sh """ - DOCKER_CLI_EXPERIMENTAL=enabled docker buildx create --use --name chaos-mesh-builder --config ./ci/builder.toml - make DOCKER_CACHE=1 DOCKER_CACHE_DIR=\$(pwd)/cache GO_BUILD_CACHE=\$(pwd)/cache image - make DOCKER_CACHE=1 DOCKER_CACHE_DIR=\$(pwd)/cache GO_BUILD_CACHE=\$(pwd)/cache image-e2e-helper - make DOCKER_CACHE=1 DOCKER_CACHE_DIR=\$(pwd)/cache GO_BUILD_CACHE=\$(pwd)/cache image-chaos-mesh-e2e - """ - } - } - stage('Run') { - ansiColor('xterm') { - sh """ - export GOPATH=${WORKSPACE}/go - export ARTIFACTS=${ARTIFACTS} - ${code} - """ - } - } - } - } finally { - dir(ARTIFACTS) { - sh """#!/bin/bash - echo "info: change ownerships for jenkins" - chown -R 1000:1000 . - echo "info: print total size of artifacts" - du -sh . - echo "info: list all files" - find . - echo "info: moving all artifacts into a sub-directory" - shopt -s extglob - mkdir ${name} - mv !(${name}) ${name}/ - """ - archiveArtifacts artifacts: "${name}/**", allowEmptyArchive: true - junit testResults: "${name}/*.xml", allowEmptyResults: true - } - } - } - } - } -} - -def getChangeLogText() { - def changeLogText = "" - for (int i = 0; i < currentBuild.changeSets.size(); i++) { - for (int j = 0; j < currentBuild.changeSets[i].items.length; j++) { - def commitId = "${currentBuild.changeSets[i].items[j].commitId}" - def commitMsg = "${currentBuild.changeSets[i].items[j].msg}" - changeLogText += "\n" + "`${commitId.take(7)}` ${commitMsg}" - } - } - return changeLogText -} - -def call(BUILD_BRANCH, CREDENTIALS_ID) { - timeout (time: 2, unit: 'HOURS') { - - def UCLOUD_OSS_URL = "http://pingcap-dev.hk.ufileos.com" - def BUILD_URL = "git@github.com:pingcap/chaos-mesh.git" - def PROJECT_DIR = "go/src/github.com/chaos-mesh/chaos-mesh" - - catchError { - node('build_go1130_memvolume') { - container("golang") { - def WORKSPACE = pwd() - dir("${PROJECT_DIR}") { - deleteDir() - - stage('Checkout') { - checkout changelog: false, - poll: false, - scm: [ - $class: 'GitSCM', - branches: [[name: "${BUILD_BRANCH}"]], - doGenerateSubmoduleConfigurations: false, - extensions: [[$class: 'SubmoduleOption', parentCredentials: true], [$class: 'CloneOption', shallow: true]], - submoduleCfg: [], - userRemoteConfigs: [[ - credentialsId: "${CREDENTIALS_ID}", - refspec: '+refs/heads/*:refs/remotes/origin/* +refs/pull/*:refs/remotes/origin/pr/*', - url: "${BUILD_URL}", - ]] - ] - } - - stash excludes: "vendor/**,deploy/**", name: "chaos-mesh" - } - } - } - - def GLOBALS = "SKIP_BUILD=y SKIP_IMAGE_BUILD=y GINKGO_NO_COLOR=y" - def artifacts = "go/src/github.com/chaos-mesh/chaos-mesh/artifacts" - def builds = [:] - builds["E2E v1.12.10"] = { - build("v1.12", "${GLOBALS} GINKGO_NODES=6 KUBE_VERSION=v1.12.10 KIND_VERSION=0.8.1 ./hack/e2e.sh -- --ginkgo.focus='Basic'") - } - builds["E2E on kubernetes 1.20.4"] = { - build("v1.20", "${GLOBALS} GINKGO_NODES=6 KUBE_VERSION=v1.20.2 ./hack/e2e.sh -- --ginkgo.focus='Basic'") - } - builds.failFast = false - parallel builds - - currentBuild.result = "SUCCESS" - } - - stage('Summary') { - def CHANGELOG = getChangeLogText() - def duration = ((System.currentTimeMillis() - currentBuild.startTimeInMillis) / 1000 / 60).setScale(2, BigDecimal.ROUND_HALF_UP) - def slackmsg = "[#${env.ghprbPullId}: ${env.ghprbPullTitle}]" + "\n" + - "${env.ghprbPullLink}" + "\n" + - "${env.ghprbPullDescription}" + "\n" + - "Integration Common Test Result: `${currentBuild.result}`" + "\n" + - "Elapsed Time: `${duration} mins` " + "\n" + - "${CHANGELOG}" + "\n" + - "${env.RUN_DISPLAY_URL}" - - if (currentBuild.result != "SUCCESS") { - slackSend channel: '#cloud_jenkins', color: 'danger', teamDomain: 'pingcap', tokenCredentialId: 'slack-pingcap-token', message: "${slackmsg}" - return - } - - slackSend channel: '#cloud_jenkins', color: 'good', teamDomain: 'pingcap', tokenCredentialId: 'slack-pingcap-token', message: "${slackmsg}" - } - - } -} - -return this - -// vim: noet diff --git a/cmd/chaos-builder/boilerplate.go b/cmd/chaos-builder/boilerplate.go new file mode 100644 index 0000000000..6405a47bf2 --- /dev/null +++ b/cmd/chaos-builder/boilerplate.go @@ -0,0 +1,36 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package main + +const boilerplate = `// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Code generated by chaos-builder. DO NOT EDIT. + +package v1alpha1 +` diff --git a/cmd/chaos-builder/config.go b/cmd/chaos-builder/config.go new file mode 100644 index 0000000000..809cdf7361 --- /dev/null +++ b/cmd/chaos-builder/config.go @@ -0,0 +1,16 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package main diff --git a/cmd/chaos-builder/frontend.go b/cmd/chaos-builder/frontend.go new file mode 100644 index 0000000000..add7468503 --- /dev/null +++ b/cmd/chaos-builder/frontend.go @@ -0,0 +1,54 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package main + +import "fmt" + +type FrontendCodeGenerator struct { + // name of each Kind of chaos, for example: PodChaos, IOChaos, DNSChaos + chaosTypes []string +} + +func newFrontendCodeGenerator(chaosTypes []string) *FrontendCodeGenerator { + return &FrontendCodeGenerator{chaosTypes} +} + +func (it *FrontendCodeGenerator) AppendTypes(typeName string) { + it.chaosTypes = append(it.chaosTypes, typeName) +} + +const typesTemplate = `import { ExperimentKind } from 'components/NewExperiment/types' + +const mapping = new Map([ +%s]) + +export function templateTypeToFieldName(templateType: ExperimentKind): string { + return mapping.get(templateType)! +} +` + +func (it *FrontendCodeGenerator) Render() string { + return fmt.Sprintf(typesTemplate, it.mapEntries()) +} + +func (it *FrontendCodeGenerator) mapEntries() string { + entries := "" + for _, chaosType := range it.chaosTypes { + entries += fmt.Sprintf(` ['%s', '%s'], +`, chaosType, lowercaseCamelCase(chaosType)) + } + return entries +} diff --git a/cmd/chaos-builder/impl.go b/cmd/chaos-builder/impl.go index 56ebbcd3df..a89edec5f5 100644 --- a/cmd/chaos-builder/impl.go +++ b/cmd/chaos-builder/impl.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package main @@ -24,13 +26,23 @@ import ( "reflect" "time" + "github.com/pkg/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + gw "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" ) + +// updating spec of a chaos will have no effect, we'd better reject it +var ErrCanNotUpdateChaos = errors.New("Cannot update chaos spec") ` const implTemplate = ` const Kind{{.Type}} = "{{.Type}}" - +{{if .IsExperiment}} // IsDeleted returns whether this resource has been deleted func (in *{{.Type}}) IsDeleted() bool { return !in.DeletionTimestamp.IsZero() @@ -44,91 +56,33 @@ func (in *{{.Type}}) IsPaused() bool { return true } +// GetObjectMeta would return the ObjectMeta for chaos +func (in *{{.Type}}) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + // GetDuration would return the duration for chaos -func (in *{{.Type}}) GetDuration() (*time.Duration, error) { - if in.Spec.Duration == nil { +func (in *{{.Type}}Spec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { return nil, nil } - duration, err := time.ParseDuration(*in.Spec.Duration) + duration, err := time.ParseDuration(string(*in.Duration)) if err != nil { return nil, err } return &duration, nil } -func (in *{{.Type}}) GetNextStart() time.Time { - if in.Status.Scheduler.NextStart == nil { - return time.Time{} - } - return in.Status.Scheduler.NextStart.Time -} - -func (in *{{.Type}}) SetNextStart(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextStart = nil - return - } - - if in.Status.Scheduler.NextStart == nil { - in.Status.Scheduler.NextStart = &metav1.Time{} - } - in.Status.Scheduler.NextStart.Time = t -} - -func (in *{{.Type}}) GetNextRecover() time.Time { - if in.Status.Scheduler.NextRecover == nil { - return time.Time{} - } - return in.Status.Scheduler.NextRecover.Time -} - -func (in *{{.Type}}) SetNextRecover(t time.Time) { - if t.IsZero() { - in.Status.Scheduler.NextRecover = nil - return - } - - if in.Status.Scheduler.NextRecover == nil { - in.Status.Scheduler.NextRecover = &metav1.Time{} - } - in.Status.Scheduler.NextRecover.Time = t -} - -// GetScheduler would return the scheduler for chaos -func (in *{{.Type}}) GetScheduler() *SchedulerSpec { - return in.Spec.Scheduler -} - -// GetChaos would return the a record for chaos -func (in *{{.Type}}) GetChaos() *ChaosInstance { - instance := &ChaosInstance{ - Name: in.Name, - Namespace: in.Namespace, - Kind: Kind{{.Type}}, - StartTime: in.CreationTimestamp.Time, - Action: "", - Status: string(in.Status.Experiment.Phase), - UID: string(in.UID), - } - - action := reflect.ValueOf(in).Elem().FieldByName("Spec").FieldByName("Action") - if action.IsValid() { - instance.Action = action.String() - } - if in.Spec.Duration != nil { - instance.Duration = *in.Spec.Duration - } - if in.DeletionTimestamp != nil { - instance.EndTime = in.DeletionTimestamp.Time - } - return instance -} - // GetStatus returns the status func (in *{{.Type}}) GetStatus() *ChaosStatus { return &in.Status.ChaosStatus } +// GetRemoteCluster returns the remoteCluster +func (in *{{.Type}}) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + // GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. func (in *{{.Type}}) GetSpecAndMetaString() (string, error) { spec, err := json.Marshal(in.Spec) @@ -152,17 +106,91 @@ type {{.Type}}List struct { Items []{{.Type}} ` + "`" + `json:"items"` + "`" + ` } +func (in *{{.Type}}List) DeepCopyList() GenericChaosList { + return in.DeepCopy() +} + // ListChaos returns a list of chaos -func (in *{{.Type}}List) ListChaos() []*ChaosInstance { - res := make([]*ChaosInstance, 0, len(in.Items)) +func (in *{{.Type}}List) ListChaos() []GenericChaos { + var result []GenericChaos for _, item := range in.Items { - res = append(res, item.GetChaos()) + item := item + result = append(result, &item) + } + return result +} + +func (in *{{.Type}}) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err + } + + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } + + return false, stopTime.Sub(now), nil + } + + return false, 0, nil +} + +func (in *{{.Type}}) IsOneShot() bool { + {{- if .OneShotExp}} + if {{.OneShotExp}} { + return true } - return res + + return false + {{- else}} + return false + {{- end}} +} +{{end}} +var {{.Type}}WebhookLog = logf.Log.WithName("{{.Type}}-resource") + +func (in *{{.Type}}) ValidateCreate() (admission.Warnings, error) { + {{.Type}}WebhookLog.Info("validate create", "name", in.Name) + return in.Validate() +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *{{.Type}}) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + {{.Type}}WebhookLog.Info("validate update", "name", in.Name) + {{- if not .EnableUpdate}} + if !reflect.DeepEqual(in.Spec, old.(*{{.Type}}).Spec) { + return nil, ErrCanNotUpdateChaos + } + {{- end}} + return in.Validate() +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *{{.Type}}) ValidateDelete() (admission.Warnings, error) { + {{.Type}}WebhookLog.Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil +} + +var _ webhook.Validator = &{{.Type}}{} + +func (in *{{.Type}}) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) +} + +var _ webhook.Defaulter = &{{.Type}}{} + +func (in *{{.Type}}) Default() { + gw.Default(in) } ` -func generateImpl(name string) string { +func generateImpl(name string, oneShotExp string, isExperiment, enableUpdate bool) string { tmpl, err := template.New("impl").Parse(implTemplate) if err != nil { log.Error(err, "fail to build template") @@ -171,7 +199,10 @@ func generateImpl(name string) string { buf := new(bytes.Buffer) err = tmpl.Execute(buf, &metadata{ - Type: name, + Type: name, + OneShotExp: oneShotExp, + IsExperiment: isExperiment, + EnableUpdate: enableUpdate, }) if err != nil { log.Error(err, "fail to execute template") diff --git a/cmd/chaos-builder/init.go b/cmd/chaos-builder/init.go index f1cf2d5e4c..cfb069c35c 100644 --- a/cmd/chaos-builder/init.go +++ b/cmd/chaos-builder/init.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package main @@ -20,13 +22,15 @@ import ( const initTemplate = ` SchemeBuilder.Register(&{{.Type}}{}, &{{.Type}}List{}) +{{- if .IsExperiment}} all.register(Kind{{.Type}}, &ChaosKind{ - Chaos: &{{.Type}}{}, - ChaosList: &{{.Type}}List{}, + chaos: &{{.Type}}{}, + list: &{{.Type}}List{}, }) +{{- end}} ` -func generateInit(name string) string { +func generateInit(name string, isExperiment bool) string { tmpl, err := template.New("ini").Parse(initTemplate) if err != nil { log.Error(err, "fail to build template") @@ -35,7 +39,8 @@ func generateInit(name string) string { buf := new(bytes.Buffer) err = tmpl.Execute(buf, &metadata{ - Type: name, + Type: name, + IsExperiment: isExperiment, }) if err != nil { log.Error(err, "fail to execute template") diff --git a/cmd/chaos-builder/main.go b/cmd/chaos-builder/main.go index 9373db386f..fbdb33de8e 100644 --- a/cmd/chaos-builder/main.go +++ b/cmd/chaos-builder/main.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package main @@ -22,44 +24,37 @@ import ( "path/filepath" "strings" + "github.com/go-logr/zapr" "github.com/pingcap/errors" - "sigs.k8s.io/controller-runtime/pkg/log/zap" + "go.uber.org/zap" ) var ( - log = zap.New(zap.UseDevMode(true)) + zapLogger, _ = zap.NewDevelopment() + log = zapr.NewLogger(zapLogger) ) type metadata struct { - Type string + Type string + OneShotExp string + IsExperiment bool + EnableUpdate bool } -const codeHeader = `// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package v1alpha1 -` - func main() { - implCode := codeHeader + implImport + implCode := boilerplate + implImport - testCode := codeHeader + testImport + testCode := boilerplate + testImport initImpl := "" - allTypes := make([]string, 0, 10) + scheduleImpl := "" workflowGenerator := newWorkflowCodeGenerator(nil) workflowTestGenerator := newWorkflowTestCodeGenerator(nil) + scheduleGenerator := newScheduleCodeGenerator(nil) + + frontendGenerator := newFrontendCodeGenerator(nil) + filepath.Walk("./api/v1alpha1", func(path string, info os.FileInfo, err error) error { log := log.WithValues("file", path) @@ -73,6 +68,9 @@ func main() { if !strings.HasSuffix(info.Name(), ".go") { return nil } + if strings.HasPrefix(info.Name(), "zz_generated") { + return nil + } fset := token.NewFileSet() file, err := parser.ParseFile(fset, path, nil, parser.ParseComments) @@ -86,36 +84,55 @@ func main() { out: for node, commentGroups := range cmap { for _, commentGroup := range commentGroups { - var err error + var oneShotExp string + var enableUpdate bool + + for _, comment := range commentGroup.List { + if strings.Contains(comment.Text, "+chaos-mesh:webhook:enableUpdate") { + enableUpdate = true + break + } + } + for _, comment := range commentGroup.List { if strings.Contains(comment.Text, "+chaos-mesh:base") { - log.Info("build", "pos", fset.Position(comment.Pos())) - baseDecl, ok := node.(*ast.GenDecl) - if !ok { - err = errors.Errorf("node is not a *ast.GenDecl") - log.Error(err, "fail to get type") + baseType, err := getType(fset, node, comment) + if err != nil { return err } - - if baseDecl.Tok != token.TYPE { - err = errors.Errorf("node.Tok is not token.TYPE") - log.Error(err, "fail to get type") - return err + if strings.Contains(comment.Text, "+chaos-mesh:base") { + if baseType.Name.Name != "Workflow" { + implCode += generateImpl(baseType.Name.Name, oneShotExp, false, enableUpdate) + initImpl += generateInit(baseType.Name.Name, false) + } } + continue out + } + } - baseType, ok := baseDecl.Specs[0].(*ast.TypeSpec) - if !ok { - err = errors.Errorf("node is not a *ast.TypeSpec") - log.Error(err, "fail to get type") + for _, comment := range commentGroup.List { + if strings.Contains(comment.Text, "+chaos-mesh:oneshot") { + oneShotExp = strings.TrimPrefix(comment.Text, "// +chaos-mesh:oneshot=") + log.Info("decode oneshot expression", "expression", oneShotExp) + } + } + for _, comment := range commentGroup.List { + if strings.Contains(comment.Text, "+chaos-mesh:experiment") { + baseType, err := getType(fset, node, comment) + if err != nil { return err } - implCode += generateImpl(baseType.Name.Name) - testCode += generateTest(baseType.Name.Name) - initImpl += generateInit(baseType.Name.Name) - workflowGenerator.AppendTypes(baseType.Name.Name) - workflowTestGenerator.AppendTypes(baseType.Name.Name) - allTypes = append(allTypes, baseType.Name.Name) + if baseType.Name.Name != "Workflow" { + implCode += generateImpl(baseType.Name.Name, oneShotExp, true, enableUpdate) + initImpl += generateInit(baseType.Name.Name, true) + testCode += generateTest(baseType.Name.Name) + workflowGenerator.AppendTypes(baseType.Name.Name) + workflowTestGenerator.AppendTypes(baseType.Name.Name) + frontendGenerator.AppendTypes(baseType.Name.Name) + } + scheduleImpl += generateScheduleRegister(baseType.Name.Name) + scheduleGenerator.AppendTypes(baseType.Name.Name) continue out } } @@ -125,20 +142,18 @@ func main() { return nil }) - validatorCode := generateGetChaosValidatorFunc(allTypes) - implCode += fmt.Sprintf(` func init() { %s +%s } -`, initImpl) +`, initImpl, scheduleImpl) file, err := os.Create("./api/v1alpha1/zz_generated.chaosmesh.go") if err != nil { log.Error(err, "fail to create file") os.Exit(1) } fmt.Fprint(file, implCode) - fmt.Fprint(file, validatorCode) testCode += testInit file, err = os.Create("./api/v1alpha1/zz_generated.chaosmesh_test.go") @@ -162,4 +177,41 @@ func init() { } fmt.Fprint(file, workflowTestGenerator.Render()) + file, err = os.Create("./api/v1alpha1/zz_generated.schedule.chaosmesh.go") + if err != nil { + log.Error(err, "fail to create file") + os.Exit(1) + } + fmt.Fprint(file, scheduleGenerator.Render()) + + file, err = os.Create("./ui/app/src/api/zz_generated.frontend.chaos-mesh.ts") + if err != nil { + log.Error(err, "fail to create file") + os.Exit(1) + } + fmt.Fprint(file, frontendGenerator.Render()) +} + +func getType(fset *token.FileSet, node ast.Node, comment *ast.Comment) (*ast.TypeSpec, error) { + log.Info("build", "pos", fset.Position(comment.Pos())) + decl, ok := node.(*ast.GenDecl) + if !ok { + err := errors.New("node is not a *ast.GenDecl") + log.Error(err, "fail to get type") + return nil, err + } + + if decl.Tok != token.TYPE { + err := errors.New("node.Tok is not token.TYPE") + log.Error(err, "fail to get type") + return nil, err + } + + baseType, ok := decl.Specs[0].(*ast.TypeSpec) + if !ok { + err := errors.New("node is not a *ast.TypeSpec") + log.Error(err, "fail to get type") + return nil, err + } + return baseType, nil } diff --git a/cmd/chaos-builder/schedule.go b/cmd/chaos-builder/schedule.go new file mode 100644 index 0000000000..63b58b09b0 --- /dev/null +++ b/cmd/chaos-builder/schedule.go @@ -0,0 +1,213 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package main + +import ( + "bytes" + "fmt" + "text/template" +) + +const scheduleTemplate = ` + allScheduleItem.register(Kind{{.Type}}, &ChaosKind{ + chaos: &{{.Type}}{}, + list: &{{.Type}}List{}, + }) +` + +func generateScheduleRegister(name string) string { + tmpl, err := template.New("ini").Parse(scheduleTemplate) + if err != nil { + log.Error(err, "fail to build template") + panic(err) + } + + buf := new(bytes.Buffer) + err = tmpl.Execute(buf, &metadata{ + Type: name, + }) + if err != nil { + log.Error(err, "fail to execute template") + panic(err) + } + + return buf.String() +} + +type scheduleCodeGenerator struct { + // name of each Kind of chaos, for example: PodChaos, IOChaos, DNSChaos + chaosTypes []string +} + +func newScheduleCodeGenerator(types []string) *scheduleCodeGenerator { + return &scheduleCodeGenerator{chaosTypes: types} +} + +func (it *scheduleCodeGenerator) AppendTypes(typeName string) { + it.chaosTypes = append(it.chaosTypes, typeName) +} + +func (it *scheduleCodeGenerator) Render() string { + + scheduleTemplateTypesEntries := "" + for _, item := range it.chaosTypes { + scheduleTemplateTypesEntries += generateScheduleTemplateTypes(item) + } + + embedChaosEntries := "" + for _, item := range it.chaosTypes { + embedChaosEntries += generateScheduleItem(item) + } + + scheduleTemplateTypeEntries := "" + for _, item := range it.chaosTypes { + scheduleTemplateTypeEntries += fmt.Sprintf(` ScheduleType%s, +`, item) + } + + spawnMethod := "" + for _, item := range it.chaosTypes { + spawnMethod += generateFillingMethodScheduleItem(item, scheduleFillingEntryTemplate) + } + + restoreMethod := "" + for _, item := range it.chaosTypes { + restoreMethod += generateFillingMethodScheduleItem(item, scheduleRestoreEntryTemplate) + } + + imports := `import ( + "github.com/pkg/errors" +) +` + + scheduleTemplateTypesCodes := fmt.Sprintf(`%s + +%s + +const ( +%s +) + +var allScheduleTemplateType = []ScheduleTemplateType{ +%s +} + +func (it *ScheduleItem) SpawnNewObject(templateType ScheduleTemplateType) (GenericChaos, error) { + switch templateType { +%s + default: + return nil, errors.Wrapf(errInvalidValue, "unknown template type %%s", templateType) + } +} + +func (it *ScheduleItem) RestoreChaosSpec(root interface{}) error { + switch chaos := root.(type) { +%s + default: + return errors.Wrapf(errInvalidValue, "unknown chaos %%#v", root) + } +} +`, + boilerplate, + imports, + scheduleTemplateTypesEntries, + scheduleTemplateTypeEntries, + spawnMethod, + restoreMethod, + ) + + return scheduleTemplateTypesCodes +} + +const scheduleTemplateTypeEntryTemplate = ` ScheduleType{{.Type}} ScheduleTemplateType = "{{.Type}}" +` + +func generateScheduleTemplateTypes(typeName string) string { + tmpl, err := template.New("scheduleTemplates").Parse(scheduleTemplateTypeEntryTemplate) + if err != nil { + log.Error(err, "fail to build template") + return "" + } + + buf := new(bytes.Buffer) + err = tmpl.Execute(buf, &metadata{ + Type: typeName, + }) + if err != nil { + log.Error(err, "fail to execute template") + return "" + } + + return buf.String() +} + +const scheduleItemTemplate = ` // +optional + {{.Type}} *{{.Type}}Spec ` + "`" + `json:"{{.JsonField}},omitempty"` + "`" + ` +` + +func generateScheduleItem(typeName string) string { + value := struct { + Type string + JsonField string + }{ + Type: typeName, + JsonField: lowercaseCamelCase(typeName), + } + tmpl, err := template.New("scheduleTemplates").Parse(scheduleItemTemplate) + if err != nil { + log.Error(err, "fail to build template") + return "" + } + + buf := new(bytes.Buffer) + err = tmpl.Execute(buf, &value) + if err != nil { + log.Error(err, "fail to execute template") + return "" + } + + return buf.String() +} + +const scheduleFillingEntryTemplate = ` case ScheduleType{{.Type}}: + result := {{.Type}}{} + result.Spec = *it.{{.Type}} + return &result, nil +` + +const scheduleRestoreEntryTemplate = ` case *{{.Type}}: + *it.{{.Type}} = chaos.Spec + return nil +` + +func generateFillingMethodScheduleItem(typeName, methodTemplate string) string { + tmpl, err := template.New("fillingMethod").Parse(methodTemplate) + if err != nil { + log.Error(err, "fail to build template") + return "" + } + + buf := new(bytes.Buffer) + err = tmpl.Execute(buf, &metadata{ + Type: typeName, + }) + if err != nil { + log.Error(err, "fail to execute template") + return "" + } + + return buf.String() +} diff --git a/cmd/chaos-builder/test.go b/cmd/chaos-builder/test.go index b759c11d66..0442bb8705 100644 --- a/cmd/chaos-builder/test.go +++ b/cmd/chaos-builder/test.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package main @@ -22,7 +24,6 @@ const testImport = ` import ( "reflect" "testing" - "time" "github.com/bxcodec/faker" . "github.com/onsi/gomega" @@ -68,73 +69,7 @@ func Test{{.Type}}GetDuration(t *testing.T) { g.Expect(err).To(BeNil()) - chaos.GetDuration() -} - -func Test{{.Type}}GetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &{{.Type}}{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextStart() -} - -func Test{{.Type}}SetNextStart(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &{{.Type}}{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextStart(time.Now()) -} - -func Test{{.Type}}GetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &{{.Type}}{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetNextRecover() -} - -func Test{{.Type}}SetNextRecover(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &{{.Type}}{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.SetNextRecover(time.Now()) -} - -func Test{{.Type}}GetScheduler(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &{{.Type}}{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetScheduler() -} - -func Test{{.Type}}GetChaos(t *testing.T) { - g := NewGomegaWithT(t) - - chaos := &{{.Type}}{} - err := faker.FakeData(chaos) - - g.Expect(err).To(BeNil()) - - chaos.GetChaos() + chaos.Spec.GetDuration() } func Test{{.Type}}GetStatus(t *testing.T) { diff --git a/cmd/chaos-builder/test_workflow.go b/cmd/chaos-builder/test_workflow.go index 7ea584c40a..8d4d105bc4 100644 --- a/cmd/chaos-builder/test_workflow.go +++ b/cmd/chaos-builder/test_workflow.go @@ -4,12 +4,14 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package main @@ -21,7 +23,7 @@ import ( // struct workflowTestCodeGenerator will render content of one file for testing the coupling with chaosKindMap type workflowTestCodeGenerator struct { - // name of each Kind of chaos, for example: PodChaos, IoChaos, DNSChaos + // name of each Kind of chaos, for example: PodChaos, IOChaos, DNSChaos chaosTypes []string } @@ -48,7 +50,7 @@ func (it *workflowTestCodeGenerator) Render() string { %s %s `, - codeHeader, + boilerplate, imports, testMethods, ) diff --git a/cmd/chaos-builder/validator.go b/cmd/chaos-builder/validator.go deleted file mode 100644 index eb4f7e4023..0000000000 --- a/cmd/chaos-builder/validator.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "bytes" - "text/template" -) - -const validatorTmpl = ` -// GetChaosValidator returns chaos object by kind -func GetChaosValidator(chaosKind string) ChaosValidator { - switch chaosKind { -{{range $val := .}} - case Kind{{$val}}: - return &{{$val}}{} -{{end}} - default: - return nil - } -} -` - -func generateGetChaosValidatorFunc(allTypes []string) string { - tmpl, err := template.New("ini").Parse(validatorTmpl) - if err != nil { - log.Error(err, "fail to build template") - panic(err) - } - - buf := new(bytes.Buffer) - err = tmpl.Execute(buf, allTypes) - if err != nil { - log.Error(err, "fail to execute template") - panic(err) - } - - return buf.String() - -} diff --git a/cmd/chaos-builder/workflow.go b/cmd/chaos-builder/workflow.go index bd4e744a4d..02513571a6 100644 --- a/cmd/chaos-builder/workflow.go +++ b/cmd/chaos-builder/workflow.go @@ -4,26 +4,29 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package main import ( "bytes" "fmt" - "regexp" "strings" "text/template" + + "github.com/iancoleman/strcase" ) // struct workflowCodeGenerator will render content of one file contains code blocks that required by workflow type workflowCodeGenerator struct { - // name of each Kind of chaos, for example: PodChaos, IoChaos, DNSChaos + // name of each Kind of chaos, for example: PodChaos, IOChaos, DNSChaos chaosTypes []string } @@ -47,9 +50,17 @@ func (it *workflowCodeGenerator) Render() string { embedChaosEntries += generateEmbedChaos(item) } - spawnMethod := "" + spawnObjectMethod := "" for _, item := range it.chaosTypes { - spawnMethod += generateSpawnMethodItem(item) + spawnObjectMethod += generateMethodItem(item, spawnObjectEntryTemplate) + } + restoreObjectMethod := "" + for _, item := range it.chaosTypes { + restoreObjectMethod += generateMethodItem(item, restoreObjectEntryTemplate) + } + spawnListMethod := "" + for _, item := range it.chaosTypes { + spawnListMethod += generateSpawnListMethodItem(item) } allChaosTemplateTypeEntries := "" for _, item := range it.chaosTypes { @@ -57,10 +68,13 @@ func (it *workflowCodeGenerator) Render() string { `, item) } + genericChaosListImplementations := "" + for _, item := range it.chaosTypes { + genericChaosListImplementations += generateGenericChaosList(item) + } + imports := `import ( - "fmt" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" + "github.com/pkg/errors" ) ` @@ -73,6 +87,7 @@ const ( ) var allChaosTemplateType = []TemplateType{ + TypeSchedule, %s } @@ -80,23 +95,41 @@ type EmbedChaos struct { %s } -func (it *EmbedChaos) SpawnNewObject(templateType TemplateType) (runtime.Object, metav1.Object, error) { - +func (it *EmbedChaos) SpawnNewObject(templateType TemplateType) (GenericChaos, error) { switch templateType { %s default: - return nil, nil, fmt.Errorf("unsupported template type %%s", templateType) + return nil, errors.Wrapf(errInvalidValue, "unknown template type %%s", templateType) + } +} + +func (it *EmbedChaos) RestoreChaosSpec(root interface{}) error { + switch chaos := root.(type) { +%s + default: + return errors.Wrapf(errInvalidValue, "unknown chaos %%#v", root) } +} - return nil, &metav1.ObjectMeta{}, nil +func (it *EmbedChaos) SpawnNewList(templateType TemplateType) (GenericChaosList, error) { + switch templateType { +%s + default: + return nil, errors.Wrapf(errInvalidValue, "unknown template type %%s", templateType) + } } + +%s `, - codeHeader, + boilerplate, imports, workflowTemplateTypesEntries, allChaosTemplateTypeEntries, embedChaosEntries, - spawnMethod, + spawnObjectMethod, + restoreObjectMethod, + spawnListMethod, + genericChaosListImplementations, ) return workflowTemplateTypesCodes @@ -134,7 +167,7 @@ func generateEmbedChaos(typeName string) string { JsonField string }{ Type: typeName, - JsonField: camelCaseToSnakeCase(typeName), + JsonField: lowercaseCamelCase(typeName), } tmpl, err := template.New("workflowTemplates").Parse(embedChaosEntryTemplate) if err != nil { @@ -152,23 +185,82 @@ func generateEmbedChaos(typeName string) string { return buf.String() } -var matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)") -var matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])") - -func camelCaseToSnakeCase(str string) string { - snake := matchFirstCap.ReplaceAllString(str, "${1}_${2}") - snake = matchAllCap.ReplaceAllString(snake, "${1}_${2}") - return strings.ToLower(snake) +func lowercaseCamelCase(str string) string { + // here are some name thing issue about the acronyms, we used ALLCAP name in chaos kind, like DNSChaos or JVMChaos, + // library could not resolve that well, so we just manually do it. + if strings.Contains(str, "Chaos") { + position := strings.Index(str, "Chaos") + return strings.ToLower(str[:position]) + str[position:] + } + return strcase.ToLowerCamel(str) } -const fillingEntryTemplate = ` case Type{{.Type}}: +const spawnObjectEntryTemplate = ` case Type{{.Type}}: result := {{.Type}}{} result.Spec = *it.{{.Type}} - return &result, result.GetObjectMeta(), nil + return &result, nil +` + +const restoreObjectEntryTemplate = ` case *{{.Type}}: + *it.{{.Type}} = chaos.Spec + return nil +` + +func generateMethodItem(typeName, methodTemplate string) string { + tmpl, err := template.New("fillMethodEntry").Parse(methodTemplate) + if err != nil { + log.Error(err, "fail to build template") + return "" + } + + buf := new(bytes.Buffer) + err = tmpl.Execute(buf, &metadata{ + Type: typeName, + }) + if err != nil { + log.Error(err, "fail to execute template") + return "" + } + + return buf.String() +} + +const spawnListEntryTemplate = ` case Type{{.Type}}: + result := {{.Type}}List{} + return &result, nil +` + +func generateSpawnListMethodItem(typeName string) string { + tmpl, err := template.New("fillingMethod").Parse(spawnListEntryTemplate) + if err != nil { + log.Error(err, "fail to build template") + return "" + } + + buf := new(bytes.Buffer) + err = tmpl.Execute(buf, &metadata{ + Type: typeName, + }) + if err != nil { + log.Error(err, "fail to execute template") + return "" + } + + return buf.String() +} + +const genericChaosList = `func (in *{{.Type}}List) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} ` -func generateSpawnMethodItem(typeName string) string { - tmpl, err := template.New("fillingMethod").Parse(fillingEntryTemplate) +func generateGenericChaosList(typeName string) string { + tmpl, err := template.New("genericChaosList").Parse(genericChaosList) if err != nil { log.Error(err, "fail to build template") return "" diff --git a/cmd/chaos-builder/workflow_test.go b/cmd/chaos-builder/workflow_test.go new file mode 100644 index 0000000000..2c83bbd959 --- /dev/null +++ b/cmd/chaos-builder/workflow_test.go @@ -0,0 +1,63 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package main + +import "testing" + +func Test_lowercaseCamelCase(t *testing.T) { + type args struct { + str string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "common", + args: args{ + str: "PodChaos", + }, + want: "podChaos", + }, { + name: "ALLCAP", + args: args{ + str: "DNSChaos", + }, + want: "dnsChaos", + }, { + name: "ALLCAP", + args: args{ + str: "JVMChaos", + }, + want: "jvmChaos", + }, { + name: "workflow", + args: args{ + str: "Workflow", + }, + want: "workflow", + }, + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := lowercaseCamelCase(tt.args.str); got != tt.want { + t.Errorf("lowercaseCamelCase() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/cmd/chaos-controller-manager/main.go b/cmd/chaos-controller-manager/main.go index 7efeb8f00b..4eff37b9b4 100644 --- a/cmd/chaos-controller-manager/main.go +++ b/cmd/chaos-controller-manager/main.go @@ -1,91 +1,62 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package main import ( "flag" + stdlog "log" "net/http" _ "net/http/pprof" "os" - "time" - "golang.org/x/time/rate" - "k8s.io/apimachinery/pkg/runtime" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "github.com/99designs/gqlgen/graphql/handler" + "github.com/99designs/gqlgen/graphql/playground" + fxlogr "github.com/chaos-mesh/fx-logr" + "github.com/go-logr/logr" + "go.uber.org/fx" authorizationv1 "k8s.io/client-go/kubernetes/typed/authorization/v1" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" - "k8s.io/client-go/rest" - "k8s.io/client-go/util/workqueue" ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/log/zap" controllermetrics "sigs.k8s.io/controller-runtime/pkg/metrics" "sigs.k8s.io/controller-runtime/pkg/webhook" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - apiWebhook "github.com/chaos-mesh/chaos-mesh/api/webhook" - _ "github.com/chaos-mesh/chaos-mesh/controllers/awschaos/detachvolume" - _ "github.com/chaos-mesh/chaos-mesh/controllers/awschaos/ec2restart" - _ "github.com/chaos-mesh/chaos-mesh/controllers/awschaos/ec2stop" + "github.com/chaos-mesh/chaos-mesh/cmd/chaos-controller-manager/provider" + "github.com/chaos-mesh/chaos-mesh/controllers" ccfg "github.com/chaos-mesh/chaos-mesh/controllers/config" - _ "github.com/chaos-mesh/chaos-mesh/controllers/dnschaos" - _ "github.com/chaos-mesh/chaos-mesh/controllers/gcpchaos/diskloss" - _ "github.com/chaos-mesh/chaos-mesh/controllers/gcpchaos/nodereset" - _ "github.com/chaos-mesh/chaos-mesh/controllers/gcpchaos/nodestop" - _ "github.com/chaos-mesh/chaos-mesh/controllers/httpchaos" - _ "github.com/chaos-mesh/chaos-mesh/controllers/iochaos" - _ "github.com/chaos-mesh/chaos-mesh/controllers/jvmchaos" - _ "github.com/chaos-mesh/chaos-mesh/controllers/kernelchaos" - "github.com/chaos-mesh/chaos-mesh/controllers/metrics" - _ "github.com/chaos-mesh/chaos-mesh/controllers/networkchaos/partition" - _ "github.com/chaos-mesh/chaos-mesh/controllers/networkchaos/trafficcontrol" - _ "github.com/chaos-mesh/chaos-mesh/controllers/podchaos/containerkill" - _ "github.com/chaos-mesh/chaos-mesh/controllers/podchaos/podfailure" - _ "github.com/chaos-mesh/chaos-mesh/controllers/podchaos/podkill" - "github.com/chaos-mesh/chaos-mesh/controllers/podiochaos" - "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos" - _ "github.com/chaos-mesh/chaos-mesh/controllers/stresschaos" - _ "github.com/chaos-mesh/chaos-mesh/controllers/timechaos" + "github.com/chaos-mesh/chaos-mesh/controllers/types" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon" + ctrlserver "github.com/chaos-mesh/chaos-mesh/pkg/ctrl" grpcUtils "github.com/chaos-mesh/chaos-mesh/pkg/grpc" - "github.com/chaos-mesh/chaos-mesh/pkg/router" + "github.com/chaos-mesh/chaos-mesh/pkg/log" + "github.com/chaos-mesh/chaos-mesh/pkg/metrics" + "github.com/chaos-mesh/chaos-mesh/pkg/selector" "github.com/chaos-mesh/chaos-mesh/pkg/version" - "github.com/chaos-mesh/chaos-mesh/pkg/webhook/config" - "github.com/chaos-mesh/chaos-mesh/pkg/webhook/config/watcher" - wfcontrollers "github.com/chaos-mesh/chaos-mesh/pkg/workflow/controllers" - // +kubebuilder:scaffold:imports + apiWebhook "github.com/chaos-mesh/chaos-mesh/pkg/webhook" ) var ( - scheme = runtime.NewScheme() - setupLog = ctrl.Log.WithName("setup") -) + printVersion bool -var ( - printVersion bool - restConfigQPS, restConfigBurst int + // TODO: create the logger through dependency injection + setupLog = ctrl.Log.WithName("setup") ) -func init() { - _ = clientgoscheme.AddToScheme(scheme) - - _ = v1alpha1.AddToScheme(scheme) - // +kubebuilder:scaffold:scheme -} - func parseFlags() { flag.BoolVar(&printVersion, "version", false, "print version information and exit") - flag.IntVar(&restConfigQPS, "rest-config-qps", 30, "QPS of rest config.") - flag.IntVar(&restConfigBurst, "rest-config-burst", 50, "burst of rest config.") flag.Parse() } @@ -96,86 +67,114 @@ func main() { os.Exit(0) } + rootLogger, err := log.NewDefaultZapLogger() + if err != nil { + stdlog.Fatal("failed to create root logger", err) + } + log.ReplaceGlobals(rootLogger) + ctrl.SetLogger(rootLogger) + fxLogger := rootLogger.WithName("fx") + // set RPCTimeout config grpcUtils.RPCTimeout = ccfg.ControllerCfg.RPCTimeout + app := fx.New( + fx.WithLogger(fxlogr.WithLogr(&fxLogger)), + fx.Supply(controllermetrics.Registry), + fx.Supply(rootLogger), + fx.Provide(metrics.NewChaosControllerManagerMetricsCollector), + fx.Provide(ctrlserver.New), + fx.Options( + provider.Module, + controllers.Module, + selector.Module, + types.ChaosObjects, + types.WebhookObjects, + ), + fx.Invoke(Run), + ) - ctrl.SetLogger(zap.New(zap.UseDevMode(true))) - - options := ctrl.Options{ - Scheme: scheme, - MetricsBindAddress: ccfg.ControllerCfg.MetricsAddr, - LeaderElection: ccfg.ControllerCfg.EnableLeaderElection, - Port: 9443, - } + app.Run() +} - if ccfg.ControllerCfg.ClusterScoped { - setupLog.Info("Chaos controller manager is running in cluster scoped mode.") - // will not specific a certain namespace - } else { - setupLog.Info("Chaos controller manager is running in namespace scoped mode.", "targetNamespace", ccfg.ControllerCfg.TargetNamespace) - options.Namespace = ccfg.ControllerCfg.TargetNamespace - } +// RunParams contains all the parameters needed to run the chaos-controller-manager +type RunParams struct { + fx.In + // Mgr is the controller-runtime Manager to register controllers and webhooks to. + Mgr ctrl.Manager + // Logger is the root logger used in the application. + Logger logr.Logger + // AuthCli is the typed kubernetes authorization client. Required for the authentication webhooks. + AuthCli *authorizationv1.AuthorizationV1Client + // DaemonClientBuilder is the builder/factory for creating chaos daemon clients. + DaemonClientBuilder *chaosdaemon.ChaosDaemonClientBuilder + // MetricsCollector collects metrics for observability. + MetricsCollector *metrics.ChaosControllerManagerMetricsCollector + // CtrlServer is the graphql server for chaosctl. + CtrlServer *handler.Server + + // Objs collects all the kinds of chaos custom resource objects that would be handled by the controller/reconciler. + Objs []types.Object `group:"objs"` + // WebhookObjs collects all the kinds of chaos custom resource objects that would be handled by the validation and mutation webhooks. + WebhookObjs []types.WebhookObject `group:"webhookObjs"` +} - cfg := ctrl.GetConfigOrDie() - setRestConfig(cfg) - mgr, err := ctrl.NewManager(cfg, options) - if err != nil { - setupLog.Error(err, "unable to start manager") - os.Exit(1) - } +// Run is the one of the entrypoints for fx application of chaos-controller-manager. It would bootstrap the +// controller-runtime manager and register all the controllers and webhooks. +// Please notice that Run is NOT the only one entrypoint, every other functions called by fx.Invoke are also entrypoint. +func Run(params RunParams) error { + mgr := params.Mgr + authCli := params.AuthCli + + var err error + for _, obj := range params.Objs { + if !ccfg.ShouldStartWebhook(obj.Name) { + continue + } - authCli, err := authorizationv1.NewForConfig(cfg) - if err != nil { - setupLog.Error(err, "unable to get authorization client") - os.Exit(1) + err = ctrl.NewWebhookManagedBy(mgr). + For(obj.Object). + Complete() + if err != nil { + return err + } } - err = router.SetupWithManagerAndConfigs(mgr, ccfg.ControllerCfg) - if err != nil { - setupLog.Error(err, "fail to setup with manager") - os.Exit(1) - } + for _, obj := range params.WebhookObjs { + if !ccfg.ShouldStartWebhook(obj.Name) { + continue + } - // We only setup webhook for podiochaos, and the logic of applying chaos are in the mutation - // webhook, because we need to get the running result synchronously in io chaos reconciler - v1alpha1.RegisterPodIoHandler(&podiochaos.Handler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("handler").WithName("PodIOChaos"), - }) - if err = (&v1alpha1.PodIoChaos{}).SetupWebhookWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create webhook", "webhook", "PodIOChaos") - os.Exit(1) + err = ctrl.NewWebhookManagedBy(mgr). + For(obj.Object). + Complete() + if err != nil { + return err + } } - // We only setup webhook for podnetworkchaos, and the logic of applying chaos are in the validation - // webhook, because we need to get the running result synchronously in network chaos reconciler - v1alpha1.RegisterRawPodNetworkHandler(&podnetworkchaos.Handler{ - Client: mgr.GetClient(), - Reader: mgr.GetAPIReader(), - Log: ctrl.Log.WithName("handler").WithName("PodNetworkChaos"), - AllowHostNetworkTesting: ccfg.ControllerCfg.AllowHostNetworkTesting, - }) - if err = (&v1alpha1.PodNetworkChaos{}).SetupWebhookWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create webhook", "webhook", "PodNetworkChaos") - os.Exit(1) + if ccfg.ShouldStartWebhook("schedule") { + // setup schedule webhook + err = ctrl.NewWebhookManagedBy(mgr). + For(&v1alpha1.Schedule{}). + Complete() + if err != nil { + return err + } } - // workflow stuff - err = wfcontrollers.BootstrapWorkflowControllers(mgr, ctrl.Log) - if err != nil { - setupLog.Error(err, "failed to setup bootstrap controllers") - os.Exit(1) + if ccfg.ShouldStartWebhook("workflow") { + err = ctrl.NewWebhookManagedBy(mgr). + For(&v1alpha1.Workflow{}). + Complete() + if err != nil { + return err + } } - // Init metrics collector - metricsCollector := metrics.NewChaosCollector(mgr.GetCache(), controllermetrics.Registry) - setupLog.Info("Setting up webhook server") hookServer := mgr.GetWebhookServer() - hookServer.CertDir = ccfg.ControllerCfg.CertsDir - conf := config.NewConfigWatcherConf() - stopCh := ctrl.SetupSignalHandler() + controllerRuntimeSignalHandler := ctrl.SetupSignalHandler() if ccfg.ControllerCfg.PprofAddr != "0" { go func() { @@ -186,118 +185,30 @@ func main() { }() } - if err = ccfg.ControllerCfg.WatcherConfig.Verify(); err != nil { - setupLog.Error(err, "invalid environment configuration") - os.Exit(1) - } - configWatcher, err := watcher.New(*ccfg.ControllerCfg.WatcherConfig, metricsCollector) - if err != nil { - setupLog.Error(err, "unable to create config watcher") - os.Exit(1) + if ccfg.ControllerCfg.CtrlAddr != "" { + go func() { + mutex := http.NewServeMux() + mutex.Handle("/", playground.Handler("GraphQL playground", "/query")) + mutex.Handle("/query", params.CtrlServer) + setupLog.Info("setup ctrlserver", "addr", ccfg.ControllerCfg.CtrlAddr) + setupLog.Error(http.ListenAndServe(ccfg.ControllerCfg.CtrlAddr, mutex), "unable to start ctrlserver") + }() } - go watchConfig(configWatcher, conf, stopCh) - hookServer.Register("/inject-v1-pod", &webhook.Admission{ - Handler: &apiWebhook.PodInjector{ - Config: conf, - ControllerCfg: ccfg.ControllerCfg, - Metrics: metricsCollector, - }}, - ) - hookServer.Register("/validate-auth", &webhook.Admission{ - Handler: apiWebhook.NewAuthValidator(ccfg.ControllerCfg.SecurityMode, mgr.GetClient(), mgr.GetAPIReader(), authCli, - ccfg.ControllerCfg.ClusterScoped, ccfg.ControllerCfg.TargetNamespace, ccfg.ControllerCfg.EnableFilterNamespace), + Handler: apiWebhook.NewAuthValidator(ccfg.ControllerCfg.SecurityMode, authCli, mgr.GetScheme(), + ccfg.ControllerCfg.ClusterScoped, ccfg.ControllerCfg.TargetNamespace, ccfg.ControllerCfg.EnableFilterNamespace, + params.Logger.WithName("validate-auth"), + ), }, ) - // +kubebuilder:scaffold:builder - setupLog.Info("Starting manager") - if err := mgr.Start(stopCh); err != nil { + if err := mgr.Start(controllerRuntimeSignalHandler); err != nil { setupLog.Error(err, "unable to start manager") + // TODO: return the error instead of exit os.Exit(1) } -} - -func setRestConfig(c *rest.Config) { - if restConfigQPS > 0 { - c.QPS = float32(restConfigQPS) - } - if restConfigBurst > 0 { - c.Burst = restConfigBurst - } -} - -func setupWatchQueue(stopCh <-chan struct{}, configWatcher *watcher.K8sConfigMapWatcher) workqueue.Interface { - // watch for reconciliation signals, and grab configmaps, then update the running configuration - // for the server - sigChan := make(chan interface{}, 10) - - queue := workqueue.NewRateLimitingQueue(&workqueue.BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(0.5), 1)}) - go func() { - for { - select { - case <-stopCh: - queue.ShutDown() - return - case <-sigChan: - queue.AddRateLimited(struct{}{}) - } - } - }() - - go func() { - for { - setupLog.Info("Launching watcher for ConfigMaps") - if err := configWatcher.Watch(sigChan, stopCh); err != nil { - switch err { - case watcher.ErrWatchChannelClosed: - // known issue: https://github.com/kubernetes/client-go/issues/334 - setupLog.Info("watcher channel has closed, restart watcher") - default: - setupLog.Error(err, "unable to watch new ConfigMaps") - os.Exit(1) - } - } - - select { - case <-stopCh: - close(sigChan) - return - default: - // sleep 2 seconds to prevent excessive log due to infinite restart - time.Sleep(2 * time.Second) - } - } - }() - - return queue -} - -func watchConfig(configWatcher *watcher.K8sConfigMapWatcher, cfg *config.Config, stopCh <-chan struct{}) { - queue := setupWatchQueue(stopCh, configWatcher) - - for { - item, shutdown := queue.Get() - if shutdown { - break - } - func() { - defer queue.Done(item) - - setupLog.Info("Triggering ConfigMap reconciliation") - updatedInjectionConfigs, err := configWatcher.GetInjectionConfigs() - if err != nil { - setupLog.Error(err, "unable to get ConfigMaps") - return - } - - setupLog.Info("Updating server with newly loaded configurations", - "original configs count", len(cfg.Injections), "updated configs count", len(updatedInjectionConfigs)) - cfg.ReplaceInjectionConfigs(updatedInjectionConfigs) - setupLog.Info("Configuration replaced") - }() - } + return nil } diff --git a/cmd/chaos-controller-manager/provider/controller.go b/cmd/chaos-controller-manager/provider/controller.go new file mode 100644 index 0000000000..3bc23d52b3 --- /dev/null +++ b/cmd/chaos-controller-manager/provider/controller.go @@ -0,0 +1,238 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package provider + +import ( + "context" + "math" + "net" + "strconv" + + "github.com/go-logr/logr" + lru "github.com/hashicorp/golang-lru/v2" + "go.uber.org/fx" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + authorizationv1 "k8s.io/client-go/kubernetes/typed/authorization/v1" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" +) + +var ( + scheme = runtime.NewScheme() +) + +func init() { + _ = clientgoscheme.AddToScheme(scheme) + + _ = v1alpha1.AddToScheme(scheme) + // +kubebuilder:scaffold:scheme +} + +// NewScheme returns the runtime.Scheme used by controller-runtime +func NewScheme() *runtime.Scheme { + return scheme +} + +// NewOption returns the manager.Options for build the controller-runtime Manager +func NewOption(logger logr.Logger, scheme *runtime.Scheme) *ctrl.Options { + setupLog := logger.WithName("setup") + + leaderElectionNamespace := config.ControllerCfg.Namespace + if len(leaderElectionNamespace) == 0 { + leaderElectionNamespace = "default" + } + + options := ctrl.Options{ + // TODO: accept the schema from parameter instead of using scheme directly + Scheme: scheme, + Metrics: metricsserver.Options{ + BindAddress: net.JoinHostPort(config.ControllerCfg.MetricsHost, strconv.Itoa(config.ControllerCfg.MetricsPort)), + }, + LeaderElection: config.ControllerCfg.EnableLeaderElection, + LeaderElectionNamespace: leaderElectionNamespace, + LeaderElectionResourceLock: "leases", + LeaderElectionID: "chaos-mesh", + LeaseDuration: &config.ControllerCfg.LeaderElectLeaseDuration, + RetryPeriod: &config.ControllerCfg.LeaderElectRetryPeriod, + RenewDeadline: &config.ControllerCfg.LeaderElectRenewDeadline, + // Don't aggregate events + EventBroadcaster: record.NewBroadcasterWithCorrelatorOptions(record.CorrelatorOptions{ + MaxEvents: math.MaxInt32, + MaxIntervalInSeconds: 1, + }), + WebhookServer: webhook.NewServer(webhook.Options{ + Host: config.ControllerCfg.WebhookHost, + Port: config.ControllerCfg.WebhookPort, + CertDir: config.ControllerCfg.CertsDir, + }), + } + + if config.ControllerCfg.ClusterScoped { + setupLog.Info("Chaos controller manager is running in cluster scoped mode.") + // will not specific a certain namespace + } else { + setupLog.Info("Chaos controller manager is running in namespace scoped mode.", "targetNamespace", config.ControllerCfg.TargetNamespace) + options.NewCache = func(cfg *rest.Config, opts cache.Options) (cache.Cache, error) { + opts.DefaultNamespaces = map[string]cache.Config{ + config.ControllerCfg.TargetNamespace: {}, + } + return cache.New(cfg, opts) + } + } + + return &options +} + +// NewConfig would fetch the rest.Config from environment. When it failed to fetch config, it would exit the whole application. +func NewConfig() *rest.Config { + return ctrl.GetConfigOrDie() +} + +// NewManager would build the controller-runtime manager with the given parameters. +func NewManager(options *ctrl.Options, cfg *rest.Config) (ctrl.Manager, error) { + if config.ControllerCfg.QPS > 0 { + cfg.QPS = config.ControllerCfg.QPS + } + if config.ControllerCfg.Burst > 0 { + cfg.Burst = config.ControllerCfg.Burst + } + + return ctrl.NewManager(cfg, *options) +} + +// NewAuthCli would build the authorizationv1.AuthorizationV1Client with given parameters. +func NewAuthCli(cfg *rest.Config) (*authorizationv1.AuthorizationV1Client, error) { + + if config.ControllerCfg.QPS > 0 { + cfg.QPS = config.ControllerCfg.QPS + } + if config.ControllerCfg.Burst > 0 { + cfg.Burst = config.ControllerCfg.Burst + } + + return authorizationv1.NewForConfig(cfg) +} + +// NewClient would build the controller-runtime client.Client with given parameters. +func NewClient(mgr ctrl.Manager, scheme *runtime.Scheme) (client.Client, error) { + // TODO: make this size configurable + cache, err := lru.New[string, runtime.Object](100) + if err != nil { + return nil, err + } + return &UpdatedClient{ + client: mgr.GetClient(), + scheme: scheme, + cache: cache, + }, nil +} + +type noCacheReader struct { + fx.Out + + client.Reader `name:"no-cache"` +} + +// NewNoCacheReader builds a client.Reader with no cache. +// TODO: we could return with fx.Annotate instead of struct noCacheReader and magic name "no-cache" +func NewNoCacheReader(mgr ctrl.Manager) noCacheReader { + return noCacheReader{ + Reader: mgr.GetAPIReader(), + } +} + +type controlPlaneCacheReader struct { + fx.Out + + client.Reader `name:"control-plane-cache"` +} + +// NewControlPlaneCacheReader builds a client.Reader with cache for certain usage for control plane +func NewControlPlaneCacheReader(logger logr.Logger, cfg *rest.Config) (controlPlaneCacheReader, error) { + httpClient, err := rest.HTTPClientFor(cfg) + if err != nil { + return controlPlaneCacheReader{}, err + } + mapper, err := apiutil.NewDynamicRESTMapper(cfg, httpClient) + if err != nil { + return controlPlaneCacheReader{}, err + } + + scheme := runtime.NewScheme() + _ = clientgoscheme.AddToScheme(scheme) + + // Create the cache for the cached read client and registering informers + cacheReader, err := cache.New(cfg, cache.Options{ + Scheme: scheme, + Mapper: mapper, + DefaultNamespaces: map[string]cache.Config{ + config.ControllerCfg.Namespace: {}, + }, + }) + if err != nil { + return controlPlaneCacheReader{}, err + } + // TODO: store the channel and use it to stop + // FIXME: goroutine leaks + go func() { + // FIXME: get context from parameter + err := cacheReader.Start(context.TODO()) + if err != nil { + logger.Error(err, "fail to start cached client") + } + }() + + c, err := client.New(cfg, client.Options{Scheme: scheme, Mapper: mapper, Cache: &client.CacheOptions{ + Reader: cacheReader, + DisableFor: nil, + Unstructured: false, + }}) + if err != nil { + return controlPlaneCacheReader{}, err + } + + return controlPlaneCacheReader{ + Reader: c, + }, nil +} + +func NewClientSet(config *rest.Config) (*kubernetes.Clientset, error) { + return kubernetes.NewForConfig(config) +} + +// Module would provide objects to fx for dependency injection. +var Module = fx.Provide( + NewOption, + NewClient, + NewClientSet, + NewManager, + NewAuthCli, + NewScheme, + NewConfig, + NewNoCacheReader, + NewControlPlaneCacheReader, +) diff --git a/cmd/chaos-controller-manager/provider/doc.go b/cmd/chaos-controller-manager/provider/doc.go new file mode 100644 index 0000000000..09721a9fc9 --- /dev/null +++ b/cmd/chaos-controller-manager/provider/doc.go @@ -0,0 +1,17 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package provider provides several required components for bootstrapping chaos-controller-manager. +package provider diff --git a/cmd/chaos-controller-manager/provider/suite_test.go b/cmd/chaos-controller-manager/provider/suite_test.go new file mode 100644 index 0000000000..4faf5e0114 --- /dev/null +++ b/cmd/chaos-controller-manager/provider/suite_test.go @@ -0,0 +1,131 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package provider + +import ( + "context" + "os" + "path/filepath" + "testing" + "time" + + "github.com/go-logr/logr" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "go.uber.org/fx" + k8sScheme "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/test/manager" + "github.com/chaos-mesh/chaos-mesh/pkg/log" +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var app *fx.App +var cfg *rest.Config +var k8sClient client.Client +var mgr ctrl.Manager +var testEnv *envtest.Environment +var setupLog = ctrl.Log.WithName("setup") + +func TestProvider(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Provider suit") +} + +var _ = BeforeSuite(func(ctx SpecContext) { + logf.SetLogger(log.NewZapLoggerWithWriter(GinkgoWriter)) + By("bootstrapping test environment") + t := true + if os.Getenv("USE_EXISTING_CLUSTER") == "true" { + testEnv = &envtest.Environment{ + UseExistingCluster: &t, + } + } else { + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, + } + } + + err := v1alpha1.SchemeBuilder.AddToScheme(k8sScheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + cfg, err = testEnv.Start() + Expect(err).ToNot(HaveOccurred()) + Expect(cfg).ToNot(BeNil()) + + rootLogger, err := log.NewDefaultZapLogger() + Expect(err).ToNot(HaveOccurred()) + + app = fx.New( + fx.Options( + fx.Supply(cfg), + fx.Supply(rootLogger), + fx.Provide( + NewOption, + NewClient, + manager.NewTestManager, + NewAuthCli, + NewScheme, + ), + ), + fx.Populate(&k8sClient), + fx.Populate(&mgr), + fx.Invoke(Run), + ) + startCtx, cancel := context.WithTimeout(context.Background(), app.StartTimeout()) + defer cancel() + Expect(err).ToNot(HaveOccurred()) + Expect(k8sClient).ToNot(BeNil()) + + if err := app.Start(startCtx); err != nil { + setupLog.Error(err, "fail to start manager") + } + Expect(err).ToNot(HaveOccurred()) + +}, NodeTimeout(60*time.Second)) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + stopCtx, cancel := context.WithTimeout(context.Background(), app.StopTimeout()) + defer cancel() + + if err := app.Stop(stopCtx); err != nil { + setupLog.Error(err, "fail to stop manager") + } + err := testEnv.Stop() + Expect(err).ToNot(HaveOccurred()) +}) + +type RunParams struct { + fx.In + + Mgr ctrl.Manager + Logger logr.Logger + Client client.Client +} + +func Run(params RunParams) error { + return nil +} diff --git a/cmd/chaos-controller-manager/provider/updated_client.go b/cmd/chaos-controller-manager/provider/updated_client.go new file mode 100644 index 0000000000..8ee95e5e4b --- /dev/null +++ b/cmd/chaos-controller-manager/provider/updated_client.go @@ -0,0 +1,196 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package provider + +import ( + "context" + "reflect" + "strconv" + + lru "github.com/hashicorp/golang-lru/v2" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" +) + +var _ client.Client = &UpdatedClient{} + +type UpdatedClient struct { + client client.Client + scheme *runtime.Scheme + + cache *lru.Cache[string, runtime.Object] +} + +func (c *UpdatedClient) objectKey(key client.ObjectKey, obj client.Object) (string, error) { + gvk, err := apiutil.GVKForObject(obj, c.scheme) + if err != nil { + return "", err + } + + return gvk.String() + "/" + key.String(), nil +} + +func (c *UpdatedClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + err := c.client.Get(ctx, key, obj) + if err != nil { + return err + } + + objectKey, err := c.objectKey(key, obj) + if err != nil { + return err + } + + cachedObject, ok := c.cache.Get(objectKey) + if ok { + cachedMeta, err := meta.Accessor(cachedObject) + if err != nil { + return nil + } + + objMeta, err := meta.Accessor(obj) + if err != nil { + return nil + } + + cachedResourceVersion, err := strconv.Atoi(cachedMeta.GetResourceVersion()) + if err != nil { + return nil + } + newResourceVersion, err := strconv.Atoi(objMeta.GetResourceVersion()) + if err != nil { + return nil + } + if cachedResourceVersion >= newResourceVersion { + cachedObject := cachedObject.(runtime.Object).DeepCopyObject() + + reflect.ValueOf(obj).Elem().Set(reflect.ValueOf(cachedObject).Elem()) + } + } + + return nil +} + +func (c *UpdatedClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { + return c.client.List(ctx, list, opts...) +} + +func (c *UpdatedClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { + return c.client.Create(ctx, obj, opts...) +} + +func (c *UpdatedClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error { + return c.client.Delete(ctx, obj, opts...) +} + +func (c *UpdatedClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + err := c.client.Update(ctx, obj, opts...) + if err != nil { + return err + } + + err = c.writeCache(obj) + if err != nil { + return err + } + + return nil +} + +func (c *UpdatedClient) writeCache(obj client.Object) error { + objMeta, err := meta.Accessor(obj) + if err != nil { + return nil + } + + objectKey, err := c.objectKey(types.NamespacedName{ + Namespace: objMeta.GetNamespace(), + Name: objMeta.GetName(), + }, obj) + if err != nil { + return err + } + + c.cache.Add(objectKey, obj.DeepCopyObject()) + + return nil +} + +func (c *UpdatedClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { + return c.client.Patch(ctx, obj, patch, opts...) +} + +func (c *UpdatedClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error { + return c.client.DeleteAllOf(ctx, obj, opts...) +} + +func (c *UpdatedClient) Scheme() *runtime.Scheme { + return c.client.Scheme() +} + +func (c *UpdatedClient) RESTMapper() meta.RESTMapper { + return c.client.RESTMapper() +} + +func (c *UpdatedClient) SubResource(subResource string) client.SubResourceClient { + return c.client.SubResource(subResource) +} + +func (c *UpdatedClient) Status() client.StatusWriter { + return &UpdatedStatusWriter{ + statusWriter: c.client.Status(), + client: c, + } +} + +func (c *UpdatedClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) { + return c.client.GroupVersionKindFor(obj) +} + +func (c *UpdatedClient) IsObjectNamespaced(obj runtime.Object) (bool, error) { + return c.client.IsObjectNamespaced(obj) +} + +type UpdatedStatusWriter struct { + statusWriter client.StatusWriter + client *UpdatedClient +} + +func (c *UpdatedStatusWriter) Create(ctx context.Context, obj client.Object, subResource client.Object, opts ...client.SubResourceCreateOption) error { + return c.statusWriter.Create(ctx, obj, subResource, opts...) +} + +func (c *UpdatedStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error { + err := c.statusWriter.Update(ctx, obj, opts...) + if err != nil { + return err + } + + err = c.client.writeCache(obj) + if err != nil { + return err + } + + return nil +} + +func (c *UpdatedStatusWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error { + return c.statusWriter.Patch(ctx, obj, patch, opts...) +} diff --git a/cmd/chaos-controller-manager/provider/updated_client_test.go b/cmd/chaos-controller-manager/provider/updated_client_test.go new file mode 100644 index 0000000000..f1a54c11dd --- /dev/null +++ b/cmd/chaos-controller-manager/provider/updated_client_test.go @@ -0,0 +1,131 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package provider + +import ( + "context" + "strconv" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +var _ = Describe("UpdatedClient", func() { + + BeforeEach(func() { + // Add any setup steps that needs to be executed before each test + }) + + AfterEach(func() { + // Add any teardown steps that needs to be executed after each test + }) + + Context(("UpdatedClient"), func() { + It(("Should create and delete successfully"), func() { + obj := &corev1.ConfigMap{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "default", + Name: "test-configmap-create-delete", + }, + Data: map[string]string{ + "test": "1", + }, + } + err := k8sClient.Create(context.TODO(), obj) + Expect(err).ToNot(HaveOccurred()) + + err = k8sClient.Delete(context.TODO(), obj) + Expect(err).ToNot(HaveOccurred()) + }) + + It("Data should always be updated", func() { + obj := &corev1.ConfigMap{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "default", + Name: "test-configmap-update", + }, + Data: map[string]string{ + "test": "0", + }, + } + err := k8sClient.Create(context.TODO(), obj) + Expect(err).ToNot(HaveOccurred()) + + for i := 0; i <= 200; i++ { + data := strconv.Itoa(i) + + obj.Data["test"] = data + err = k8sClient.Update(context.TODO(), obj) + Expect(err).ToNot(HaveOccurred()) + + err = k8sClient.Get(context.TODO(), types.NamespacedName{ + Namespace: "default", + Name: "test-configmap-update", + }, obj) + Expect(err).ToNot(HaveOccurred()) + + Expect(obj.Data["test"]).To(Equal(data)) + } + + err = k8sClient.Delete(context.TODO(), obj) + Expect(err).ToNot(HaveOccurred()) + }) + + It("Newer data should be returned", func() { + obj := &corev1.ConfigMap{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "default", + Name: "test-configmap-another-update", + }, + Data: map[string]string{ + "test": "0", + }, + } + err := k8sClient.Create(context.TODO(), obj) + Expect(err).ToNot(HaveOccurred()) + + obj.Data["test"] = "1" + err = k8sClient.Update(context.TODO(), obj) + Expect(err).ToNot(HaveOccurred()) + + newObj := &corev1.ConfigMap{} + err = k8sClient.Get(context.TODO(), types.NamespacedName{ + Namespace: "default", + Name: "test-configmap-another-update", + }, newObj) + Expect(err).ToNot(HaveOccurred()) + + Expect(newObj.Data["test"]).To(Equal("1")) + newObj.Data["test"] = "2" + anotherCleanClient := mgr.GetClient() + err = anotherCleanClient.Update(context.TODO(), newObj) + Expect(err).ToNot(HaveOccurred()) + + time.Sleep(1 * time.Second) + newObj = &corev1.ConfigMap{} + err = k8sClient.Get(context.TODO(), types.NamespacedName{ + Namespace: "default", + Name: "test-configmap-another-update", + }, newObj) + Expect(err).ToNot(HaveOccurred()) + Expect(newObj.Data["test"]).To(Equal("2")) + }) + }) +}) diff --git a/cmd/chaos-daemon-helper/main.go b/cmd/chaos-daemon-helper/main.go new file mode 100644 index 0000000000..f023c0f1cf --- /dev/null +++ b/cmd/chaos-daemon-helper/main.go @@ -0,0 +1,40 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package main + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/helper" +) + +var rootCmd = &cobra.Command{ + Use: "cdh [command]", + Short: "cdh is a helper to run some logic in another namespaces/cgroups", + Long: `chaos-daemon sometimes needs to run some logic inside another namespace/cgroup. +We can write these logic inside this helper, and execute them through nsexec.`, +} + +func main() { + rootCmd.AddCommand(helper.NormalizeVolumeNameCmd) + if err := rootCmd.Execute(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/cmd/chaos-daemon/main.go b/cmd/chaos-daemon/main.go index 86ab31847a..1bf26569dd 100644 --- a/cmd/chaos-daemon/main.go +++ b/cmd/chaos-daemon/main.go @@ -1,35 +1,41 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package main import ( "flag" + stdlog "log" "os" + "os/signal" + "syscall" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" + ctrl "sigs.k8s.io/controller-runtime" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients" "github.com/chaos-mesh/chaos-mesh/pkg/fusedev" + "github.com/chaos-mesh/chaos-mesh/pkg/log" + "github.com/chaos-mesh/chaos-mesh/pkg/sysfs" "github.com/chaos-mesh/chaos-mesh/pkg/version" - - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/log/zap" ) var ( - log = ctrl.Log.WithName("chaos-daemon") - conf = &chaosdaemon.Config{Host: "0.0.0.0"} + conf = &chaosdaemon.Config{Host: "0.0.0.0", CrClientConfig: &crclients.CrClientConfig{}} printVersion bool ) @@ -38,7 +44,9 @@ func init() { flag.BoolVar(&printVersion, "version", false, "print version information and exit") flag.IntVar(&conf.GRPCPort, "grpc-port", 31767, "the port which grpc server listens on") flag.IntVar(&conf.HTTPPort, "http-port", 31766, "the port which http server listens on") - flag.StringVar(&conf.Runtime, "runtime", "docker", "current container runtime") + flag.StringVar(&conf.CrClientConfig.Runtime, "runtime", "docker", "current container runtime") + flag.StringVar(&conf.CrClientConfig.SocketPath, "runtime-socket-path", "", "current container runtime socket path") + flag.StringVar(&conf.CrClientConfig.ContainerdNS, "containerd-ns", "k8s.io", "namespace used for containerd") flag.StringVar(&conf.CaCert, "ca", "", "ca certificate of grpc server") flag.StringVar(&conf.Cert, "cert", "", "certificate of grpc server") flag.StringVar(&conf.Key, "key", "", "key of grpc server") @@ -54,22 +62,58 @@ func main() { os.Exit(0) } - ctrl.SetLogger(zap.New(zap.UseDevMode(true))) + rootLogger, err := log.NewDefaultZapLogger() + if err != nil { + stdlog.Fatal("failed to create root logger", err) + } + rootLogger = rootLogger.WithName("chaos-daemon.daemon-server") + log.ReplaceGlobals(rootLogger) + ctrl.SetLogger(rootLogger) reg := prometheus.NewRegistry() reg.MustRegister( - prometheus.NewGoCollector(), - prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}), + // Use collectors as prometheus functions deprecated + collectors.NewGoCollector(), + collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}), ) - log.Info("grant access to /dev/fuse") - err := fusedev.GrantAccess() + rootLogger.Info("grant access to /dev/fuse") + err = fusedev.GrantAccess() if err != nil { - log.Error(err, "fail to grant access to /dev/fuse") + rootLogger.Error(err, "grant access to /dev/fuse") } - if err = chaosdaemon.StartServer(conf, reg); err != nil { - log.Error(err, "failed to start chaos-daemon server") + rootLogger.Info("remount /sys with read-write permission") + err = sysfs.RemountWithOption() + if err != nil { + rootLogger.Error(err, "remount /sys with read-write permission") + } + + server, err := chaosdaemon.BuildServer(conf, reg, rootLogger) + if err != nil { + rootLogger.Error(err, "build chaos-daemon server") os.Exit(1) } + + errs := make(chan error) + go func() { + errs <- server.Start() + }() + + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, + syscall.SIGINT, + syscall.SIGTERM) + + select { + case sig := <-sigc: + rootLogger.Info("received signal", "signal", sig) + case err = <-errs: + if err != nil { + rootLogger.Error(err, "chaos-daemon runtime") + } + } + if err = server.Shutdown(); err != nil { + rootLogger.Error(err, "chaos-daemon shutdown") + } } diff --git a/cmd/chaos-dashboard/main.go b/cmd/chaos-dashboard/main.go index cde198bd74..3228ba3043 100644 --- a/cmd/chaos-dashboard/main.go +++ b/cmd/chaos-dashboard/main.go @@ -1,55 +1,49 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package main import ( + "context" "flag" + stdlog "log" "os" - "go.uber.org/fx" - + fxlogr "github.com/chaos-mesh/fx-logr" _ "github.com/jinzhu/gorm/dialects/mssql" _ "github.com/jinzhu/gorm/dialects/mysql" _ "github.com/jinzhu/gorm/dialects/postgres" _ "github.com/jinzhu/gorm/dialects/sqlite" - + "go.uber.org/fx" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - "github.com/chaos-mesh/chaos-mesh/pkg/apiserver" - "github.com/chaos-mesh/chaos-mesh/pkg/collector" "github.com/chaos-mesh/chaos-mesh/pkg/config" - "github.com/chaos-mesh/chaos-mesh/pkg/store" - "github.com/chaos-mesh/chaos-mesh/pkg/store/dbstore" - "github.com/chaos-mesh/chaos-mesh/pkg/ttlcontroller" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/collector" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/store" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/ttlcontroller" + "github.com/chaos-mesh/chaos-mesh/pkg/log" "github.com/chaos-mesh/chaos-mesh/pkg/version" ) -var ( - log = ctrl.Log.WithName("setup") -) - -var ( - printVersion bool -) - // @title Chaos Mesh Dashboard API -// @version 1.0 -// @description Swagger docs for Chaos Mesh Dashboard. If you encounter any problems with API, please click on the issues link below to report bugs or questions. +// @version 2.5 +// @description Swagger for Chaos Mesh Dashboard. If you encounter any problems with API, please click on the issues link below to report. -// @contact.name Issues +// @contact.name GitHub Issues // @contact.url https://github.com/chaos-mesh/chaos-mesh/issues // @license.name Apache 2.0 @@ -57,6 +51,8 @@ var ( // @BasePath /api func main() { + var printVersion bool + flag.BoolVar(&printVersion, "version", false, "print version information and exit") flag.Parse() @@ -65,30 +61,39 @@ func main() { os.Exit(0) } - ctrl.SetLogger(zap.New(zap.UseDevMode(true))) + rootLogger, err := log.NewDefaultZapLogger() + if err != nil { + stdlog.Fatal("failed to create root logger", err) + } + + ctrl.SetLogger(rootLogger) + mainLog := rootLogger.WithName("main") + fxLogger := rootLogger.WithName("fx") - dashboardConfig, err := config.EnvironChaosDashboard() + dashboardConfig, err := config.GetChaosDashboardEnv() if err != nil { - log.Error(err, "main: invalid ChaosDashboardConfig") + mainLog.Error(err, "invalid ChaosDashboardConfig") os.Exit(1) } dashboardConfig.Version = version.Get().GitVersion - persistTTLConfigParsed, err := config.ParsePersistTTLConfig(dashboardConfig.PersistTTL) + persistTTLConfigParsed, err := dashboardConfig.PersistTTL.Parse() if err != nil { - log.Error(err, "main: invalid PersistTTLConfig") + mainLog.Error(err, "invalid PersistTTLConfig") os.Exit(1) } - controllerRuntimeStopCh := ctrl.SetupSignalHandler() + controllerRuntimeSignalHandlerContext := ctrl.SetupSignalHandler() app := fx.New( + fx.WithLogger(fxlogr.WithLogr(&fxLogger)), + fx.Supply(rootLogger), fx.Provide( - func() (<-chan struct{}, *config.ChaosDashboardConfig, *ttlcontroller.TTLconfig) { - return controllerRuntimeStopCh, dashboardConfig, persistTTLConfigParsed + func() (context.Context, *config.ChaosDashboardConfig, *config.TTLConfig) { + return controllerRuntimeSignalHandlerContext, dashboardConfig, persistTTLConfigParsed }, - dbstore.NewDBStore, - collector.NewServer, - ttlcontroller.NewController, + store.Bootstrap, + collector.Bootstrap, + ttlcontroller.Bootstrap, ), store.Module, apiserver.Module, @@ -97,5 +102,4 @@ func main() { ) app.Run() - <-controllerRuntimeStopCh } diff --git a/cmd/chaosctl/main.go b/cmd/chaosctl/main.go index de59fb17fd..4b7903b85c 100644 --- a/cmd/chaosctl/main.go +++ b/cmd/chaosctl/main.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package main diff --git a/cmd/generate-makefile/doc.go b/cmd/generate-makefile/doc.go new file mode 100644 index 0000000000..87f9f51a6a --- /dev/null +++ b/cmd/generate-makefile/doc.go @@ -0,0 +1,18 @@ +// Copyright 2023 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// This command line tool is used to generate partial Makefiles, such as binary.generated.mk, +// containing targets for building executable binaries. +package main diff --git a/cmd/generate-makefile/funcmaps.go b/cmd/generate-makefile/funcmaps.go new file mode 100644 index 0000000000..afdc9a40e6 --- /dev/null +++ b/cmd/generate-makefile/funcmaps.go @@ -0,0 +1,19 @@ +// Copyright 2023 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import "strings" + +var defaultFuncMap = map[string]interface{}{"StringsJoin": strings.Join} diff --git a/cmd/generate-makefile/generate_binary_makefile.go b/cmd/generate-makefile/generate_binary_makefile.go new file mode 100644 index 0000000000..fae6fae6f0 --- /dev/null +++ b/cmd/generate-makefile/generate_binary_makefile.go @@ -0,0 +1,140 @@ +// Copyright 2023 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package main + +import ( + "bytes" + "fmt" + "os" + "text/template" + + "github.com/pkg/errors" +) + +// binaryGeneratedMkTemplate is the template for the file binary.generated.mk, use binaryGeneratedMkOptions as the context. +const binaryGeneratedMkTemplate = `# Generated by ./cmd/generate-makefile. DO NOT EDIT. + +##@ Generated targets in binary.generated.mk + +{{ .Content -}} + +.PHONY: clean-binary +clean-binary: +{{- range .Recipes }} + rm -f {{ .OutputPath }} +{{- end }} +` + +// binaryRecipeTemplate is the template for one target, use binaryRecipeOptions as the context. +const binaryRecipeTemplate = `.PHONY: {{ .TargetName }} +{{ .TargetName }}: SHELL:=$(RUN_IN_BUILD_SHELL) +{{ .TargetName }}: image-build-env {{ StringsJoin .DependencyTargets " " }} ## {{ .Comment }} +{{- if .UseCGO }} + $(CGO) build -ldflags "$(LDFLAGS)" -tags "${BUILD_TAGS}" -o {{ .OutputPath }} {{ .SourcePath }} +{{- else }} + $(GO) build -ldflags "$(LDFLAGS)" -tags "${BUILD_TAGS}" -o {{ .OutputPath }} {{ .SourcePath }} +{{- end }} + +` + +type binaryRecipeOptions struct { + // TargetName is the name of the makefile target. + TargetName string + // SourcePath is the path to the source file. + SourcePath string + // OutputPath is the path to the output file. + OutputPath string + // UseCGO introduces a CGO_ENABLED=1 environment variable to the build command. + UseCGO bool + // DependencyTargets are the targets that this target depends on. + DependencyTargets []string + // Comment is the comment for the target, do not need to include the leading `##` + Comment string +} + +type binaryGeneratedMkOptions struct { + Recipes []binaryRecipeOptions + Content string +} + +func renderBinaryGeneratedMk(name string, fileTemplate string, binaryRecipeTemplate string, recipes []binaryRecipeOptions) error { + targetFile, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + return errors.Wrap(err, "open file "+name) + } + recipeTemplate, err := template.New(name + " recipe").Funcs(defaultFuncMap).Parse(binaryRecipeTemplate) + if err != nil { + return errors.Wrap(err, "parse "+name+" recipe template") + } + + var buffer bytes.Buffer + for _, recipe := range recipes { + err := recipeTemplate.Execute(&buffer, recipe) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("render recipe in "+name+", recipe: %s", recipe.TargetName)) + } + } + binaryTemplate, err := template.New(name).Parse(fileTemplate) + if err != nil { + return errors.Wrap(err, "parse "+name+" template") + } + err = binaryTemplate.Execute(targetFile, binaryGeneratedMkOptions{ + Recipes: recipes, + Content: buffer.String(), + }) + if err != nil { + return errors.Wrap(err, "render "+name) + } + return nil +} + +// binaryRecipes is the list of binaryRecipes to generate, edit here to build new binaries. +var binaryRecipes = []binaryRecipeOptions{ + { + TargetName: "images/chaos-mesh/bin/chaos-controller-manager", + SourcePath: "cmd/chaos-controller-manager/main.go", + OutputPath: "images/chaos-mesh/bin/chaos-controller-manager", + UseCGO: false, + DependencyTargets: nil, + Comment: "Build binary chaos-controller-manager", + }, { + TargetName: "images/chaos-daemon/bin/chaos-daemon", + SourcePath: "cmd/chaos-daemon/main.go", + OutputPath: "images/chaos-daemon/bin/chaos-daemon", + UseCGO: true, + DependencyTargets: []string{ + "pkg/time/fakeclock/fake_clock_gettime.o", + "pkg/time/fakeclock/fake_gettimeofday.o", + }, + Comment: "Build binary chaos-daemon", + }, { + TargetName: "images/chaos-dashboard/bin/chaos-dashboard", + SourcePath: "cmd/chaos-dashboard/main.go", + OutputPath: "images/chaos-dashboard/bin/chaos-dashboard", + UseCGO: true, + DependencyTargets: []string{ + "ui", + }, + Comment: "Build binary chaos-dashboard", + }, { + TargetName: "images/chaos-daemon/bin/cdh", + SourcePath: "cmd/chaos-daemon-helper/main.go", + OutputPath: "images/chaos-daemon/bin/cdh", + UseCGO: true, + DependencyTargets: nil, + Comment: "Build binary chaos-daemon-helper", + }, +} diff --git a/cmd/generate-makefile/generate_container_image_makefile.go b/cmd/generate-makefile/generate_container_image_makefile.go new file mode 100644 index 0000000000..e3dfbae913 --- /dev/null +++ b/cmd/generate-makefile/generate_container_image_makefile.go @@ -0,0 +1,156 @@ +// Copyright 2023 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "bytes" + "fmt" + "os" + "text/template" + + "github.com/pkg/errors" +) + +// containerImageGeneratedMkTemplate is the template for the file container-image.generated.mk, use containerImageGeneratedMkOptions as the context. +const containerImageGeneratedMkTemplate = `# Generated by ./cmd/generate-makefile. DO NOT EDIT. + +##@ Generated targets in container-image.generated.mk + +.PHONY: image +image-all: {{- range .Recipes }} image-{{.ImageName}} {{- end }} ## Build all container images + +{{ .Content -}} + +.PHONY: clean-image-built +clean-image-built: +{{- range .Recipes }} + rm -f {{ .SourcePath }}/.dockerbuilt +{{- end }} + +` + +// containerImageGeneratedMkTemplate is the template for one target, use containerImageRecipeOptions as the context. +const containerImageRecipeTemplate = `.PHONY: image-{{ .ImageName }} +image-{{ .ImageName }}: {{ .SourcePath }}/.dockerbuilt ## {{ .Comment }} + +{{ .SourcePath }}/.dockerbuilt: SHELL=bash +{{ .SourcePath }}/.dockerbuilt: {{ StringsJoin .DependencyTargets " " }} {{ .SourcePath }}/Dockerfile + $(ROOT)/build/build_image.py {{ .ImageName }} {{ .SourcePath }} + touch {{ .SourcePath }}/.dockerbuilt + +` + +func renderContainerImageGeneratedMk() error { + targetFile, err := os.OpenFile("container-image.generated.mk", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + return errors.Wrap(err, "open file container-image.generated.mk") + } + recipeTemplate, err := template.New("container-image.generated.mk recipe").Funcs(defaultFuncMap).Parse(containerImageRecipeTemplate) + if err != nil { + return errors.Wrap(err, "parse container-image.generated.mk recipe") + } + var buffer bytes.Buffer + for _, recipe := range containerImageRecipes { + err := recipeTemplate.Execute(&buffer, recipe) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("render recipe in container-image.generated.mk, recipe: image-%s", recipe.ImageName)) + } + } + + containerImageTemplate, err := template.New("container-image.generated.mk").Funcs(defaultFuncMap).Parse(containerImageGeneratedMkTemplate) + if err != nil { + return errors.Wrap(err, "parse container-image.generated.mk template") + } + err = containerImageTemplate.Execute(targetFile, containerImageGeneratedMkOptions{ + Recipes: containerImageRecipes, + Content: buffer.String(), + }) + if err != nil { + return errors.Wrap(err, "render container-image.generated.mk") + } + + return nil +} + +type containerImageRecipeOptions struct { + ImageName string + SourcePath string + // DependencyTargets are the targets that this target depends on. + DependencyTargets []string + // Comment is the comment for the target, do not need to include the leading `##` + Comment string +} + +type containerImageGeneratedMkOptions struct { + Recipes []containerImageRecipeOptions + Content string +} + +var containerImageRecipes = []containerImageRecipeOptions{ + { + ImageName: "chaos-daemon", + SourcePath: "images/chaos-daemon", + DependencyTargets: []string{ + "images/chaos-daemon/bin/chaos-daemon", + "images/chaos-daemon/bin/pause", + "images/chaos-daemon/bin/cdh", + }, + Comment: "Build container image for chaos-daemon, ghcr.io/chaos-mesh/chaos-daemon:latest", + }, { + ImageName: "chaos-mesh", + SourcePath: "images/chaos-mesh", + DependencyTargets: []string{"images/chaos-mesh/bin/chaos-controller-manager"}, + Comment: "Build container image for chaos-mesh, ghcr.io/chaos-mesh/chaos-mesh:latest", + }, { + ImageName: "chaos-dashboard", + SourcePath: "images/chaos-dashboard", + DependencyTargets: []string{"images/chaos-dashboard/bin/chaos-dashboard"}, + Comment: "Build container image for chaos-dashboard, ghcr.io/chaos-mesh/chaos-dashboard:latest", + }, { + ImageName: "build-env", + SourcePath: "images/build-env", + DependencyTargets: nil, + Comment: "Build container image for build-env, ghcr.io/chaos-mesh/build-env:latest", + }, { + ImageName: "dev-env", + SourcePath: "images/dev-env", + DependencyTargets: nil, + Comment: "Build container image for dev-env, ghcr.io/chaos-mesh/dev-env:latest", + }, { + ImageName: "e2e-helper", + SourcePath: "e2e-test/cmd/e2e_helper", + DependencyTargets: nil, + Comment: "Build container image for e2e-helper", + }, { + ImageName: "chaos-mesh-e2e", + SourcePath: "e2e-test/image/e2e", + DependencyTargets: []string{ + "e2e-test/image/e2e/manifests", + "e2e-test/image/e2e/chaos-mesh", + "e2e-build", + }, + Comment: "Build container image for running e2e tests", + }, { + ImageName: "chaos-kernel", + SourcePath: "images/chaos-kernel", + DependencyTargets: nil, + Comment: "Build container image for chaos-kernel, ghcr.io/chaos-mesh/chaos-kernel:latest", + }, { + ImageName: "chaos-dlv", + SourcePath: "images/chaos-dlv", + DependencyTargets: nil, + Comment: "Build container image for chaos-dlv", + }, +} diff --git a/cmd/generate-makefile/generate_local_binary_makefile.go b/cmd/generate-makefile/generate_local_binary_makefile.go new file mode 100644 index 0000000000..7362c53f27 --- /dev/null +++ b/cmd/generate-makefile/generate_local_binary_makefile.go @@ -0,0 +1,59 @@ +// Copyright 2023 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package main + +// localBinaryGeneratedMkTemplate is the template for the file local-binary.generated.mk, use binaryGeneratedMkOptions as the context. +const localBinaryGeneratedMkTemplate = `# Generated by ./cmd/generate-makefile. DO NOT EDIT. + +##@ Generated targets in local-binary.generated.mk + +{{ .Content -}} + +.PHONY: clean-local-binary +clean-local-binary: +{{- range .Recipes }} + rm -f {{ .OutputPath }} +{{- end }} +` + +// localBinaryRecipeTemplate is the template for one target, use localBinaryRecipeOptions as the context. +const localBinaryRecipeTemplate = `.PHONY: {{ .OutputPath }} +{{ .TargetName }}: {{ StringsJoin .DependencyTargets " " }} ## {{ .Comment }} +{{- if .UseCGO }} + $(CGO) build -ldflags "$(LDFLAGS)" -tags "${BUILD_TAGS}" -o {{ .OutputPath }} {{ .SourcePath }} +{{- else }} + $(GO) build -ldflags "$(LDFLAGS)" -tags "${BUILD_TAGS}" -o {{ .OutputPath }} {{ .SourcePath }} +{{- end }} + +` + +// localBinaryRecipes is the list of binaryRecipes to generate, edit here to build new binaries. +var localBinaryRecipes = []binaryRecipeOptions{ + { + TargetName: "local/chaos-controller-manager", + SourcePath: "cmd/chaos-controller-manager/main.go", + OutputPath: "bin/chaos-controller-manager", + UseCGO: false, + Comment: "Build binary chaos-controller-manager in local environment", + }, + { + TargetName: "local/chaos-dashboard", + SourcePath: "cmd/chaos-dashboard/main.go", + OutputPath: "bin/chaos-dashboard", + UseCGO: true, + Comment: "Build binary chaos-dashboard in local environment", + }, +} diff --git a/cmd/generate-makefile/main.go b/cmd/generate-makefile/main.go new file mode 100644 index 0000000000..fec4ffd7fc --- /dev/null +++ b/cmd/generate-makefile/main.go @@ -0,0 +1,42 @@ +// Copyright 2023 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package main + +func main() { + var err error + err = renderBinaryGeneratedMk( + "local-binary.generated.mk", + localBinaryGeneratedMkTemplate, + localBinaryRecipeTemplate, + localBinaryRecipes, + ) + if err != nil { + panic(err) + } + err = renderBinaryGeneratedMk( + "binary.generated.mk", + binaryGeneratedMkTemplate, + binaryRecipeTemplate, + binaryRecipes, + ) + if err != nil { + panic(err) + } + err = renderContainerImageGeneratedMk() + if err != nil { + panic(err) + } +} diff --git a/cmd/watchmaker/main_darwin.go b/cmd/watchmaker/main_darwin.go index 5086a3ac1d..1142698261 100644 --- a/cmd/watchmaker/main_darwin.go +++ b/cmd/watchmaker/main_darwin.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package main diff --git a/cmd/watchmaker/main_linux.go b/cmd/watchmaker/main_linux.go index 44f8ee8db9..45b083d048 100644 --- a/cmd/watchmaker/main_linux.go +++ b/cmd/watchmaker/main_linux.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package main @@ -19,16 +21,13 @@ import ( "os" "strings" - "github.com/chaos-mesh/chaos-mesh/pkg/time/utils" - "github.com/go-logr/zapr" "go.uber.org/zap" - "github.com/chaos-mesh/chaos-mesh/pkg/ptrace" - - "github.com/chaos-mesh/chaos-mesh/pkg/version" - + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/tasks" "github.com/chaos-mesh/chaos-mesh/pkg/time" + "github.com/chaos-mesh/chaos-mesh/pkg/time/utils" + "github.com/chaos-mesh/chaos-mesh/pkg/version" ) var ( @@ -50,6 +49,8 @@ func initFlag() { } func main() { + fmt.Println("Watchmaker will not support recovery function in future," + + " please use time attack in chaosd.") initFlag() version.PrintVersionInfo("watchmaker") @@ -63,8 +64,6 @@ func main() { panic(fmt.Sprintf("error while creating zap logger: %v", err)) } log := zapr.NewLogger(zapLog) - ptrace.RegisterLogger(log.WithName("ptrace")) - time.RegisterLogger(log.WithName("time")) clkIds := strings.Split(clockIdsSlice, ",") mask, err := utils.EncodeClkIds(clkIds) @@ -74,7 +73,12 @@ func main() { } log.Info("get clock ids mask", "mask", mask) - err = time.ModifyTime(pid, secDelta, nsecDelta, mask) + s, err := time.GetSkew(log, time.NewConfig(secDelta, nsecDelta, mask)) + if err != nil { + log.Error(err, "error while GetSkew") + os.Exit(1) + } + err = s.Inject(tasks.SysPID(pid)) if err != nil { log.Error(err, "error while modifying time", "pid", pid, "secDelta", secDelta, "nsecDelta", nsecDelta, "mask", mask) diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000000..91c84be44e --- /dev/null +++ b/codecov.yml @@ -0,0 +1,27 @@ +codecov: + require_ci_to_pass: true + +coverage: + precision: 2 + round: down + range: "70...100" + status: + patch: false + project: + default: + target: auto + # Allow the coverage to drop by 5%, and still post a success status. + threshold: 5% + +parsers: + gcov: + branch_detection: + conditional: true + loop: true + method: false + macro: false + +comment: + layout: "diff, flags, files, footer" + behavior: default + require_changes: false diff --git a/config/crd/bases/chaos-mesh.org_awschaos.yaml b/config/crd/bases/chaos-mesh.org_awschaos.yaml index ecb4fdea6c..f84ade0532 100644 --- a/config/crd/bases/chaos-mesh.org_awschaos.yaml +++ b/config/crd/bases/chaos-mesh.org_awschaos.yaml @@ -1,166 +1,174 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: awschaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: AwsChaos - listKind: AwsChaosList + kind: AWSChaos + listKind: AWSChaosList plural: awschaos singular: awschaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: AwsChaos is the Schema for the awschaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: AwsChaosSpec is the content of the specification for an AwsChaos - properties: - action: - description: 'Action defines the specific aws chaos action. Supported - action: ec2-stop / ec2-restart / detach-volume Default action: ec2-stop' - enum: - - ec2-stop - - ec2-restart - - detach-volume - type: string - awsRegion: - description: AwsRegion defines the region of aws. - type: string - deviceName: - description: DeviceName indicates the name of the device. Needed in - detach-volume. - type: string - duration: - description: Duration represents the duration of the chaos action. - type: string - ec2Instance: - description: Ec2Instance indicates the ID of the ec2 instance. - type: string - endpoint: - description: Endpoint indicates the endpoint of the aws server. Just - used it in test now. - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. - type: string - volumeID: - description: EbsVolume indicates the ID of the EBS volume. Needed in - detach-volume. - type: string - required: - - action - - awsRegion - - ec2Instance - type: object - status: - description: AwsChaosStatus represents the status of an AwsChaos - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: AWSChaos is the Schema for the awschaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AWSChaosSpec is the content of the specification for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. Supported + action: ec2-stop / ec2-restart / detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. Needed in + detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws server. Just + used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. Needed + in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + status: + description: AWSChaosStatus represents the status of an AWSChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/config/crd/bases/chaos-mesh.org_azurechaos.yaml b/config/crd/bases/chaos-mesh.org_azurechaos.yaml new file mode 100644 index 0000000000..9db34d55c1 --- /dev/null +++ b/config/crd/bases/chaos-mesh.org_azurechaos.yaml @@ -0,0 +1,175 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: azurechaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: AzureChaos + listKind: AzureChaosList + plural: azurechaos + singular: azurechaos + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: AzureChaos is the Schema for the azurechaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AzureChaosSpec is the content of the specification for an + AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. Supported + action: vm-stop / vm-restart / disk-detach Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the data disk. + Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. It + is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + status: + description: AzureChaosStatus represents the status of an AzureChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} diff --git a/config/crd/bases/chaos-mesh.org_blockchaos.yaml b/config/crd/bases/chaos-mesh.org_blockchaos.yaml new file mode 100644 index 0000000000..68ebcde0fe --- /dev/null +++ b/config/crd/bases/chaos-mesh.org_blockchaos.yaml @@ -0,0 +1,286 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: blockchaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: BlockChaos + listKind: BlockChaosList + plural: blockchaos + singular: blockchaos + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: BlockChaos is the Schema for the blockchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BlockChaosSpec is the content of the specification for a + BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. Supported + action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every io request. + type: string + type: object + duration: + description: Duration represents the duration of the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + status: + description: BlockChaosStatus represents the status of a BlockChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + ids: + additionalProperties: + type: integer + description: InjectionIds always specifies the number of injected + chaos action + type: object + required: + - experiment + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} diff --git a/config/crd/bases/chaos-mesh.org_dnschaos.yaml b/config/crd/bases/chaos-mesh.org_dnschaos.yaml index 1534e925a8..34e6f0730e 100644 --- a/config/crd/bases/chaos-mesh.org_dnschaos.yaml +++ b/config/crd/bases/chaos-mesh.org_dnschaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: dnschaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,249 +12,267 @@ spec: listKind: DNSChaosList plural: dnschaos singular: dnschaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: DNSChaos is the Schema for the networkchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a pod chaos experiment - properties: - action: - description: 'Action defines the specific DNS chaos action. Supported - action: error, random Default action: error' - enum: - - error - - random - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - patterns: - description: "Choose which domain names to take effect, support the - placeholder ? and wildcard *, or the Specified domain name. Note: - \ 1. The wildcard * must be at the end of the string. For example, - chaos-*.org is invalid. 2. if the patterns is empty, will take - effect on all the domain names. For example: \t\tThe value is [\"google.com\", - \"github.*\", \"chaos-mes?.org\"], \t\twill take effect on \"google.com\", - \"github.com\" and \"chaos-mesh.org\"" - items: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: DNSChaos is the Schema for the networkchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a pod chaos experiment + properties: + action: + description: 'Action defines the specific DNS chaos action. Supported + action: error, random Default action: error' + enum: + - error + - random type: string - type: array - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, support the + placeholder ? and wildcard *, or the Specified domain name. Note: + 1. The wildcard * must be at the end of the string. For example, + chaos-*.org is invalid. 2. if the patterns is empty, will take effect + on all the domain names. For example: The value is ["google.com", + "github.*", "chaos-mes?.org"], will take effect on "google.com", + "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - status: - description: Most recently observed status of the chaos experiment about - pods - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + status: + description: Most recently observed status of the chaos experiment about + pods + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/config/crd/bases/chaos-mesh.org_gcpchaos.yaml b/config/crd/bases/chaos-mesh.org_gcpchaos.yaml index 0991c9e978..fa35da0505 100644 --- a/config/crd/bases/chaos-mesh.org_gcpchaos.yaml +++ b/config/crd/bases/chaos-mesh.org_gcpchaos.yaml @@ -1,165 +1,177 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: gcpchaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: GcpChaos - listKind: GcpChaosList + kind: GCPChaos + listKind: GCPChaosList plural: gcpchaos singular: gcpchaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: GcpChaos is the Schema for the gcpchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: GcpChaosSpec is the content of the specification for a GcpChaos - properties: - action: - description: 'Action defines the specific gcp chaos action. Supported - action: node-stop / node-reset / disk-loss Default action: node-stop' - enum: - - node-stop - - node-reset - - disk-loss - type: string - deviceName: - description: The device name of the disk to detach. Needed in disk-loss. - type: string - duration: - description: Duration represents the duration of the chaos action. - type: string - instance: - description: Instance defines the name of the instance - type: string - project: - description: Project defines the name of gcp project. - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. It is - used for GCP credentials. - type: string - zone: - description: Zone defines the zone of gcp project. - type: string - required: - - action - - instance - - project - - zone - type: object - status: - description: GcpChaosStatus represents the status of a GcpChaos - properties: - attachedDiskString: - description: The attached disk info string. Needed in disk-loss. - type: string - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: GCPChaos is the Schema for the gcpchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: GCPChaosSpec is the content of the specification for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. Supported + action: node-stop / node-reset / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed in disk-loss. + items: type: string - nextStart: - description: Next time when this action will be applied again - format: date-time + type: array + duration: + description: Duration represents the duration of the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. It + is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + status: + description: GCPChaosStatus represents the status of a GCPChaos + properties: + attachedDiskStrings: + description: The attached disk info strings. Needed in disk-loss. + items: type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: array + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/config/crd/bases/chaos-mesh.org_httpchaos.yaml b/config/crd/bases/chaos-mesh.org_httpchaos.yaml index b504cfa49c..d1784fad72 100644 --- a/config/crd/bases/chaos-mesh.org_httpchaos.yaml +++ b/config/crd/bases/chaos-mesh.org_httpchaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: httpchaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,269 +12,384 @@ spec: listKind: HTTPChaosList plural: httpchaos singular: httpchaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: HTTPChaos is the Schema for the HTTPchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: delay | abort | mixed Default action: delay' - enum: - - delay - - abort - - mixed - type: string - duration: - description: Duration represents the duration of the chaos action. It - is required when the action is `PodFailureAction`. 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". - type: string - headers: - description: Specifies how the header match will be performed to route - the request. - items: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: HTTPChaos is the Schema for the HTTPchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status code in + response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal numbers, + each with optional fraction and a unit suffix, such as "300ms", + "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", + "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + method: + description: Method is a rule to select target by http method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. properties: - exact_match: - type: string - invert_match: - type: string - name: - type: string - prefix_match: - type: string - present_match: - type: string - range_match: - type: string - regex_match: + body: + description: Body is a rule to patch message body of target. + properties: + type: + description: Type represents the patch type, only support + `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers of target. + For example: `[["Set-Cookie", ""], ["Set-Cookie", + ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries of target(Request + only). For example: `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri path in http request. + type: string + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents in target. + properties: + body: + description: Body is a rule to replace http message body in target. + format: byte type: string - safe_regex_match: + code: + description: Code is a rule to replace http status code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers of target. + The key-value pairs represent header name and header value pairs. + type: object + method: + description: Method is a rule to replace http method in request. type: string - suffix_match: + path: + description: Path is rule to to replace uri path in http request. type: string - required: - - name + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries in http + request. For example, with value `{ "foo": "unknown" }`, the + `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object type: object - type: array - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - percent: - description: 'Percent defines the percentage of injection errors and - provides a number from 0-100. default: 100.' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + request_headers: + additionalProperties: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + description: RequestHeaders is a rule to select target by http headers + in request. The key-value pairs represent header name and header + value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target by http headers + in response. The key-value pairs represent header name and header + value pairs. + type: object + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos if + there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file in secret, + `ca.crt` for example type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: + certName: + description: CertName represents the data name of cert file in + secret, `tls.crt` for example type: string - type: array - nodeSelectors: - additionalProperties: + keyName: + description: KeyName represents the data name of key file in secret, + `tls.key` for example type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: + secretName: + description: SecretName represents the name of required secret + resource type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: + secretNamespace: + description: SecretNamespace represents the namespace of required + secret resource type: string - type: array - pods: - additionalProperties: - items: + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + status: + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. + status: + type: string + type: + type: string + required: + - status + - type type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. IF `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - status: - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + instances: + additionalProperties: + format: int64 + type: integer + description: Instances always specifies podhttpchaos generation or + empty + type: object + required: + - experiment + type: object + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/config/crd/bases/chaos-mesh.org_iochaos.yaml b/config/crd/bases/chaos-mesh.org_iochaos.yaml index d944dd1981..a6aaef0723 100644 --- a/config/crd/bases/chaos-mesh.org_iochaos.yaml +++ b/config/crd/bases/chaos-mesh.org_iochaos.yaml @@ -1,378 +1,399 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: iochaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: IoChaos - listKind: IoChaosList + kind: IOChaos + listKind: IOChaosList plural: iochaos singular: iochaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: IoChaos is the Schema for the iochaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: IoChaosSpec defines the desired state of IoChaos - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: latency / fault / attrOverride / mistake' - enum: - - latency - - fault - - attrOverride - - mistake - type: string - attr: - description: Attr defines the overrided attribution - properties: - atime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - blocks: - format: int64 - type: integer - ctime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - gid: - format: int32 - type: integer - ino: - format: int64 - type: integer - kind: - description: FileType represents type of a file - type: string - mtime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - nlink: - format: int32 - type: integer - perm: - type: integer - rdev: - format: int32 - type: integer - size: - format: int64 - type: integer - uid: - format: int32 - type: integer - type: object - containerName: - description: ContainerName indicates the target container to inject - iochaos in - type: string - delay: - description: Delay defines the value of I/O chaos action delay. A delay - string is a possibly signed sequence of decimal numbers, each with - optional fraction and a unit suffix, such as "300ms". Valid time units - are "ns", "us" (or "µs"), "ms", "s", "m", "h". - type: string - duration: - description: Duration represents the duration of the chaos action. It - is required when the action is `PodFailureAction`. 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". - type: string - errno: - description: 'Errno defines the error code that returned by I/O action. - refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' - format: int32 - type: integer - methods: - description: 'Methods defines the I/O methods for injecting I/O chaos - action. default: all I/O methods.' - items: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: IOChaos is the Schema for the iochaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake type: string - type: array - mistake: - description: Mistake defines what types of incorrectness are injected - to IO operations - properties: - filling: - description: Filling determines what is filled in the miskate data. - enum: - - zero - - random - type: string - maxLength: - description: Max length of each wrong data segment in bytes - format: int64 - minimum: 1 - type: integer - maxOccurrences: - description: There will be [1, MaxOccurrences] segments of wrong - data. - format: int64 - minimum: 1 - type: integer - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - path: - description: Path defines the path of files for injecting I/O chaos - action. - type: string - percent: - description: 'Percent defines the percentage of injection errors and - provides a number from 0-100. default: 100.' - type: integer - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: - type: string - type: array + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer required: - - key - - operator + - nsec + - sec type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action delay. A + delay string is a possibly signed sequence of decimal numbers, each + with optional fraction and a unit suffix, such as "300ms". Valid + time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that returned by I/O action. + refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting I/O chaos + action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness are injected + to IO operations + properties: + filling: + description: Filling determines what is filled in the mistake + data. + enum: + - zero + - random type: string - type: array - pods: - additionalProperties: + maxLength: + description: Max length of each wrong data segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments of wrong + data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting I/O chaos + action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection errors and + provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. IF `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - volumePath: - description: VolumePath represents the mount path of injected volume - type: string - required: - - action - - mode - - selector - - volumePath - type: object - status: - description: IoChaosStatus defines the observed state of IoChaos - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + status: + description: IOChaosStatus defines the observed state of IOChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + instances: + additionalProperties: + format: int64 + type: integer + description: Instances always specifies podiochaos generation or empty + type: object + required: + - experiment + type: object + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/config/crd/bases/chaos-mesh.org_jvmchaos.yaml b/config/crd/bases/chaos-mesh.org_jvmchaos.yaml index cb6a5671f8..1ed95aa1b9 100644 --- a/config/crd/bases/chaos-mesh.org_jvmchaos.yaml +++ b/config/crd/bases/chaos-mesh.org_jvmchaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: jvmchaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,266 +12,311 @@ spec: listKind: JVMChaosList plural: jvmchaos singular: jvmchaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: JVMChaos is the Schema for the jvmchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: JVMChaosSpec defines the desired state of JVMChaos - properties: - action: - description: 'Action defines the specific jvm chaos action. Supported - action: delay;return;script;cfl;oom;ccf;tce;cpf;tde;tpf' - enum: - - delay - - return - - script - - cfl - - oom - - ccf - - tce - - cpf - - tde - - tpf - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - flags: - additionalProperties: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: JVMChaos is the Schema for the jvmchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. Supported + action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql type: string - description: Flags represents the flags of action - type: object - matchers: - additionalProperties: + class: + description: Java class type: string - description: Matchers represents the matching rules for the target - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + type: array + cpuCount: + description: the CPU core number needs to use, only set it when action + is stress + type: integer + database: + description: the match database default value is "", means match all + database + type: string + duration: + description: Duration represents the duration of the chaos action + type: string + exception: + description: the exception which needs to throw for action `exception` + or the exception message needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', unit ms or + the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it when action + is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support 5.X.X(set + to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will generate + one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. type: string - type: array - required: - - key - - operator + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - target: - description: 'Target defines the specific jvm chaos target. Supported - target: servlet;psql;jvm;jedis;http;dubbo;rocketmq;tars;mysql;druid;redisson;rabbitmq;mongodb' - enum: - - servlet - - psql - - jvm - - jedis - - http - - dubbo - - rocketmq - - tars - - mysql - - druid - - redisson - - rabbitmq - - mongodb - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the % of pods to do chaos action - type: string - required: - - action - - mode - - selector - - target - type: object - status: - description: JVMChaosStatus defines the observed state of JVMChaos - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + sqlType: + description: the match sql type default value is "", means match all + SQL type. The value can be 'select', 'insert', 'update', 'delete', + 'replace'. + type: string + table: + description: the match table default value is "", means match all + table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + status: + description: JVMChaosStatus defines the observed state of JVMChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/config/crd/bases/chaos-mesh.org_kernelchaos.yaml b/config/crd/bases/chaos-mesh.org_kernelchaos.yaml index 6217f3f022..c2a656c5c3 100644 --- a/config/crd/bases/chaos-mesh.org_kernelchaos.yaml +++ b/config/crd/bases/chaos-mesh.org_kernelchaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: kernelchaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,298 +12,313 @@ spec: listKind: KernelChaosList plural: kernelchaos singular: kernelchaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: KernelChaos is the Schema for the kernelchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a kernel chaos experiment - properties: - duration: - description: Duration represents the duration of the chaos action - type: string - failKernRequest: - description: FailKernRequest defines the request of kernel injection - properties: - callchain: - description: 'Callchain indicate a special call chain, such as: ext4_mount -> - mount_subtree -> ... -> should_failslab With - an optional set of predicates and an optional set of parameters, - which used with predicates. You can read call chan and predicate - examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples - to learn more. If no special call chain, just keep Callchain empty, - which means it will fail at any call chain with slab alloc (eg: - kmalloc).' - items: - description: Frame defines the function signature and predicate - in function's body - properties: - funcname: - description: Funcname can be find from kernel source or `/proc/kallsyms`, - such as `ext4_mount` - type: string - parameters: - description: Parameters is used with predicate, for example, - if you want to inject slab error in `d_alloc_parallel(struct - dentry *parent, const struct qstr *name)` with a special - name `bananas`, you need to set it to `struct dentry *parent, - const struct qstr *name` otherwise omit it. - type: string - predicate: - description: Predicate will access the arguments of this Frame, - example with Parameters's, you can set it to `STRNCMP(name->name, - "bananas", 8)` to make inject only with it, or omit it to - inject for all d_alloc_parallel call chain. - type: string - type: object - type: array - failtype: - description: 'FailType indicates what to fail, can be set to ''0'' - / ''1'' / ''2'' If `0`, indicates slab to fail (should_failslab) - If `1`, indicates alloc_page to fail (should_fail_alloc_page) - If `2`, indicates bio to fail (should_fail_bio) You can read: 1. - https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html 2. - http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt - to learn more' - format: int32 - maximum: 2 - minimum: 0 - type: integer - headers: - description: 'Headers indicates the appropriate kernel headers you - need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so on' - items: - type: string - type: array - probability: - description: Probability indicates the fails with probability. If - you want 1%, please set this field with 1. - format: int32 - maximum: 100 - minimum: 0 - type: integer - times: - description: Times indicates the max times of fails. - format: int32 - minimum: 0 - type: integer - required: - - failtype - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + versions: + - additionalPrinterColumns: + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: KernelChaos is the Schema for the kernelchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a kernel chaos experiment + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call chain, such as: + ext4_mount -> mount_subtree -> ... -> should_failslab With an + optional set of predicates and an optional set of parameters, + which used with predicates. You can read call chan and predicate + examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep Callchain + empty, which means it will fail at any call chain with slab + alloc (eg: kmalloc).' + items: + description: Frame defines the function signature and predicate + in function's body + properties: + funcname: + description: Funcname can be find from kernel source or + `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, for example, + if you want to inject slab error in `d_alloc_parallel(struct + dentry *parent, const struct qstr *name)` with a special + name `bananas`, you need to set it to `struct dentry *parent, + const struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments of this + Frame, example with Parameters's, you can set it to `STRNCMP(name->name, + "bananas", 8)` to make inject only with it, or omit it + to inject for all d_alloc_parallel call chain. type: string - type: array - required: - - key - - operator + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be set to ''0'' + / ''1'' / ''2'' If `0`, indicates slab to fail (should_failslab) + If `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) You can read: + 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel headers + you need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - failKernRequest - - mode - - selector - type: object - status: - description: Most recently observed status of the kernel chaos experiment - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + status: + description: Most recently observed status of the kernel chaos experiment + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/config/crd/bases/chaos-mesh.org_networkchaos.yaml b/config/crd/bases/chaos-mesh.org_networkchaos.yaml index e66fc2b5d7..2913abf211 100644 --- a/config/crd/bases/chaos-mesh.org_networkchaos.yaml +++ b/config/crd/bases/chaos-mesh.org_networkchaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: networkchaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,474 +12,509 @@ spec: listKind: NetworkChaosList plural: networkchaos singular: networkchaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: NetworkChaos is the Schema for the networkchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a pod chaos experiment - properties: - action: - description: 'Action defines the specific network chaos action. Supported - action: partition, netem, delay, loss, duplicate, corrupt Default - action: delay' - enum: - - netem - - delay - - loss - - duplicate - - corrupt - - partition - - bandwidth - type: string - bandwidth: - description: Bandwidth represents the detail about bandwidth control - action - properties: - buffer: - description: Buffer is the maximum amount of bytes that tokens can - be available for instantaneously. - format: int32 - minimum: 1 - type: integer - limit: - description: Limit is the number of bytes that can be queued waiting - for tokens to become available. - format: int32 - minimum: 1 - type: integer - minburst: - description: Minburst specifies the size of the peakrate bucket. - For perfect accuracy, should be set to the MTU of the interface. If - a peakrate is needed, but some burstiness is acceptable, this - size can be raised. A 3000 byte minburst allows around 3mbit/s - of peakrate, given 1000 byte packets. - format: int32 - minimum: 0 - type: integer - peakrate: - description: Peakrate is the maximum depletion rate of the bucket. - The peakrate does not need to be set, it is only necessary if - perfect millisecond timescale shaping is required. - format: int64 - minimum: 0 - type: integer - rate: - description: Rate is the speed knob. Allows bps, kbps, mbps, gbps, - tbps unit. bps means bytes per second. - type: string - required: - - buffer - - limit - - rate - type: object - corrupt: - description: Corrupt represents the detail about corrupt action - properties: - correlation: - type: string - corrupt: - type: string - required: - - correlation - - corrupt - type: object - delay: - description: Delay represents the detail about delay action - properties: - correlation: - type: string - jitter: - type: string - latency: - type: string - reorder: - description: ReorderSpec defines details of packet reorder. - properties: - correlation: - type: string - gap: - type: integer - reorder: - type: string - required: - - correlation - - gap - - reorder - type: object - required: - - latency - type: object - direction: - description: Direction represents the direction, this applies on netem - and network partition action - enum: - - to - - from - - both - - "" - type: string - duplicate: - description: DuplicateSpec represents the detail about loss action - properties: - correlation: - type: string - duplicate: - type: string - required: - - correlation - - duplicate - type: object - duration: - description: Duration represents the duration of the chaos action - type: string - externalTargets: - description: ExternalTargets represents network targets outside k8s - items: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: NetworkChaos is the Schema for the networkchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a pod chaos experiment + properties: + action: + description: 'Action defines the specific network chaos action. Supported + action: partition, netem, delay, loss, duplicate, corrupt Default + action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth type: string - type: array - loss: - description: Loss represents the detail about loss action - properties: - correlation: - type: string - loss: - type: string - required: - - correlation - - loss - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: + bandwidth: + description: Bandwidth represents the detail about bandwidth control + action + properties: + buffer: + description: Buffer is the maximum amount of bytes that tokens + can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be queued waiting + for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate bucket. + For perfect accuracy, should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness is acceptable, this + size can be raised. A 3000 byte minburst allows around 3mbit/s + of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of the bucket. + The peakrate does not need to be set, it is only necessary if + perfect millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, gbit, + tbit, bps, kbps, mbps, gbps, tbps unit. bps means bytes per + second. type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. properties: - key: - description: key is the label key that the selector applies - to. + correlation: type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. + gap: + type: integer + reorder: type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: - type: string - type: array required: - - key - - operator + - gap + - reorder type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies on netem + and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss action + properties: + correlation: type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: + duplicate: type: string - type: array - nodeSelectors: - additionalProperties: + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: + loss: type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, gbit, + tbit, bps, kbps, mbps, gbps, tbps unit. bps means bytes per + second. type: string - type: array - pods: - additionalProperties: - items: + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - target: - description: Target represents network target, this applies on netem - and network partition action - properties: - mode: - description: TargetMode defines the target selector mode - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - - "" - type: string - selector: - description: TargetSelector defines the target selector - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. + type: array + required: + - key + - operator type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: items: type: string type: array - pods: - additionalProperties: + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this applies on netem + and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: TargetValue is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - mode - - selector - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - status: - description: Most recently observed status of the chaos experiment about - pods - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device to be affected + in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + status: + description: Most recently observed status of the chaos experiment about + pods + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + instances: + additionalProperties: + format: int64 + type: integer + description: Instances always specifies podnetworkchaos generation + or empty + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/config/crd/bases/chaos-mesh.org_physicalmachinechaos.yaml b/config/crd/bases/chaos-mesh.org_physicalmachinechaos.yaml new file mode 100644 index 0000000000..dba9ead76d --- /dev/null +++ b/config/crd/bases/chaos-mesh.org_physicalmachinechaos.yaml @@ -0,0 +1,1091 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: physicalmachinechaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: PhysicalMachineChaos + listKind: PhysicalMachineChaosList + plural: physicalmachinechaos + singular: physicalmachinechaos + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: PhysicalMachineChaos is the Schema for the physical machine chaos + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a physical machine chaos experiment + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one of Address + and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock on which to + act. More clock description in linux kernel can be found in + man page of clock_getres, clock_gettime, clock_settime. Muti + clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. if path not + provided, payload will read/write from/into a temp file, temp + file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will write into + the file path. support unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. if path not + provided, payload will read/write from/into a temp file, temp + file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write into + the file path. support unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. if path not + provided, payload will read/write from/into a temp file, temp + file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write into + the file path. support unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the file. + type: string + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http status code + in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by http status code + in response + type: string + delay: + description: Delay represents the delay of the target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", means match + all database + type: string + exception: + description: The exception which needs to throw for action `exception` + or the exception message needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' or the + latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", means match + all SQL type. The value can be 'select', 'insert', 'update', + 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, will + use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set it when + action is stress + type: integer + mem-type: + description: the memory type need to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: + tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can be accepted, + others will be dropped. only set when the IPProtocol is tcp, + used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: + tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), ms, s, + m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf with this + value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or µs), ms, s, + m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: + tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP address + type: string + rate: + description: The speed of network traffic, allows bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: + tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can be accepted, + others will be dropped. only set when the IPProtocol is tcp, + used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values can be + 'from', 'to'. 'from' means packets coming from the 'IPAddress' + or 'Hostname' and going to your server, 'to' means packets originating + from your server and going to the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of the original + value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string keys and a set + values that used to select physical machines. The key defines + the namespace which physical machine belong, and each value + is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. 0 is + effectively a sleep (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, default + is the total available memory. One can specify the size as % + of total available memory or in units of B, KB/KiB, MB/MiB, + GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of physical machines to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of physical machines + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do chaos + action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + status: + description: Most recently observed status of the chaos experiment + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} diff --git a/config/crd/bases/chaos-mesh.org_physicalmachines.yaml b/config/crd/bases/chaos-mesh.org_physicalmachines.yaml new file mode 100644 index 0000000000..2ce402edd5 --- /dev/null +++ b/config/crd/bases/chaos-mesh.org_physicalmachines.yaml @@ -0,0 +1,47 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: physicalmachines.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: PhysicalMachine + listKind: PhysicalMachineList + plural: physicalmachines + singular: physicalmachine + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PhysicalMachine is the Schema for the physical machine API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a physical machine + properties: + address: + description: Address represents the address of the physical machine + type: string + required: + - address + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/config/crd/bases/chaos-mesh.org_podchaos.yaml b/config/crd/bases/chaos-mesh.org_podchaos.yaml index 1fc747fdcc..fd9dd23ddb 100644 --- a/config/crd/bases/chaos-mesh.org_podchaos.yaml +++ b/config/crd/bases/chaos-mesh.org_podchaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: podchaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,255 +12,263 @@ spec: listKind: PodChaosList plural: podchaos singular: podchaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: PodChaos is the control script`s spec. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a pod chaos experiment - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: pod-kill / pod-failure / container-kill Default action: pod-kill' - enum: - - pod-kill - - pod-failure - - container-kill - type: string - containerName: - description: ContainerName indicates the name of the container. Needed - in container-kill. - type: string - duration: - description: Duration represents the duration of the chaos action. It - is required when the action is `PodFailureAction`. 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". - type: string - gracePeriod: - description: GracePeriod is used in pod-kill action. It represents the - duration in seconds before the pod should be deleted. Value must be - non-negative integer. The default value is zero that indicates delete - immediately. - format: int64 - minimum: 0 - type: integer - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PodChaos is the control script`s spec. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a pod chaos experiment + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: pod-kill / pod-failure / container-kill Default action: + pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + type: array + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It represents + the duration in seconds before the pod should be deleted. Value + must be non-negative integer. The default value is zero that indicates + delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. IF `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - status: - description: Most recently observed status of the chaos experiment about - pods - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + status: + description: Most recently observed status of the chaos experiment about + pods + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/config/crd/bases/chaos-mesh.org_podhttpchaos.yaml b/config/crd/bases/chaos-mesh.org_podhttpchaos.yaml new file mode 100644 index 0000000000..889162287c --- /dev/null +++ b/config/crd/bases/chaos-mesh.org_podhttpchaos.yaml @@ -0,0 +1,237 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: podhttpchaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: PodHttpChaos + listKind: PodHttpChaosList + plural: podhttpchaos + singular: podhttpchaos + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PodHttpChaos is the Schema for the podhttpchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PodHttpChaosSpec defines the desired state of PodHttpChaos. + properties: + rules: + description: Rules are a list of injection rule for http request. + items: + description: PodHttpChaosRule defines the injection rule for http. + properties: + actions: + description: Actions contains rules to inject target. + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, + such as "300ms", "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of + target. + properties: + type: + description: Type represents the patch type, only + support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], + ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", "bar"], + ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http message + body in target. + format: byte + type: string + code: + description: Code is a rule to replace http status code + in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header name + and header value pairs. + type: object + method: + description: Method is a rule to replace http method + in request. + type: string + path: + description: Path is rule to to replace uri path in + http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": + "unknown" }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + type: object + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + selector: + description: Selector contains the rules to select target. + properties: + code: + description: Code is a rule to select target by http status + code in response. + format: int32 + type: integer + method: + description: Method is a rule to select target by http method + in request. + type: string + path: + description: Path is a rule to select target by uri path + in http request. + type: string + port: + description: Port is a rule to select server listening on + specific port. + format: int32 + type: integer + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target by + http headers in request. The key-value pairs represent + header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target + by http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + type: object + source: + description: Source represents the source of current rules + type: string + target: + description: Target is the object to be selected and injected, + . + type: string + required: + - actions + - port + - selector + - target + type: object + type: array + tls: + description: TLS is the tls config, will be override if there are + multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file in secret, + `ca.crt` for example + type: string + certName: + description: CertName represents the data name of cert file in + secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of key file in secret, + `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required secret + resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace of required + secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + type: object + status: + description: PodHttpChaosStatus defines the actual state of PodHttpChaos. + properties: + failedMessage: + type: string + observedGeneration: + format: int64 + type: integer + pid: + description: Pid represents a running tproxy process id. + format: int64 + type: integer + startTime: + description: StartTime represents the start time of a tproxy process. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/chaos-mesh.org_podiochaos.yaml b/config/crd/bases/chaos-mesh.org_podiochaos.yaml index ded2239c36..b48e851305 100644 --- a/config/crd/bases/chaos-mesh.org_podiochaos.yaml +++ b/config/crd/bases/chaos-mesh.org_podiochaos.yaml @@ -1,207 +1,207 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: podiochaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: PodIoChaos - listKind: PodIoChaosList + kind: PodIOChaos + listKind: PodIOChaosList plural: podiochaos singular: podiochaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: PodIoChaos is the Schema for the podiochaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: PodIoChaosSpec defines the desired state of IoChaos - properties: - actions: - description: Actions are a list of IoChaos actions - items: - description: IoChaosAction defines an possible action of IoChaos - properties: - atime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - blocks: - format: int64 - type: integer - ctime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - faults: - description: Faults represents the fault to inject - items: - description: IoFault represents the fault to inject and their - weight + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PodIOChaos is the Schema for the podiochaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PodIOChaosSpec defines the desired state of IOChaos + properties: + actions: + description: Actions are a list of IOChaos actions + items: + description: IOChaosAction defines a possible action of IOChaos + properties: + atime: + description: Timespec represents a time properties: - errno: - format: int32 + nsec: + format: int64 type: integer - weight: - format: int32 + sec: + format: int64 type: integer required: - - errno - - weight + - nsec + - sec type: object - type: array - gid: - format: int32 - type: integer - ino: - format: int64 - type: integer - kind: - description: FileType represents type of a file - type: string - latency: - description: Latency represents the latency to inject - type: string - methods: - description: Methods represents the method that the action will - inject in - items: + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + faults: + description: Faults represents the fault to inject + items: + description: IoFault represents the fault to inject and their + weight + properties: + errno: + format: int32 + type: integer + weight: + format: int32 + type: integer + required: + - errno + - weight + type: object + type: array + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + latency: + description: Latency represents the latency to inject type: string - type: array - mistake: - description: MistakeSpec represents the mistake to inject - properties: - filling: - description: Filling determines what is filled in the miskate - data. - enum: - - zero - - random + methods: + description: Methods represents the method that the action will + inject in + items: type: string - maxLength: - description: Max length of each wrong data segment in bytes - format: int64 - minimum: 1 - type: integer - maxOccurrences: - description: There will be [1, MaxOccurrences] segments of - wrong data. - format: int64 - minimum: 1 - type: integer - type: object - mtime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - nlink: - format: int32 - type: integer - path: - description: Path represents a glob of injecting path - type: string - percent: - description: Percent represents the percent probability of injecting - this action - type: integer - perm: - type: integer - rdev: - format: int32 - type: integer - size: - format: int64 - type: integer - source: - description: Source represents the source of current rules - type: string - type: - description: IoChaosType represents the type of an IoChaos Action - type: string - uid: - format: int32 - type: integer - required: - - path - - percent - - type - type: object - type: array - container: - description: 'TODO: support multiple different container to inject in - one pod' - type: string - pid: - description: Pid represents a running toda process id - format: int64 - type: integer - startTime: - description: StartTime represents the start time of a toda process - format: int64 - type: integer - volumeMountPath: - description: 'VolumeMountPath represents the target mount path It must - be a root of mount path now. TODO: search the mount parent of any - path automatically. TODO: support multiple different volume mount - path in one pod' - type: string - required: - - volumeMountPath - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: array + mistake: + description: MistakeSpec represents the mistake to inject + properties: + filling: + description: Filling determines what is filled in the mistake + data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + path: + description: Path represents a glob of injecting path + type: string + percent: + description: Percent represents the percent probability of injecting + this action + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + source: + description: Source represents the source of current rules + type: string + type: + description: IOChaosType represents the type of IOChaos Action + type: string + uid: + format: int32 + type: integer + required: + - path + - percent + - type + type: object + type: array + container: + description: 'TODO: support multiple different container to inject + in one pod' + type: string + volumeMountPath: + description: 'VolumeMountPath represents the target mount path It + must be a root of mount path now. TODO: search the mount parent + of any path automatically. TODO: support multiple different volume + mount path in one pod' + type: string + required: + - volumeMountPath + type: object + status: + properties: + failedMessage: + type: string + observedGeneration: + format: int64 + type: integer + pid: + description: Pid represents a running toda process id + format: int64 + type: integer + startTime: + description: StartTime represents the start time of a toda process + format: int64 + type: integer + type: object + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: + status: {} diff --git a/config/crd/bases/chaos-mesh.org_podnetworkchaos.yaml b/config/crd/bases/chaos-mesh.org_podnetworkchaos.yaml index e4ffdf8f2b..2b226e8017 100644 --- a/config/crd/bases/chaos-mesh.org_podnetworkchaos.yaml +++ b/config/crd/bases/chaos-mesh.org_podnetworkchaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: podnetworkchaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,272 +12,253 @@ spec: listKind: PodNetworkChaosList plural: podnetworkchaos singular: podnetworkchaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: PodNetworkChaos is the Schema for the PodNetworkChaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a pod chaos experiment - properties: - ipsets: - description: The ipset on the pod - items: - description: RawIPSet represents an ipset on specific pod - properties: - cidrs: - description: The contents of ipset - items: - type: string - type: array - name: - description: The name of ipset - type: string - source: - type: string - required: - - cidrs - - name - - source - type: object - type: array - iptables: - description: The iptables rules on the pod - items: - description: RawIptables represents the iptables rules on specific - pod - properties: - direction: - description: The block direction of this iptables rule - type: string - ipsets: - description: The name of related ipset - items: - type: string - type: array - name: - description: The name of iptables chain - type: string - source: - type: string - required: - - direction - - ipsets - - name - - source - type: object - type: array - tcs: - description: The tc rules on the pod - items: - description: RawTrafficControl represents the traffic control chaos - on specific pod - properties: - bandwidth: - description: Bandwidth represents the detail about bandwidth control - action - properties: - buffer: - description: Buffer is the maximum amount of bytes that tokens - can be available for instantaneously. - format: int32 - minimum: 1 - type: integer - limit: - description: Limit is the number of bytes that can be queued - waiting for tokens to become available. - format: int32 - minimum: 1 - type: integer - minburst: - description: Minburst specifies the size of the peakrate bucket. - For perfect accuracy, should be set to the MTU of the interface. If - a peakrate is needed, but some burstiness is acceptable, - this size can be raised. A 3000 byte minburst allows around - 3mbit/s of peakrate, given 1000 byte packets. - format: int32 - minimum: 0 - type: integer - peakrate: - description: Peakrate is the maximum depletion rate of the - bucket. The peakrate does not need to be set, it is only - necessary if perfect millisecond timescale shaping is required. - format: int64 - minimum: 0 - type: integer - rate: - description: Rate is the speed knob. Allows bps, kbps, mbps, - gbps, tbps unit. bps means bytes per second. - type: string - required: - - buffer - - limit - - rate - type: object - corrupt: - description: Corrupt represents the detail about corrupt action - properties: - correlation: - type: string - corrupt: - type: string - required: - - correlation - - corrupt - type: object - delay: - description: Delay represents the detail about delay action - properties: - correlation: - type: string - jitter: - type: string - latency: - type: string - reorder: - description: ReorderSpec defines details of packet reorder. + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PodNetworkChaos is the Schema for the PodNetworkChaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a pod chaos experiment + properties: + ipsets: + description: The ipset on the pod + items: + description: RawIPSet represents an ipset on specific pod + properties: + cidrAndPorts: + description: The contents of ipset. Only available when IPSetType + is NetPortIPSet. + items: + description: CidrAndPort represents CIDR and port pair properties: - correlation: + cidr: type: string - gap: + port: + maximum: 65535 + minimum: 1 type: integer - reorder: - type: string required: - - correlation - - gap - - reorder + - cidr + - port type: object - required: - - latency - type: object - duplicate: - description: DuplicateSpec represents the detail about loss action - properties: - correlation: - type: string - duplicate: - type: string - required: - - correlation - - duplicate - type: object - ipset: - description: The name of target ipset - type: string - loss: - description: Loss represents the detail about loss action - properties: - correlation: - type: string - loss: - type: string - required: - - correlation - - loss - type: object - source: - description: The name and namespace of the source network chaos - type: string - type: - description: The type of traffic control - type: string - required: - - source - - type - type: object - type: array - type: object - status: - description: Most recently observed status of the chaos experiment about - pods - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: + type: array + cidrs: + description: The contents of ipset. Only available when IPSetType + is NetIPSet. + items: type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: + type: array + ipsetType: + description: IPSetType represents the type of IP set + type: string + name: + description: The name of ipset + type: string + setNames: + description: The contents of ipset. Only available when IPSetType + is SetIPSet. + items: type: string - podIP: + type: array + source: + type: string + required: + - ipsetType + - name + - source + type: object + type: array + iptables: + description: The iptables rules on the pod + items: + description: RawIptables represents the iptables rules on specific + pod + properties: + device: + description: Device represents the network device to be affected. + type: string + direction: + description: The block direction of this iptables rule + type: string + ipsets: + description: The name of related ipset + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + nullable: true + type: array + name: + description: The name of iptables chain + type: string + source: + type: string + required: + - direction + - name + - source + type: object + type: array + tcs: + description: The tc rules on the pod + items: + description: RawTrafficControl represents the traffic control chaos + on specific pod + properties: + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes that + tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be queued + waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate + bucket. For perfect accuracy, should be set to the MTU + of the interface. If a peakrate is needed, but some burstiness + is acceptable, this size can be raised. A 3000 byte minburst + allows around 3mbit/s of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of the + bucket. The peakrate does not need to be set, it is only + necessary if perfect millisecond timescale shaping is + required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + duplicate: + description: DuplicateSpec represents the detail about loss + action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + ipset: + description: The name of target ipset + type: string + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + rate: + description: Rate represents the detail about rate control action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - rate + type: object + source: + description: The name and namespace of the source network chaos + type: string + type: + description: The type of traffic control + type: string + required: + - source + - type + type: object + type: array + type: object + status: + description: Most recently observed status of the chaos experiment about + pods + properties: + failedMessage: + type: string + observedGeneration: + format: int64 + type: integer + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: + status: {} diff --git a/config/crd/bases/chaos-mesh.org_remoteclusters.yaml b/config/crd/bases/chaos-mesh.org_remoteclusters.yaml new file mode 100644 index 0000000000..d32bb37b9d --- /dev/null +++ b/config/crd/bases/chaos-mesh.org_remoteclusters.yaml @@ -0,0 +1,101 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: remoteclusters.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: RemoteCluster + listKind: RemoteClusterList + plural: remoteclusters + singular: remotecluster + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: RemoteCluster defines a remote cluster + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: RemoteClusterSpec defines the specification of a remote cluster + properties: + configOverride: + type: object + x-kubernetes-preserve-unknown-fields: true + kubeConfig: + description: RemoteClusterKubeConfig refers to a secret by which we'll + use to connect remote cluster + properties: + secretRef: + description: RemoteClusterSecretRef refers to a secret in any + namespaces + properties: + key: + type: string + name: + type: string + namespace: + type: string + required: + - key + - name + - namespace + type: object + required: + - secretRef + type: object + namespace: + type: string + version: + type: string + required: + - kubeConfig + - namespace + - version + type: object + status: + properties: + conditions: + description: Conditions represents the current condition of the remote + cluster + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + currentVersion: + type: string + observedGeneration: + format: int64 + type: integer + required: + - currentVersion + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/chaos-mesh.org_schedules.yaml b/config/crd/bases/chaos-mesh.org_schedules.yaml new file mode 100644 index 0000000000..3c26ef09f3 --- /dev/null +++ b/config/crd/bases/chaos-mesh.org_schedules.yaml @@ -0,0 +1,13778 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: schedules.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: Schedule + listKind: ScheduleList + plural: schedules + singular: schedule + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Schedule is the cronly schedule object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ScheduleSpec is the specification of a schedule object + properties: + awsChaos: + description: AWSChaosSpec is the content of the specification for + an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. Supported + action: ec2-stop / ec2-restart / detach-volume Default action: + ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. Needed + in detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws server. + Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. Needed + in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification for + an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. + Supported action: vm-stop / vm-restart / disk-detach Default + action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. Needed in + disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the data + disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification for + a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. + Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every io request. + type: string + type: object + duration: + description: Duration represents the duration of the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + default: Forbid + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos action. Supported + action: error, random Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, support + the placeholder ? and wildcard *, or the Specified domain name. + Note: 1. The wildcard * must be at the end of the string. For + example, chaos-*.org is invalid. 2. if the patterns is empty, + will take effect on all the domain names. For example: The value + is ["google.com", "github.*", "chaos-mes?.org"], will take effect + on "google.com", "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification for + a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. Supported + action: node-stop / node-reset / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status code + in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, such + as "300ms", "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + method: + description: Method is a rule to select target by http method + in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of target. + properties: + type: + description: Type represents the patch type, only support + `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers of + target. For example: `[["Set-Cookie", ""], ["Set-Cookie", + ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries of target(Request + only). For example: `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri path in http + request. + type: string + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents in target. + properties: + body: + description: Body is a rule to replace http message body in + target. + format: byte + type: string + code: + description: Code is a rule to replace http status code in + response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers of + target. The key-value pairs represent header name and header + value pairs. + type: object + method: + description: Method is a rule to replace http method in request. + type: string + path: + description: Path is rule to to replace uri path in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries in + http request. For example, with value `{ "foo": "unknown" + }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target by http + headers in request. The key-value pairs represent header name + and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target by http + headers in response. The key-value pairs represent header name + and header value pairs. + type: object + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file in + secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name of cert file + in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of key file + in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required secret + resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace of required + secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action delay. + A delay string is a possibly signed sequence of decimal numbers, + each with optional fraction and a unit suffix, such as "300ms". + Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that returned by I/O + action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting I/O + chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness are injected + to IO operations + properties: + filling: + description: Filling determines what is filled in the mistake + data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments of + wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting I/O + chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection errors + and provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected + volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. Supported + action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only set it when + action is stress + type: integer + database: + description: the match database default value is "", means match + all database + type: string + duration: + description: Duration represents the duration of the chaos action + type: string + exception: + description: the exception which needs to throw for action `exception` + or the exception message needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', unit ms + or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will generate + one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", means match + all SQL type. The value can be 'select', 'insert', 'update', + 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call chain, such + as: ext4_mount -> mount_subtree -> ... -> should_failslab + With an optional set of predicates and an optional set of + parameters, which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep Callchain + empty, which means it will fail at any call chain with slab + alloc (eg: kmalloc).' + items: + description: Frame defines the function signature and predicate + in function's body + properties: + funcname: + description: Funcname can be find from kernel source + or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, for + example, if you want to inject slab error in `d_alloc_parallel(struct + dentry *parent, const struct qstr *name)` with a special + name `bananas`, you need to set it to `struct dentry + *parent, const struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments of + this Frame, example with Parameters's, you can set + it to `STRNCMP(name->name, "bananas", 8)` to make + inject only with it, or omit it to inject for all + d_alloc_parallel call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be set + to ''0'' / ''1'' / ''2'' If `0`, indicates slab to fail + (should_failslab) If `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) You can + read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel headers + you need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so + on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos action. + Supported action: partition, netem, delay, loss, duplicate, + corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth control + action + properties: + buffer: + description: Buffer is the maximum amount of bytes that tokens + can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be queued + waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate bucket. + For perfect accuracy, should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness is acceptable, + this size can be raised. A 3000 byte minburst allows around + 3mbit/s of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of the + bucket. The peakrate does not need to be set, it is only + necessary if perfect millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies + on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets outside + k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this applies on + netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device to be + affected in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired state of + PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one of Address + and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock on which + to act. More clock description in linux kernel can be found + in man page of clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the file. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + delay: + description: Delay represents the delay of the target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for action + `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', unit + ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", means + match all database + type: string + exception: + description: The exception which needs to throw for action + `exception` or the exception message needs to throw in action + `mysql` + type: string + latency: + description: The latency duration for action 'latency' or + the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, will + use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set it + when action is stress + type: integer + mem-type: + description: the memory type need to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can + be accepted, others will be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf with + this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads to + run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP address + type: string + rate: + description: The speed of network traffic, allows bps, kbps, + mbps, gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can + be accepted, others will be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values can + be 'from', 'to'. 'from' means packets coming from the 'IPAddress' + or 'Hostname' and going to your server, 'to' means packets + originating from your server and going to the 'IPAddress' + or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of the original + value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string keys and + a set values that used to select physical machines. The + key defines the namespace which physical machine belong, + and each value is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. 0 + is effectively a sleep (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, default + is the total available memory. One can specify the size + as % of total available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify + the percent of physical machines the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify + the max percent of pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a user creates + on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: pod-kill / pod-failure / container-kill Default action: + pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It represents + the duration in seconds before the pod should be deleted. Value + must be non-negative integer. The default value is zero that + indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + exclusiveMinimum: true + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors just + like `Stressors` except that it's an experimental feature and + more powerful. You can define stressors in `stress-ng` (see + also `man stress-ng`) dialect, however not all of the supported + stressors are well tested. It maybe retired in later releases. + You should always use `Stressors` to define the stressors and + use this only when you want more stressors unsupported by `Stressors`. + When both `StressngStressors` and `Stressors` are defined, `StressngStressors` + wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported to + stress system components out. You can use one or more of them + to make up various kinds of stresses. At least one of the stressors + should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading per CPU + worker. 0 is effectively a sleep (no load) and 100 is + full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to apply the + stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj of the + stress process. See `man 5 proc` to know more about + this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per vm worker, + default is the total available memory. One can specify + the size as % of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to apply the + stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id All available + options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected program. + It's a possibly signed sequence of decimal numbers, such as + "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + workflow: + properties: + entry: + type: string + templates: + items: + properties: + abortWithStatusCheck: + description: AbortWithStatusCheck describe whether to abort + the workflow when the failure threshold of StatusCheck + is exceeded. Only used when Type is TypeStatusCheck. + type: boolean + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos + action. Supported action: ec2-stop / ec2-restart / + detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. + Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 + instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the + aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. + Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos + action. Supported action: vm-stop / vm-restart / disk-detach + Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. + Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of + the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure + subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos + action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every + io request. + type: string + type: object + duration: + description: Duration represents the duration of the + chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + children: + description: Children describes the children steps of serial + or parallel node. Only used when Type is TypeSerial or + TypeParallel. + items: + type: string + type: array + conditionalBranches: + description: ConditionalBranches describes the conditional + branches of custom tasks. Only used when Type is TypeTask. + items: + properties: + expression: + description: Expression is the expression for this + conditional branch, expected type of result is boolean. + If expression is empty, this branch will always + be selected/the template will be spawned. + type: string + target: + description: Target is the name of other template, + if expression is evaluated as true, this template + will be spawned. + type: string + required: + - target + type: object + type: array + deadline: + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos + action. Supported action: error, random Default action: + error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, + support the placeholder ? and wildcard *, or the Specified + domain name. Note: 1. The wildcard * must be at the + end of the string. For example, chaos-*.org is invalid. + 2. if the patterns is empty, will take effect on all + the domain names. For example: The value is ["google.com", + "github.*", "chaos-mes?.org"], will take effect on + "google.com", "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos + action. Supported action: node-stop / node-reset / + disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed + in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http + status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target + request/response. A duration string is a possibly + unsigned sequence of decimal numbers, each with optional + fraction and a unit suffix, such as "300ms", "2h45m". + Valid time units are "ns", "us" (or "µs"), "ms", "s", + "m", "h". + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + method: + description: Method is a rule to select target by http + method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. + properties: + body: + description: Body is a rule to patch message body + of target. + properties: + type: + description: Type represents the patch type, + only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", + "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri + path in http request. + type: string + port: + description: Port represents the target port to be proxy + of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http message + body in target. + format: byte + type: string + code: + description: Code is a rule to replace http status + code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header + name and header value pairs. + type: object + method: + description: Method is a rule to replace http method + in request. + type: string + path: + description: Path is rule to to replace uri path + in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": + "unknown" }`, the `/?foo=bar` will be altered + to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target + by http headers in request. The key-value pairs represent + header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target + by http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and + injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of + ca file in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name of + cert file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of + key file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required + secret resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace + of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: latency / fault / attrOverride + / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action + delay. A delay string is a possibly signed sequence + of decimal numbers, each with optional fraction and + a unit suffix, such as "300ms". Valid time units are + "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the + chaos action. It is required when the action is `PodFailureAction`. + 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". + type: string + errno: + description: 'Errno defines the error code that returned + by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting + I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled in + the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment + in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting + I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection + errors and provides a number from 0-100. default: + 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path of + injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos + action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only + set it when action is stress + type: integer + database: + description: the match database default value is "", + means match all database + type: string + duration: + description: Duration represents the duration of the + chaos action + type: string + exception: + description: the exception which needs to throw for + action `exception` or the exception message needs + to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set + it when action is stress, the value can be 'stack' + or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only + support 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and + will generate one if not set + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", + means match all SQL type. The value can be 'select', + 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of + KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of + kernel injection + properties: + callchain: + description: 'Callchain indicate a special call + chain, such as: ext4_mount -> mount_subtree -> + ... -> should_failslab With an optional set of + predicates and an optional set of parameters, + which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just + keep Callchain empty, which means it will fail + at any call chain with slab alloc (eg: kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from kernel + source or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab + error in `d_alloc_parallel(struct dentry + *parent, const struct qstr *name)` with + a special name `bananas`, you need to set + it to `struct dentry *parent, const struct + qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments + of this Frame, example with Parameters's, + you can set it to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, or omit + it to inject for all d_alloc_parallel call + chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can + be set to ''0'' / ''1'' / ''2'' If `0`, indicates + slab to fail (should_failslab) If `1`, indicates + alloc_page to fail (should_fail_alloc_page) If + `2`, indicates bio to fail (should_fail_bio) You + can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with + probability. If you want 1%, please set this field + with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + name: + type: string + networkChaos: + description: NetworkChaosSpec defines the desired state + of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos + action. Supported action: partition, netem, delay, + loss, duplicate, corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes + that tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can + be queued waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the + peakrate bucket. For perfect accuracy, should + be set to the MTU of the interface. If a peakrate + is needed, but some burstiness is acceptable, + this size can be raised. A 3000 byte minburst + allows around 3mbit/s of peakrate, given 1000 + byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate + of the bucket. The peakrate does not need to be + set, it is only necessary if perfect millisecond + timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, + kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, + tbps unit. bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt + action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay + action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet + reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to + be affected. + type: string + direction: + default: to + description: Direction represents the direction, this + applies on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about + loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the + chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets + outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control + action + properties: + rate: + description: Rate is the speed knob. Allows bit, + kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, + tbps unit. bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this + applies on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device + to be affected in target scope. + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired + state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only + one of Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock + on which to act. More clock description in linux + kernel can be found in man page of clock_getres, + clock_gettime, clock_settime. Muti clock ids should + be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + payload-process-num: + description: specifies the number of process work + on writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + payload-process-num: + description: specifies the number of process work + on writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the + chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to append + the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to + be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of + the file. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file + to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the + file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by + http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP + connection, we will only attack HTTP connection + with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by + http status code in response + type: string + delay: + description: Delay represents the delay of the target + request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP + connection, we will only attack HTTP connection + with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support + GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw + for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', + unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is + "", means match all database + type: string + exception: + description: The exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' + or the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set to + "8") now + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is + "", means match all SQL type. The value can be + 'select', 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", + means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's + data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only + set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, only + set it when action is stress, the value can be + 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp + flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used for + partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or + µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf + test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client + threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the + IP address + type: string + rate: + description: The speed of network traffic, allows + bps, kbps, mbps, gbps, tbps unit. bps means bytes + per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is + 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp + flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used for + partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means packets + coming from the 'IPAddress' or 'Hostname' and + going to your server, 'to' means packets originating + from your server and going to the 'IPAddress' + or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these + IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering + experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string + keys and a set values that used to select physical + machines. The key defines the namespace which + physical machine belong, and each value is a set + of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU + worker. 0 is effectively a sleep (no load) and + 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, + default is the total available memory. One can + specify the size as % of total available memory + or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of physical machines + to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of physical + machines the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a + user creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: pod-kill / pod-failure / + container-kill Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action. It is required when the action is `PodFailureAction`. + 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. + It represents the duration in seconds before the pod + should be deleted. Value must be non-negative integer. + The default value is zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + description: Schedule describe the Schedule(describing scheduled + chaos) to be injected with chaos nodes. Only used when + Type is TypeSchedule. + properties: + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos + action. Supported action: ec2-stop / ec2-restart + / detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the + device. Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the + ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of + the aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS + volume. Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure + chaos action. Supported action: vm-stop / vm-restart + / disk-detach Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the + disk. Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number + of the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name + of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure + subscription. + type: string + vmName: + description: VMName defines the name of Virtual + Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block + chaos action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of + every io request. + type: string + type: object + duration: + description: Duration represents the duration of + the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state + of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos + action. Supported action: error, random Default + action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take + effect, support the placeholder ? and wildcard + *, or the Specified domain name. Note: 1. The + wildcard * must be at the end of the string. For + example, chaos-*.org is invalid. 2. if the patterns + is empty, will take effect on all the domain names. + For example: The value is ["google.com", "github.*", + "chaos-mes?.org"], will take effect on "google.com", + "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos + action. Supported action: node-stop / node-reset + / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. + Needed in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by + http status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target + request/response. A duration string is a possibly + unsigned sequence of decimal numbers, each with + optional fraction and a unit suffix, such as "300ms", + "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + method: + description: Method is a rule to select target by + http method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. + properties: + body: + description: Body is a rule to patch message + body of target. + properties: + type: + description: Type represents the patch type, + only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http + headers of target. For example: `[["Set-Cookie", + ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri + queries of target(Request only). For example: + `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by + uri path in http request. + type: string + port: + description: Port represents the target port to + be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http + message body in target. + format: byte + type: string + code: + description: Code is a rule to replace http + status code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http + headers of target. The key-value pairs represent + header name and header value pairs. + type: object + method: + description: Method is a rule to replace http + method in request. + type: string + path: + description: Path is rule to to replace uri + path in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri + queries in http request. For example, with + value `{ "foo": "unknown" }`, the `/?foo=bar` + will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select + target by http headers in request. The key-value + pairs represent header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select + target by http headers in response. The key-value + pairs represent header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected + and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override + PodHttpChaos if there are multiple HTTPChaos experiments + are applied + properties: + caName: + description: CAName represents the data name + of ca file in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name + of cert file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name + of key file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name + of required secret resource + type: string + secretNamespace: + description: SecretNamespace represents the + namespace of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of + IOChaos + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: latency / fault / attrOverride + / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos + action delay. A delay string is a possibly signed + sequence of decimal numbers, each with optional + fraction and a unit suffix, such as "300ms". Valid + time units are "ns", "us" (or "µs"), "ms", "s", + "m", "h". + type: string + duration: + description: Duration represents the duration of + the chaos action. It is required when the action + is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that + returned by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for + injecting I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled + in the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment + in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] + segments of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for + injecting I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of + injection errors and provides a number from 0-100. + default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path + of injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state + of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos + action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only + set it when action is stress + type: integer + database: + description: the match database default value is + "", means match all database + type: string + duration: + description: Duration represents the duration of + the chaos action + type: string + exception: + description: the exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only + set it when action is stress, the value can be + 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set to + "8") now + type: string + name: + description: byteman rule name, should be unique, + and will generate one if not set + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action + 'ruleData' + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is + "", means match all SQL type. The value can be + 'select', 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", + means match all table + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state + of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request + of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call + chain, such as: ext4_mount -> mount_subtree + -> ... -> should_failslab With an optional + set of predicates and an optional set of parameters, + which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just + keep Callchain empty, which means it will + fail at any call chain with slab alloc (eg: + kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from + kernel source or `/proc/kallsyms`, such + as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab + error in `d_alloc_parallel(struct dentry + *parent, const struct qstr *name)` with + a special name `bananas`, you need to + set it to `struct dentry *parent, const + struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the + arguments of this Frame, example with + Parameters's, you can set it to `STRNCMP(name->name, + "bananas", 8)` to make inject only with + it, or omit it to inject for all d_alloc_parallel + call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, + can be set to ''0'' / ''1'' / ''2'' If `0`, + indicates slab to fail (should_failslab) If + `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) + You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails + with probability. If you want 1%, please set + this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of + fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state + of NetworkChaos + properties: + action: + description: 'Action defines the specific network + chaos action. Supported action: partition, netem, + delay, loss, duplicate, corrupt Default action: + delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about + bandwidth control action + properties: + buffer: + description: Buffer is the maximum amount of + bytes that tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that + can be queued waiting for tokens to become + available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of + the peakrate bucket. For perfect accuracy, + should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness + is acceptable, this size can be raised. A + 3000 byte minburst allows around 3mbit/s of + peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion + rate of the bucket. The peakrate does not + need to be set, it is only necessary if perfect + millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about + corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay + action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of + packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device + to be affected. + type: string + direction: + default: to + description: Direction represents the direction, + this applies on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail + about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of + the chaos action + type: string + externalTargets: + description: ExternalTargets represents network + targets outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss + action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate + control action + properties: + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this + applies on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network + device to be affected in target scope. + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired + state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. + Only one of Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular + clock on which to act. More clock description + in linux kernel can be found in man page of + clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 is + valid value + type: integer + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 is + valid value + type: integer + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of + the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to + append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to + create or delete. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to + create or delete. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + privilege: + description: Privilege is the file privilege + to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to + be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string + of the file. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + line: + description: Line is the line number of the + file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string + of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of + HTTP connection, we will only attack HTTP + connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + delay: + description: Delay represents the delay of the + target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of + HTTP connection, we will only attack HTTP + connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support + GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw + for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action + 'latency', unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value + is "", means match all database + type: string + exception: + description: The exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action + 'latency' or the latency duration in action + `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set + to "8") now + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value + is "", means match all SQL type. The value + can be 'select', 'insert', 'update', 'delete', + 'replace'. + type: string + table: + description: the match table default value is + "", means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule + file's data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, + only set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, + only set it when action is stress, the value + can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the + tcp flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used + for partition. + type: string + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: + ns, us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the + iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client + threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on + the IP address + type: string + rate: + description: The speed of network traffic, allows + bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the + tcp flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used + for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means packets + coming from the 'IPAddress' or 'Hostname' + and going to your server, 'to' means packets + originating from your server and going to + the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these + IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process + ID + type: string + recoverCmd: + description: the command to be run when recovering + experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical + machines that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string + keys and a set values that used to select + physical machines. The key defines the namespace + which physical machine belong, and each value + is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per + CPU worker. 0 is effectively a sleep (no load) + and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the + stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per + vm worker, default is the total available + memory. One can specify the size as % of total + available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when + attack + type: string + recoverCmd: + description: The command to be executed when + recover + type: string + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of physical + machines to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent + of physical machines the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do + chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that + a user creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: pod-kill / pod-failure + / container-kill Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action. It is required when the action + is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. + It represents the duration in seconds before the + pod should be deleted. Value must be non-negative + integer. The default value is zero that indicates + delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired state + of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of + stressors just like `Stressors` except that it's + an experimental feature and more powerful. You + can define stressors in `stress-ng` (see also + `man stress-ng`) dialect, however not all of the + supported stressors are well tested. It maybe + retired in later releases. You should always use + `Stressors` to define the stressors and use this + only when you want more stressors unsupported + by `Stressors`. When both `StressngStressors` + and `Stressors` are defined, `StressngStressors` + wins. + type: string + stressors: + description: Stressors defines plenty of stressors + supported to stress system components out. You + can use one or more of them to make up various + kinds of stresses. At least one of the stressors + should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading + per CPU worker. 0 is effectively a sleep + (no load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 workers + can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual + memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` + to know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % + of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 workers + can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state + of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock + id All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of + injected program. It's a possibly signed sequence + of decimal numbers, such as "300ms", "-1.5h" or + "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + required: + - schedule + - type + type: object + statusCheck: + description: StatusCheck describe the behavior of StatusCheck. + Only used when Type is TypeStatusCheck. + properties: + duration: + description: Duration defines the duration of the whole + status check if the number of failed execution does + not exceed the failure threshold. Duration is available + to both `Synchronous` and `Continuous` mode. 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum consecutive + failure for the status check to be considered failed. + minimum: 1 + type: integer + http: + properties: + body: + type: string + criteria: + description: Criteria defines how to determine the + result of the status check. + properties: + statusCode: + description: StatusCode defines the expected + http status code for the request. A statusCode + string could be a single code (e.g. 200), + or an inclusive range (e.g. 200-400, both + `200` and `400` are included). + type: string + required: + - statusCode + type: object + headers: + additionalProperties: + items: + type: string + type: array + description: "A Header represents the key-value + pairs in an HTTP header. \n The keys should be + in canonical form, as returned by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in seconds) + to perform an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of the + status check. Support type: Synchronous / Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number + of record to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum consecutive + successes for the status check to be considered successful. + SuccessThreshold only works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of seconds + after which an execution of status check times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check + type. Support type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + stressChaos: + description: StressChaosSpec defines the desired state of + StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors + just like `Stressors` except that it's an experimental + feature and more powerful. You can define stressors + in `stress-ng` (see also `man stress-ng`) dialect, + however not all of the supported stressors are well + tested. It maybe retired in later releases. You should + always use `Stressors` to define the stressors and + use this only when you want more stressors unsupported + by `Stressors`. When both `StressngStressors` and + `Stressors` are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported + to stress system components out. You can use one or + more of them to make up various kinds of stresses. + At least one of the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading + per CPU worker. 0 is effectively a sleep (no + load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to + apply the stressor. Maximum 8192 workers can + run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory + out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` to + know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % of total + available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to + apply the stressor. Maximum 8192 workers can + run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + type: object + task: + description: Task describes the behavior of the custom task. + Only used when Type is TypeTask. + properties: + container: + description: Container is the main container image to + run in the pod + properties: + args: + description: 'Arguments to the entrypoint. The container + image''s CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using + the container''s environment. If a variable cannot + be resolved, the reference in the input string + will be unchanged. Double $$ are reduced to a + single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will + never be expanded, regardless of whether the variable + exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The container image''s ENTRYPOINT is + used if this is not provided. Variable references + $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, + the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot + be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set + in the container. Cannot be updated. + items: + description: EnvVar represents an environment + variable present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined + environment variables in the container and + any service environment variables. If a + variable cannot be resolved, the reference + in the input string will be unchanged. Double + $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal + "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable + exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: + supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the + container: only resources limits and + requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret + in the pod's namespace + properties: + key: + description: The key of the secret + to select from. Must be a valid + secret key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined within + a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container + is starting. When a key exists in multiple sources, + the value associated with the last source will + take precedence. Values defined by an Env with + a duplicate key will take precedence. Cannot be + updated. + items: + description: EnvFromSource represents the source + of a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be a + C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config + management to default or override container images + in workload controllers like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, + Never, IfNotPresent. Defaults to Always if :latest + tag is specified, or IfNotPresent otherwise. Cannot + be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system + should take in response to container lifecycle + events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately + after a container is created. If the handler + fails, the container is terminated and restarted + according to its restart policy. Other management + of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT + supported as a LifecycleHandler and kept + for the backward compatibility. There + are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler + is specified. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately + before a container is terminated due to an + API request or management event such as liveness/startup + probe failure, preemption, resource contention, + etc. The handler is not called if the container + crashes or exits. The Pod''s termination grace + period countdown begins before the PreStop + hook is executed. Regardless of the outcome + of the handler, the container will eventually + terminate within the Pod''s termination grace + period (unless delayed by finalizers). Other + management of the container blocks until the + hook completes or until the termination grace + period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT + supported as a LifecycleHandler and kept + for the backward compatibility. There + are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler + is specified. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as + a DNS_LABEL. Each container in a pod must have + a unique name (DNS_LABEL). Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. + Not specifying a port here DOES NOT prevent that + port from being exposed. Any port which is listening + on the default "0.0.0.0" address inside a container + will be accessible from the network. Modifying + this array with strategic merge patch may corrupt + the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network + port in a single container. + properties: + containerPort: + description: Number of port to expose on the + pod's IP address. This must be a valid port + number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on the + host. If specified, this must be a valid + port number, 0 < x < 65536. If HostNetwork + is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an + IANA_SVC_NAME and unique within the pod. + Each named port in a pod must have a unique + name. Name for the port that can be referred + to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, + TCP, or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service + readiness. Container will be removed from service + endpoints if the probe fails. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents + resource resize policy for the container. + properties: + resourceName: + description: 'Name of the resource to which + this resource resize policy applies. Supported + values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when + specified resource is resized. If not specified, + it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this + container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, + defined in spec.resourceClaims, that are used + by this container. \n This is an alpha field + and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. + It can only be set for containers." + items: + description: ResourceClaim references one + entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available inside + a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. If Requests + is omitted for a container, it defaults to + Limits if that is explicitly specified, otherwise + to an implementation-defined value. Requests + cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + restartPolicy: + description: 'RestartPolicy defines the restart + behavior of individual containers in a pod. This + field may only be set for init containers, and + the only allowed value is "Always". For non-init + containers or when this field is not specified, + the restart behavior is defined by the Pod''s + restart policy and the container type. Setting + the RestartPolicy as "Always" for the init container + will have the following effect: this init container + will be continually restarted on exit until all + regular containers have terminated. Once all regular + containers have completed, all init containers + with restartPolicy "Always" will be shut down. + This lifecycle differs from normal init containers + and is often referred to as a "sidecar" container. + Although this init container still starts in the + init container sequence, it does not wait for + the container to complete before proceeding to + the next init container. Instead, the next init + container starts immediately after this init container + is started, or after any startupProbe has successfully + completed.' + type: string + securityContext: + description: 'SecurityContext defines the security + options the container should be run with. If set, + the fields of SecurityContext override the equivalent + fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges + than its parent process. This bool directly + controls if the no_new_privs flag will be + set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run + as Privileged 2) has CAP_SYS_ADMIN Note that + this field cannot be set when spec.os.name + is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when + running containers. Defaults to the default + set of capabilities granted by the container + runtime. Note that this field cannot be set + when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. + Processes in privileged containers are essentially + equivalent to root on the host. Defaults to + false. Note that this field cannot be set + when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc + mount to use for the containers. The default + is DefaultProcMount which uses the container + runtime defaults for readonly paths and masked + paths. This requires the ProcMountType feature + flag to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only + root filesystem. Default is false. Note that + this field cannot be set when spec.os.name + is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of + the container process. Uses runtime default + if unset. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must + run as a non-root user. If true, the Kubelet + will validate the image at runtime to ensure + that it does not run as UID 0 (root) and fail + to start the container if it does. If unset + or false, no such validation will be performed. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of + the container process. Defaults to user specified + in image metadata if unspecified. May also + be set in PodSecurityContext. If set in both + SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied + to the container. If unspecified, the container + runtime will allocate a random SELinux context + for each container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label + that applies to the container. + type: string + role: + description: Role is a SELinux role label + that applies to the container. + type: string + type: + description: Type is a SELinux type label + that applies to the container. + type: string + user: + description: User is a SELinux user label + that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this + container. If seccomp options are provided + at both the pod & container level, the container + options override the pod options. Note that + this field cannot be set when spec.os.name + is windows. + properties: + localhostProfile: + description: localhostProfile indicates + a profile defined in a file on the node + should be used. The profile must be preconfigured + on the node to work. Must be a descending + path, relative to the kubelet's configured + seccomp profile location. Must be set + if type is "Localhost". Must NOT be set + for any other type. + type: string + type: + description: "type indicates which kind + of seccomp profile will be applied. Valid + options are: \n Localhost - a profile + defined in a file on the node should be + used. RuntimeDefault - the container runtime + default profile should be used. Unconfined + - no profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options + from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where + the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName + field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the + name of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a + container should be run as a 'Host Process' + container. All of a Pod's containers must + have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess + containers and non-HostProcess containers). + In addition, if HostProcess is true then + HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to + run the entrypoint of the container process. + Defaults to the user specified in image + metadata if unspecified. May also be set + in PodSecurityContext. If set in both + SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the Pod + has successfully initialized. If specified, no + other probes are executed until this completes + successfully. If this probe fails, the Pod will + be restarted, just as if the livenessProbe failed. + This can be used to provide different probe parameters + at the beginning of a Pod''s lifecycle, when it + might take a long time to load data or warm a + cache, than during steady-state operation. This + cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. If + this is not set, reads from stdin in the container + will always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should + close the stdin channel after it has been opened + by a single attach. When stdin is true the stdin + stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is + opened on container start, is empty until the + first client attaches to stdin, and then remains + open and accepts data until the client disconnects, + at which time stdin is closed and remains closed + until the container is restarted. If this flag + is false, a container processes that reads from + stdin will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to + which the container''s termination message will + be written is mounted into the container''s filesystem. + Message written is intended to be brief final + status, such as an assertion failure message. + Will be truncated by the node if greater than + 4096 bytes. The total message length across all + containers will be limited to 12kb. Defaults to + /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message + should be populated. File will use the contents + of terminationMessagePath to populate the container + status message on both success and failure. FallbackToLogsOnError + will use the last chunk of container log output + if the termination message file is empty and the + container exited with an error. The log output + is limited to 2048 bytes or 80 lines, whichever + is smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be + true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block + devices to be used by the container. + items: + description: volumeDevice describes a mapping + of a raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside + of the container that the device will be + mapped to. + type: string + name: + description: name must match the name of a + persistentVolumeClaim in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting + of a Volume within a container. + properties: + mountPath: + description: Path within the container at + which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how + mounts are propagated from the host to container + and the other way around. When not set, + MountPropagationNone is used. This field + is beta in 1.10. + type: string + name: + description: This must match the Name of a + Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write + otherwise (false or unspecified). Defaults + to false. + type: boolean + subPath: + description: Path within the volume from which + the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume + from which the container's volume should + be mounted. Behaves similarly to SubPath + but environment variable references $(VAR_NAME) + are expanded using the container's environment. + Defaults to "" (volume's root). SubPathExpr + and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not + specified, the container runtime's default will + be used, which might be configured in the container + image. Cannot be updated. + type: string + required: + - name + type: object + volumes: + description: Volumes is a list of volumes that can be + mounted by containers in a template. + items: + description: Volume represents a named volume in a + pod that may be accessed by any container in the + pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents + an AWS Disk resource that is attached to a kubelet''s + host machine and then exposed to the pod. More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in + the volume that you want to mount. If omitted, + the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify + the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can + leave the property empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force + the readOnly setting in VolumeMounts. More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the + persistent disk resource in AWS (Amazon + EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data + Disk mount on the host and bind mount to the + pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching + mode: None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data + disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk + in the blob storage + type: string + fsType: + description: fsType is Filesystem type to + mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: + multiple blob disks per storage account Dedicated: + single blob disk per storage account Managed: + azure managed data disk (only in managed + availability set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File + Service mount on the host and bind mount to + the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret + that contains Azure Storage Account Name + and Key + type: string + shareName: + description: shareName is the azure share + Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount + on the host that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors + is a collection of Ceph monitors More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the + mounted root, rather than the full Ceph + tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile + is the path to key ring for User, default + is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef + is reference to the authentication secret + for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the + rados user name, default is admin More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume + attached and mounted on kubelets host machine. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points + to a secret object containing parameters + used to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the + volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap + that should populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode + bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. + Directories within the path are not affected + by this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced + ConfigMap will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the ConfigMap, the volume setup will + error unless it is marked optional. Paths + must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether the + ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) + represents ephemeral storage that is handled + by certain external CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI + driver that handles this volume. Consult + with your admin for the correct name as + registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", + "xfs", "ntfs". If not provided, the empty + value is passed to the associated CSI driver + which will determine the default filesystem + to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference + to the secret object containing sensitive + information to pass to the CSI driver to + complete the CSI NodePublishVolume and NodeUnpublishVolume + calls. This field is optional, and may + be empty if no secret is required. If the + secret object contains more than one secret, + all secret references are passed. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only + configuration for the volume. Defaults to + false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. + Consult your driver's documentation for + supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API + about the pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on + created files by default. Must be a Optional: + mode bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. + Directories within the path are not affected + by this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + items: + description: Items is a list of downward API + volume file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used + to set permissions on this file, must + be an octal value between 0000 and + 0777 or a decimal value between 0 + and 511. YAML accepts both octal and + decimal values, JSON requires decimal + values for mode bits. If not specified, + the volume defaultMode will be used. + This might be in conflict with other + options that affect the file mode, + like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file to + be created. Must not be absolute or + contain the ''..'' path. Must be utf-8 + encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env + vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary + directory that shares a pod''s lifetime. More + info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type + of storage medium should back this directory. + The default is "" which means to use the + node''s default medium. Must be an empty + string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount + of local storage required for this EmptyDir + volume. The size limit is also applicable + for memory medium. The maximum usage on + memory medium EmptyDir would be the minimum + value between the SizeLimit specified here + and the sum of memory limits of all containers + in a pod. The default is nil which means + that the limit is undefined. More info: + https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume that + is handled by a cluster storage driver. The + volume's lifecycle is tied to the pod that defines + it - it will be created before the pod starts, + and deleted when the pod is removed. \n Use + this if: a) the volume is only needed while + the pod runs, b) features of normal volumes + like restoring from snapshot or capacity tracking + are needed, c) the storage driver is specified + through a storage class, and d) the storage + driver supports dynamic volume provisioning + through a PersistentVolumeClaim (see EphemeralVolumeSource + for more information on the connection between + this volume type and PersistentVolumeClaim). + \n Use PersistentVolumeClaim or one of the vendor-specific + APIs for volumes that persist for longer than + the lifecycle of an individual pod. \n Use CSI + for light-weight local ephemeral volumes if + the CSI driver is meant to be used that way + - see the documentation of the driver for more + information. \n A pod can use both types of + ephemeral volumes and persistent volumes at + the same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone + PVC to provision the volume. The pod in + which this EphemeralVolumeSource is embedded + will be the owner of the PVC, i.e. the PVC + will be deleted together with the pod. The + name of the PVC will be `-` where `` is the name + from the `PodSpec.Volumes` array entry. + Pod validation will reject the pod if the + concatenated name is not valid for a PVC + (for example, too long). \n An existing + PVC with that name that is not owned by + the pod will *not* be used for the pod to + avoid using an unrelated volume by mistake. + Starting the pod is then blocked until the + unrelated PVC is removed. If such a pre-created + PVC is meant to be used by the pod, the + PVC has to updated with an owner reference + to the pod once the pod exists. Normally + this should not be necessary, but it may + be useful when manually reconstructing a + broken cluster. \n This field is read-only + and no changes will be made by Kubernetes + to the PVC after it has been created. \n + Required, must not be nil." + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when + creating it. No other fields are allowed + and will be rejected during validation. + type: object + spec: + description: The specification for the + PersistentVolumeClaim. The entire content + is copied unchanged into the PVC that + gets created from this template. The + same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: 'accessModes contains + the desired access modes the volume + should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can + be used to specify either: * An + existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external + controller can support the specified + data source, it will create a new + volume based on the contents of + the specified data source. When + the AnyVolumeDataSource feature + gate is enabled, dataSource contents + will be copied to dataSourceRef, + and dataSourceRef contents will + be copied to dataSource when dataSourceRef.namespace + is not specified. If the namespace + is specified, then dataSourceRef + will not be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, + the specified Kind must be in + the core API group. For any + other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies + the object from which to populate + the volume with data, if a non-empty + volume is desired. This may be any + object from a non-empty API group + (non core object) or a PersistentVolumeClaim + object. When this field is specified, + volume binding will only succeed + if the type of the specified object + matches some installed volume populator + or dynamic provisioner. This field + will replace the functionality of + the dataSource field and as such + if both fields are non-empty, they + must have the same value. For backwards + compatibility, when namespace isn''t + specified in dataSourceRef, both + fields (dataSource and dataSourceRef) + will be set to the same value automatically + if one of them is empty and the + other is non-empty. When namespace + is specified in dataSourceRef, dataSource + isn''t set to the same value and + must be empty. There are three important + differences between dataSource and + dataSourceRef: * While dataSource + only allows two specific types of + objects, dataSourceRef allows any + non-core object, as well as PersistentVolumeClaim + objects. * While dataSource ignores + disallowed values (dropping them), + dataSourceRef preserves all values, + and generates an error if a disallowed + value is specified. * While dataSource + only allows local objects, dataSourceRef + allows objects in any namespaces. + (Beta) Using this field requires + the AnyVolumeDataSource feature + gate to be enabled. (Alpha) Using + the namespace field of dataSourceRef + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, + the specified Kind must be in + the core API group. For any + other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + namespace: + description: Namespace is the + namespace of resource being + referenced Note that when a + namespace is specified, a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent + namespace to allow that namespace's + owner to accept the reference. + See the ReferenceGrant documentation + for details. (Alpha) This field + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents + the minimum resources the volume + should have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed + to specify resource requirements + that are lower than previous value + but must still be higher than capacity + recorded in the status field of + the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the + names of resources, defined + in spec.resourceClaims, that + are used by this container. + \n This is an alpha field and + requires enabling the DynamicResourceAllocation + feature gate. \n This field + is immutable. It can only be + set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match + the name of one entry + in pod.spec.resourceClaims + of the Pod where this + field is used. It makes + that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes + the maximum amount of compute + resources allowed. More info: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes + the minimum amount of compute + resources required. If Requests + is omitted for a container, + it defaults to Limits if that + is explicitly specified, otherwise + to an implementation-defined + value. Requests cannot exceed + Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query + over volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a key, + and an operator that relates + the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid + operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In + or NotIn, the values array + must be non-empty. If + the operator is Exists + or DoesNotExist, the values + array must be empty. This + array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a + map of {key,value} pairs. A + single {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator + is "In", and the values array + contains only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName is + the name of the StorageClass required + by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what + type of volume is required by the + claim. Value of Filesystem is implied + when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding + reference to the PersistentVolume + backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource + that is attached to a kubelet's host machine + and then exposed to the pod. + properties: + fsType: + description: 'fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. TODO: how do we prevent + errors in the filesystem from compromising + the machine' + type: string + lun: + description: 'lun is Optional: FC target lun + number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target + worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume world + wide identifiers (wwids) Either wwids or + combination of targetWWNs and lun must be + set, but not both simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume + resource that is provisioned/attached using + an exec based plugin. + properties: + driver: + description: driver is the name of the driver + to use for this volume. + type: string + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". The default filesystem depends + on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field + holds extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef + is reference to the secret object containing + sensitive information to pass to the plugin + scripts. This may be empty if no secret + object is specified. If the secret object + contains more than one secret, all secrets + are passed to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume + attached to a kubelet's host machine. This depends + on the Flocker control service being running + properties: + datasetName: + description: datasetName is Name of the dataset + stored as metadata -> name on the dataset + for Flocker should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the + dataset. This is unique identifier of a + Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE + Disk resource that is attached to a kubelet''s + host machine and then exposed to the pod. More + info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of + the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in + the volume that you want to mount. If omitted, + the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify + the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can + leave the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the + PD resource in GCE. Used to identify the + disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the + ReadOnly setting in VolumeMounts. Defaults + to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository + at a particular revision. DEPRECATED: GitRepo + is deprecated. To provision a container with + a git repo, mount an EmptyDir into an InitContainer + that clones the repo using git, then mount the + EmptyDir into the Pod''s container.' + properties: + directory: + description: directory is the target directory + name. Must not contain or start with '..'. If + '.' is supplied, the volume directory will + be the git repository. Otherwise, if specified, + the volume will contain the git repository + in the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for + the specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name + that details Glusterfs topology. More info: + https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume + path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the + Glusterfs volume to be mounted with read-only + permissions. Defaults to false. More info: + https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing + file or directory on the host machine that is + directly exposed to the container. This is generally + used for system agents or other privileged things + that are allowed to see the host machine. Most + containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can + use host directory mounts and who can/can not + mount host directories as read/write.' + properties: + path: + description: 'path of the directory on the + host. If the path is a symlink, it will + follow the link to the real path. More info: + https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults + to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource + that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether + support iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether + support iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI + Initiator Name. If initiatorName is specified + with iscsiInterface simultaneously, new + iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified + Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface + Name that uses an iSCSI transport. Defaults + to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun + number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal + List. The portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the + ReadOnly setting in VolumeMounts. Defaults + to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret + for iSCSI target and initiator authentication + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target + Portal. The Portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL + and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the + host that shares a pod''s lifetime More info: + https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the + NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the + NFS export to be mounted with read-only + permissions. Defaults to false. More info: + https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP + address of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource + represents a reference to a PersistentVolumeClaim + in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this + volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a + PhotonController persistent disk attached and + mounted on kubelets host machine + properties: + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies + Photon Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx + volume attached and mounted on kubelets host + machine + properties: + fsType: + description: fSType represents the filesystem + type to mount Must be a filesystem type + supported by the host operating system. + Ex. "ext4", "xfs". Implicitly inferred to + be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies + a Portworx volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources + secrets, configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits + used to set permissions on created files + by default. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. Directories within the path are + not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume + projections + items: + description: Projection that may be projected + along with other supported volume types + properties: + configMap: + description: configMap information about + the configMap data to project + properties: + items: + description: items if unspecified, + each key-value pair in the Data + field of the referenced ConfigMap + will be projected into the volume + as a file whose name is the key + and content is the value. If specified, + the listed keys will be projected + into the specified paths, and + unlisted keys will not be present. + If a key is specified which is + not present in the ConfigMap, + the volume setup will error unless + it is marked optional. Paths must + be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key + to a path within a volume. + properties: + key: + description: key is the key + to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an + octal value between 0000 + and 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If + not specified, the volume + defaultMode will be used. + This might be in conflict + with other options that + affect the file mode, like + fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map + the key to. May not be an + absolute path. May not contain + the path element '..'. May + not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information + about the downwardAPI data to project + properties: + items: + description: Items is a list of + DownwardAPIVolume file + items: + description: DownwardAPIVolumeFile + represents information to create + the file containing the pod + field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only + annotations, labels, name + and namespace are supported.' + properties: + apiVersion: + description: Version of + the schema the FieldPath + is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the + field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode + bits used to set permissions + on this file, must be an + octal value between 0000 + and 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If + not specified, the volume + defaultMode will be used. + This might be in conflict + with other options that + affect the file mode, like + fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path + is the relative path name + of the file to be created. + Must not be absolute or + contain the ''..'' path. + Must be utf-8 encoded. The + first item of the relative + path must not start with + ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource + of the container: only resources + limits and requests (limits.cpu, + limits.memory, requests.cpu + and requests.memory) are + currently supported.' + properties: + containerName: + description: 'Container + name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies + the output format of + the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: + resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about + the secret data to project + properties: + items: + description: items if unspecified, + each key-value pair in the Data + field of the referenced Secret + will be projected into the volume + as a file whose name is the key + and content is the value. If specified, + the listed keys will be projected + into the specified paths, and + unlisted keys will not be present. + If a key is specified which is + not present in the Secret, the + volume setup will error unless + it is marked optional. Paths must + be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key + to a path within a volume. + properties: + key: + description: key is the key + to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an + octal value between 0000 + and 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If + not specified, the volume + defaultMode will be used. + This might be in conflict + with other options that + affect the file mode, like + fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map + the key to. May not be an + absolute path. May not contain + the path element '..'. May + not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: optional field specify + whether the Secret or its key + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is + information about the serviceAccountToken + data to project + properties: + audience: + description: audience is the intended + audience of the token. A recipient + of a token must identify itself + with an identifier specified in + the audience of the token, and + otherwise should reject the token. + The audience defaults to the identifier + of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is + the requested duration of validity + of the service account token. + As the token approaches expiration, + the kubelet volume plugin will + proactively rotate the service + account token. The kubelet will + start trying to rotate the token + if the token is older than 80 + percent of its time to live or + if the token is older than 24 + hours.Defaults to 1 hour and must + be at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative + to the mount point of the file + to project the token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount + on the host that shares a pod's lifetime + properties: + group: + description: group to map volume access to + Default is no group + type: string + readOnly: + description: readOnly here will force the + Quobyte volume to be mounted with read-only + permissions. Defaults to false. + type: boolean + registry: + description: registry represents a single + or multiple Quobyte Registry services specified + as a string as host:port pair (multiple + entries are separated with commas) which + acts as the central registry for volumes + type: string + tenant: + description: tenant owning the given Quobyte + volume in the Backend Used with dynamically + provisioned Quobyte volumes, value is set + by the plugin + type: string + user: + description: user to map volume access to + Defaults to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + image: + description: 'image is the rados image name. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring + for RBDUser. Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of + Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. + Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the + ReadOnly setting in VolumeMounts. Defaults + to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides + keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. + Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of + the ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name + of the ScaleIO Protection Domain for the + configured storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret + for ScaleIO user and other sensitive information. + If this is not provided, Login operation + will fail. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable + SSL communication with Gateway, default + false + type: boolean + storageMode: + description: storageMode indicates whether + the storage for a volume should be ThickProvisioned + or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage + Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage + system as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume + already created in the ScaleIO system that + is associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that + should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode + bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. + Directories within the path are not affected + by this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + items: + description: items If unspecified, each key-value + pair in the Data field of the referenced + Secret will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the Secret, the volume setup will error + unless it is marked optional. Paths must + be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether + the Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the + secret in the pod''s namespace to use. More + info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret + to use for obtaining the StorageOS API credentials. If + not specified, default values will be attempted. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable + name of the StorageOS volume. Volume names + are only unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the + scope of the volume within StorageOS. If + no namespace is specified then the Pod's + namespace will be used. This allows the + Kubernetes name scoping to be mirrored within + StorageOS for tighter integration. Set VolumeName + to any name to override the default behaviour. + Set to "default" if you are not using namespaces + within StorageOS. Namespaces that do not + pre-exist within StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere + volume attached and mounted on kubelets host + machine + properties: + fsType: + description: fsType is filesystem type to + mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage + Policy Based Management (SPBM) profile ID + associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage + Policy Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + templateType: + type: string + timeChaos: + description: TimeChaosSpec defines the desired state of + TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id + All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected + program. It's a possibly signed sequence of decimal + numbers, such as "300ms", "-1.5h" or "2h45m". Valid + time units are "ns", "us" (or "µs"), "ms", "s", "m", + "h". + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + required: + - name + - templateType + type: object + type: array + required: + - entry + - templates + type: object + required: + - schedule + - type + type: object + status: + description: ScheduleStatus is the status of a schedule object + properties: + active: + items: + description: "ObjectReference contains enough information to let + you inspect or modify the referred object. --- New uses of this + type are discouraged because of difficulty describing its usage + when embedded in APIs. 1. Ignored fields. It includes many fields + which are not generally honored. For instance, ResourceVersion + and FieldPath are both very rarely valid in actual usage. 2. Invalid + usage help. It is impossible to add specific help for individual + usage. In most embedded usages, there are particular restrictions + like, \"must refer only to types A and B\" or \"UID not honored\" + or \"name must be restricted\". Those cannot be well described + when embedded. 3. Inconsistent validation. Because the usages + are different, the validation rules are different by usage, which + makes it hard for users to predict what will happen. 4. The fields + are both imprecise and overly precise. Kind is not a precise + mapping to a URL. This can produce ambiguity during interpretation + and require a REST mapping. In most cases, the dependency is + on the group,resource tuple and the version of the actual struct + is irrelevant. 5. We cannot easily change it. Because this type + is embedded in many locations, updates to this type will affect + numerous schemas. Don't make new APIs embed an underspecified + API type they do not control. \n Instead of using this type, create + a locally provided and used type that is well-focused on your + reference. For example, ServiceReferences for admission registration: + https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + time: + format: date-time + nullable: true + type: string + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/config/crd/bases/chaos-mesh.org_statuschecks.yaml b/config/crd/bases/chaos-mesh.org_statuschecks.yaml new file mode 100644 index 0000000000..dcea06ed85 --- /dev/null +++ b/config/crd/bases/chaos-mesh.org_statuschecks.yaml @@ -0,0 +1,195 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: statuschecks.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: StatusCheck + listKind: StatusCheckList + plural: statuschecks + singular: statuscheck + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a status check + properties: + duration: + description: Duration defines the duration of the whole status check + if the number of failed execution does not exceed the failure threshold. + Duration is available to both `Synchronous` and `Continuous` mode. + 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum consecutive failure + for the status check to be considered failed. + minimum: 1 + type: integer + http: + properties: + body: + type: string + criteria: + description: Criteria defines how to determine the result of the + status check. + properties: + statusCode: + description: StatusCode defines the expected http status code + for the request. A statusCode string could be a single code + (e.g. 200), or an inclusive range (e.g. 200-400, both `200` + and `400` are included). + type: string + required: + - statusCode + type: object + headers: + additionalProperties: + items: + type: string + type: array + description: "A Header represents the key-value pairs in an HTTP + header. \n The keys should be in canonical form, as returned + by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in seconds) to perform + an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of the status check. + Support type: Synchronous / Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number of record to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum consecutive successes + for the status check to be considered successful. SuccessThreshold + only works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of seconds after which + an execution of status check times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check type. Support + type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + status: + description: Most recently observed status of status check + properties: + completionTime: + description: CompletionTime represents time when the status check + was completed. + format: date-time + type: string + conditions: + description: Conditions represents the latest available observations + of a StatusCheck's current state. + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - lastProbeTime + - lastTransitionTime + - reason + - status + - type + type: object + type: array + count: + description: Count represents the total number of the status check + executed. + format: int64 + type: integer + records: + description: Records contains the history of the execution of StatusCheck. + items: + properties: + outcome: + type: string + startTime: + format: date-time + type: string + required: + - outcome + - startTime + type: object + type: array + startTime: + description: StartTime represents time when the status check started + to execute. + format: date-time + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/chaos-mesh.org_stresschaos.yaml b/config/crd/bases/chaos-mesh.org_stresschaos.yaml index bc95de3e81..1763c201ed 100644 --- a/config/crd/bases/chaos-mesh.org_stresschaos.yaml +++ b/config/crd/bases/chaos-mesh.org_stresschaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: stresschaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,296 +12,333 @@ spec: listKind: StressChaosList plural: stresschaos singular: stresschaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: StressChaos is the Schema for the stresschaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a time chaos experiment - properties: - containerName: - description: ContainerName indicates the target container to inject - stress in - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + versions: + - additionalPrinterColumns: + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: StressChaos is the Schema for the stresschaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a time chaos experiment + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - stressngStressors: - description: StressngStressors defines plenty of stressors just like - `Stressors` except that it's an experimental feature and more powerful. - You can define stressors in `stress-ng` (see also `man stress-ng`) - dialect, however not all of the supported stressors are well tested. - It maybe retired in later releases. You should always use `Stressors` - to define the stressors and use this only when you want more stressors - unsupported by `Stressors`. When both `StressngStressors` and `Stressors` - are defined, `StressngStressors` wins. - type: string - stressors: - description: Stressors defines plenty of stressors supported to stress - system components out. You can use one or more of them to make up - various kinds of stresses. At least one of the stressors should be - specified. - properties: - cpu: - description: CPUStressor stresses CPU out - properties: - load: - description: Load specifies P percent loading per CPU worker. - 0 is effectively a sleep (no load) and 100 is full loading. - type: integer - options: - description: extend stress-ng options - items: - type: string - type: array - workers: - description: Workers specifies N workers to apply the stressor. - type: integer - required: - - workers - type: object - memory: - description: MemoryStressor stresses virtual memory out - properties: - options: - description: extend stress-ng options + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: items: type: string type: array - size: - description: Size specifies N bytes consumed per vm worker, - default is the total available memory. One can specify the - size as % of total available memory or in units of B, KB/KiB, - MB/MiB, GB/GiB, TB/TiB. - type: string - workers: - description: Workers specifies N workers to apply the stressor. - type: integer - required: - - workers - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the % of pods to do chaos action - type: string - required: - - mode - - selector - type: object - status: - description: Most recently observed status of the time chaos experiment - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors just like + `Stressors` except that it's an experimental feature and more powerful. + You can define stressors in `stress-ng` (see also `man stress-ng`) + dialect, however not all of the supported stressors are well tested. + It maybe retired in later releases. You should always use `Stressors` + to define the stressors and use this only when you want more stressors + unsupported by `Stressors`. When both `StressngStressors` and `Stressors` + are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported to stress + system components out. You can use one or more of them to make up + various kinds of stresses. At least one of the stressors should + be specified. + properties: + cpu: + description: CPUStressor stresses CPU out properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + load: + description: Load specifies P percent loading per CPU worker. + 0 is effectively a sleep (no load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to apply the stressor. + Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj of the stress + process. See `man 5 proc` to know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per vm worker, + default is the total available memory. One can specify the + size as % of total available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB. type: string + workers: + description: Workers specifies N workers to apply the stressor. + Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer required: - - action - - hostIP - - name - - namespace - - podIP + - workers type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - instances: - additionalProperties: - description: StressInstance is an instance generates stresses + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - mode + - selector + type: object + status: + description: Most recently observed status of the time chaos experiment + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. properties: - startTime: - description: StartTime specifies when the instance starts - format: date-time - type: string - uid: - description: UID is the instance identifier + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop type: string type: object - description: Instances always specifies stressing instances - type: object - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + instances: + additionalProperties: + description: StressInstance is an instance generates stresses + properties: + memoryStartTime: + description: MemoryStartTime specifies when the memStress starts + format: date-time + type: string + memoryUid: + description: MemoryUID is the memStress identifier + type: string + startTime: + description: StartTime specifies when the stress-ng starts + format: date-time + type: string + uid: + description: UID is the stress-ng identifier + type: string + type: object + description: Instances always specifies stressing instances + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/config/crd/bases/chaos-mesh.org_timechaos.yaml b/config/crd/bases/chaos-mesh.org_timechaos.yaml index 2f9ef0472d..8cb96a39ef 100644 --- a/config/crd/bases/chaos-mesh.org_timechaos.yaml +++ b/config/crd/bases/chaos-mesh.org_timechaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: timechaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,250 +12,259 @@ spec: listKind: TimeChaosList plural: timechaos singular: timechaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: TimeChaos is the Schema for the timechaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a time chaos experiment - properties: - clockIds: - description: ClockIds defines all affected clock id All available options - are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", - "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", - "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] - items: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: TimeChaos is the Schema for the timechaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a time chaos experiment + properties: + clockIds: + description: ClockIds defines all affected clock id All available + options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action type: string - type: array - containerNames: - description: ContainerName indicates the name of affected container. - If not set, all containers will be injected - items: + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent type: string - type: array - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - timeOffset: - description: TimeOffset defines the delta time of injected program. - It's a possibly signed sequence of decimal numbers, such as "300ms", - "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", - "s", "m", "h". - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - mode - - selector - - timeOffset - type: object - status: - description: Most recently observed status of the time chaos experiment - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + timeOffset: + description: TimeOffset defines the delta time of injected program. + It's a possibly signed sequence of decimal numbers, such as "300ms", + "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", + "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + status: + description: Most recently observed status of the time chaos experiment + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/config/crd/bases/chaos-mesh.org_workflownodes.yaml b/config/crd/bases/chaos-mesh.org_workflownodes.yaml index ae77ef307b..03d8dfb41b 100644 --- a/config/crd/bases/chaos-mesh.org_workflownodes.yaml +++ b/config/crd/bases/chaos-mesh.org_workflownodes.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: workflownodes.chaos-mesh.org spec: group: chaos-mesh.org @@ -16,2078 +14,20573 @@ spec: shortNames: - wfn singular: workflownode - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a node of workflow - properties: - aws_chaos: - description: AwsChaosSpec is the content of the specification for an - AwsChaos - properties: - action: - description: 'Action defines the specific aws chaos action. Supported - action: ec2-stop / ec2-restart / detach-volume Default action: - ec2-stop' - enum: - - ec2-stop - - ec2-restart - - detach-volume - type: string - awsRegion: - description: AwsRegion defines the region of aws. - type: string - deviceName: - description: DeviceName indicates the name of the device. Needed - in detach-volume. - type: string - duration: - description: Duration represents the duration of the chaos action. - type: string - ec2Instance: - description: Ec2Instance indicates the ID of the ec2 instance. - type: string - endpoint: - description: Endpoint indicates the endpoint of the aws server. - Just used it in test now. - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. - type: string - volumeID: - description: EbsVolume indicates the ID of the EBS volume. Needed - in detach-volume. - type: string - required: - - action - - awsRegion - - ec2Instance - type: object - deadline: - format: date-time - type: string - dns_chaos: - description: DNSChaosSpec defines the desired state of DNSChaos - properties: - action: - description: 'Action defines the specific DNS chaos action. Supported - action: error, random Default action: error' - enum: - - error - - random - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - patterns: - description: "Choose which domain names to take effect, support - the placeholder ? and wildcard *, or the Specified domain name. - Note: 1. The wildcard * must be at the end of the string. - For example, chaos-*.org is invalid. 2. if the patterns is - empty, will take effect on all the domain names. For example: - \t\tThe value is [\"google.com\", \"github.*\", \"chaos-mes?.org\"], - \t\twill take effect on \"google.com\", \"github.com\" and \"chaos-mesh.org\"" - items: - type: string - type: array - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - action - - mode - - selector - type: object - gcp_chaos: - description: GcpChaosSpec is the content of the specification for a - GcpChaos - properties: - action: - description: 'Action defines the specific gcp chaos action. Supported - action: node-stop / node-reset / disk-loss Default action: node-stop' - enum: - - node-stop - - node-reset - - disk-loss - type: string - deviceName: - description: The device name of the disk to detach. Needed in disk-loss. - type: string - duration: - description: Duration represents the duration of the chaos action. - type: string - instance: - description: Instance defines the name of the instance - type: string - project: - description: Project defines the name of gcp project. - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a node of workflow + properties: + abortWithStatusCheck: + description: AbortWithStatusCheck describe whether to abort the workflow + when the failure threshold of StatusCheck is exceeded. Only used + when Type is TypeStatusCheck. + type: boolean + awsChaos: + description: AWSChaosSpec is the content of the specification for + an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. Supported + action: ec2-stop / ec2-restart / detach-volume Default action: + ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. Needed + in detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws server. + Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. Needed + in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification for + an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. + Supported action: vm-stop / vm-restart / disk-detach Default + action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. Needed in + disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the data + disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification for + a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. + Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. It - is used for GCP credentials. - type: string - zone: - description: Zone defines the zone of gcp project. - type: string - required: - - action - - instance - - project - - zone - type: object - http_chaos: - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: delay | abort | mixed Default action: delay' - enum: - - delay - - abort - - mixed - type: string - duration: - description: Duration represents the duration of the chaos action. - It is required when the action is `PodFailureAction`. 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". - type: string - headers: - description: Specifies how the header match will be performed to - route the request. - items: + type: array + delay: + description: Delay defines the delay distribution. properties: - exact_match: - type: string - invert_match: - type: string - name: - type: string - prefix_match: - type: string - present_match: - type: string - range_match: - type: string - regex_match: + correlation: type: string - safe_regex_match: + jitter: type: string - suffix_match: + latency: + description: Latency defines the latency of every io request. type: string - required: - - name type: object - type: array - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - percent: - description: 'Percent defines the percentage of injection errors - and provides a number from 0-100. default: 100.' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: + duration: + description: Duration represents the duration of the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - action - - mode - - selector - type: object - io_chaos: - description: IoChaosSpec defines the desired state of IoChaos - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: latency / fault / attrOverride / mistake' - enum: - - latency - - fault - - attrOverride - - mistake - type: string - attr: - description: Attr defines the overrided attribution - properties: - atime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - blocks: - format: int64 - type: integer - ctime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - gid: - format: int32 - type: integer - ino: - format: int64 - type: integer - kind: - description: FileType represents type of a file - type: string - mtime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - nlink: - format: int32 - type: integer - perm: - type: integer - rdev: - format: int32 - type: integer - size: - format: int64 - type: integer - uid: - format: int32 - type: integer - type: object - containerName: - description: ContainerName indicates the target container to inject - iochaos in - type: string - delay: - description: Delay defines the value of I/O chaos action delay. - A delay string is a possibly signed sequence of decimal numbers, - each with optional fraction and a unit suffix, such as "300ms". - Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - type: string - duration: - description: Duration represents the duration of the chaos action. - It is required when the action is `PodFailureAction`. 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". - type: string - errno: - description: 'Errno defines the error code that returned by I/O - action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' - format: int32 - type: integer - methods: - description: 'Methods defines the I/O methods for injecting I/O - chaos action. default: all I/O methods.' - items: - type: string - type: array - mistake: - description: Mistake defines what types of incorrectness are injected - to IO operations - properties: - filling: - description: Filling determines what is filled in the miskate - data. - enum: - - zero - - random - type: string - maxLength: - description: Max length of each wrong data segment in bytes - format: int64 - minimum: 1 - type: integer - maxOccurrences: - description: There will be [1, MaxOccurrences] segments of wrong - data. - format: int64 - minimum: 1 - type: integer - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - path: - description: Path defines the path of files for injecting I/O chaos - action. - type: string - percent: - description: 'Percent defines the percentage of injection errors - and provides a number from 0-100. default: 100.' - type: integer - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - volumePath: - description: VolumePath represents the mount path of injected volume - type: string - required: - - action - - mode - - selector - - volumePath - type: object - jvm_chaos: - description: JVMChaosSpec defines the desired state of JVMChaos - properties: - action: - description: 'Action defines the specific jvm chaos action. Supported - action: delay;return;script;cfl;oom;ccf;tce;cpf;tde;tpf' - enum: - - delay - - return - - script - - cfl - - oom - - ccf - - tce - - cpf - - tde - - tpf - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - flags: - additionalProperties: + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action type: string - description: Flags represents the flags of action - type: object - matchers: - additionalProperties: + volumeName: type: string - description: Matchers represents the matching rules for the target - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' + required: + - action + - mode + - selector + - volumeName + type: object + children: + items: type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. + type: array + conditionalBranches: + items: properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + expression: + description: Expression is the expression for this conditional + branch, expected type of result is boolean. If expression + is empty, this branch will always be selected/the template + will be spawned. + type: string + target: + description: Target is the name of other template, if expression + is evaluated as true, this template will be spawned. type: string required: - - cron + - target type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: + type: array + deadline: + format: date-time + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos action. Supported + action: error, random Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, support + the placeholder ? and wildcard *, or the Specified domain name. + Note: 1. The wildcard * must be at the end of the string. For + example, chaos-*.org is invalid. 2. if the patterns is empty, + will take effect on all the domain names. For example: The value + is ["google.com", "github.*", "chaos-mes?.org"], will take effect + on "google.com", "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - target: - description: 'Target defines the specific jvm chaos target. Supported - target: servlet;psql;jvm;jedis;http;dubbo;rocketmq;tars;mysql;druid;redisson;rabbitmq;mongodb' - enum: - - servlet - - psql - - jvm - - jedis - - http - - dubbo - - rocketmq - - tars - - mysql - - druid - - redisson - - rabbitmq - - mongodb - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the % of pods to do chaos action - type: string - required: - - action - - mode - - selector - - target - type: object - kernel_chaos: - description: KernelChaosSpec defines the desired state of KernelChaos - properties: - duration: - description: Duration represents the duration of the chaos action - type: string - failKernRequest: - description: FailKernRequest defines the request of kernel injection - properties: - callchain: - description: 'Callchain indicate a special call chain, such - as: ext4_mount -> mount_subtree -> ... -> - should_failslab With an optional set of predicates and an - optional set of parameters, which used with predicates. You - can read call chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples - to learn more. If no special call chain, just keep Callchain - empty, which means it will fail at any call chain with slab - alloc (eg: kmalloc).' - items: - description: Frame defines the function signature and predicate - in function's body - properties: - funcname: - description: Funcname can be find from kernel source or - `/proc/kallsyms`, such as `ext4_mount` - type: string - parameters: - description: Parameters is used with predicate, for example, - if you want to inject slab error in `d_alloc_parallel(struct - dentry *parent, const struct qstr *name)` with a special - name `bananas`, you need to set it to `struct dentry - *parent, const struct qstr *name` otherwise omit it. - type: string - predicate: - description: Predicate will access the arguments of this - Frame, example with Parameters's, you can set it to - `STRNCMP(name->name, "bananas", 8)` to make inject only - with it, or omit it to inject for all d_alloc_parallel - call chain. - type: string - type: object - type: array - failtype: - description: 'FailType indicates what to fail, can be set to - ''0'' / ''1'' / ''2'' If `0`, indicates slab to fail (should_failslab) - If `1`, indicates alloc_page to fail (should_fail_alloc_page) - If `2`, indicates bio to fail (should_fail_bio) You can read: 1. - https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html 2. - http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt - to learn more' - format: int32 - maximum: 2 - minimum: 0 - type: integer - headers: - description: 'Headers indicates the appropriate kernel headers - you need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so on' - items: - type: string - type: array - probability: - description: Probability indicates the fails with probability. - If you want 1%, please set this field with 1. - format: int32 - maximum: 100 - minimum: 0 - type: integer - times: - description: Times indicates the max times of fails. - format: int32 - minimum: 0 - type: integer - required: - - failtype - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - failKernRequest - - mode - - selector - type: object - network_chaos: - description: NetworkChaosSpec defines the desired state of NetworkChaos - properties: - action: - description: 'Action defines the specific network chaos action. - Supported action: partition, netem, delay, loss, duplicate, corrupt - Default action: delay' - enum: - - netem - - delay - - loss - - duplicate - - corrupt - - partition - - bandwidth - type: string - bandwidth: - description: Bandwidth represents the detail about bandwidth control - action - properties: - buffer: - description: Buffer is the maximum amount of bytes that tokens - can be available for instantaneously. - format: int32 - minimum: 1 - type: integer - limit: - description: Limit is the number of bytes that can be queued - waiting for tokens to become available. - format: int32 - minimum: 1 - type: integer - minburst: - description: Minburst specifies the size of the peakrate bucket. - For perfect accuracy, should be set to the MTU of the interface. If - a peakrate is needed, but some burstiness is acceptable, this - size can be raised. A 3000 byte minburst allows around 3mbit/s - of peakrate, given 1000 byte packets. - format: int32 - minimum: 0 - type: integer - peakrate: - description: Peakrate is the maximum depletion rate of the bucket. - The peakrate does not need to be set, it is only necessary - if perfect millisecond timescale shaping is required. - format: int64 - minimum: 0 - type: integer - rate: - description: Rate is the speed knob. Allows bps, kbps, mbps, - gbps, tbps unit. bps means bytes per second. - type: string - required: - - buffer - - limit - - rate - type: object - corrupt: - description: Corrupt represents the detail about corrupt action - properties: - correlation: - type: string - corrupt: - type: string - required: - - correlation - - corrupt - type: object - delay: - description: Delay represents the detail about delay action - properties: - correlation: - type: string - jitter: - type: string - latency: + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification for + a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. Supported + action: node-stop / node-reset / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed in disk-loss. + items: type: string - reorder: - description: ReorderSpec defines details of packet reorder. - properties: - correlation: + type: array + duration: + description: Duration represents the duration of the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status code + in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, such + as "300ms", "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + method: + description: Method is a rule to select target by http method + in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of target. + properties: + type: + description: Type represents the patch type, only support + `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers of + target. For example: `[["Set-Cookie", ""], ["Set-Cookie", + ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries of target(Request + only). For example: `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri path in http + request. + type: string + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents in target. + properties: + body: + description: Body is a rule to replace http message body in + target. + format: byte + type: string + code: + description: Code is a rule to replace http status code in + response. + format: int32 + type: integer + headers: + additionalProperties: type: string - gap: - type: integer - reorder: + description: Headers is a rule to replace http headers of + target. The key-value pairs represent header name and header + value pairs. + type: object + method: + description: Method is a rule to replace http method in request. + type: string + path: + description: Path is rule to to replace uri path in http request. + type: string + queries: + additionalProperties: type: string - required: - - correlation - - gap - - reorder - type: object - required: - - latency - type: object - direction: - description: Direction represents the direction, this applies on - netem and network partition action - enum: - - to - - from - - both - - "" - type: string - duplicate: - description: DuplicateSpec represents the detail about loss action - properties: - correlation: - type: string - duplicate: - type: string - required: - - correlation - - duplicate - type: object - duration: - description: Duration represents the duration of the chaos action - type: string - externalTargets: - description: ExternalTargets represents network targets outside - k8s - items: - type: string - type: array - loss: - description: Loss represents the detail about loss action - properties: - correlation: - type: string - loss: + description: 'Queries is a rule to replace uri queries in + http request. For example, with value `{ "foo": "unknown" + }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: type: string - required: - - correlation - - loss - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + description: RequestHeaders is a rule to select target by http + headers in request. The key-value pairs represent header name + and header value pairs. + type: object + response_headers: + additionalProperties: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: + description: ResponseHeaders is a rule to select target by http + headers in response. The key-value pairs represent header name + and header value pairs. + type: object + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. type: object - type: array - fieldSelectors: - additionalProperties: + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file in + secret, `ca.crt` for example type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: + certName: + description: CertName represents the data name of cert file + in secret, `tls.crt` for example type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: + keyName: + description: KeyName represents the data name of key file + in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required secret + resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace of required + secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action delay. + A delay string is a possibly signed sequence of decimal numbers, + each with optional fraction and a unit suffix, such as "300ms". + Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that returned by I/O + action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting I/O + chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness are injected + to IO operations + properties: + filling: + description: Filling determines what is filled in the mistake + data. + enum: + - zero + - random type: string - type: array - pods: - additionalProperties: + maxLength: + description: Max length of each wrong data segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments of + wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting I/O + chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection errors + and provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - target: - description: Target represents network target, this applies on netem - and network partition action - properties: - mode: - description: TargetMode defines the target selector mode - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - - "" + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected + volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. Supported + action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - selector: - description: TargetSelector defines the target selector - properties: - annotationSelectors: - additionalProperties: + type: array + cpuCount: + description: the CPU core number needs to use, only set it when + action is stress + type: integer + database: + description: the match database default value is "", means match + all database + type: string + duration: + description: Duration represents the duration of the chaos action + type: string + exception: + description: the exception which needs to throw for action `exception` + or the exception message needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', unit ms + or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will generate + one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", means match + all SQL type. The value can be 'select', 'insert', 'update', + 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call chain, such + as: ext4_mount -> mount_subtree -> ... -> should_failslab + With an optional set of predicates and an optional set of + parameters, which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep Callchain + empty, which means it will fail at any call chain with slab + alloc (eg: kmalloc).' + items: + description: Frame defines the function signature and predicate + in function's body + properties: + funcname: + description: Funcname can be find from kernel source + or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, for + example, if you want to inject slab error in `d_alloc_parallel(struct + dentry *parent, const struct qstr *name)` with a special + name `bananas`, you need to set it to `struct dentry + *parent, const struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments of + this Frame, example with Parameters's, you can set + it to `STRNCMP(name->name, "bananas", 8)` to make + inject only with it, or omit it to inject for all + d_alloc_parallel call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be set + to ''0'' / ''1'' / ''2'' If `0`, indicates slab to fail + (should_failslab) If `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) You can + read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel headers + you need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so + on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos action. + Supported action: partition, netem, delay, loss, duplicate, + corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth control + action + properties: + buffer: + description: Buffer is the maximum amount of bytes that tokens + can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be queued + waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate bucket. + For perfect accuracy, should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness is acceptable, + this size can be raised. A 3000 byte minburst allows around + 3mbit/s of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of the + bucket. The peakrate does not need to be set, it is only + necessary if perfect millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies + on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets outside + k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this applies on + netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device to be + affected in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired state of + PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one of Address + and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock on which + to act. More clock description in linux kernel can be found + in man page of clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the file. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + delay: + description: Delay represents the delay of the target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for action + `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', unit + ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", means + match all database + type: string + exception: + description: The exception which needs to throw for action + `exception` or the exception message needs to throw in action + `mysql` + type: string + latency: + description: The latency duration for action 'latency' or + the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, will + use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set it + when action is stress + type: integer + mem-type: + description: the memory type need to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can + be accepted, others will be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf with + this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads to + run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP address + type: string + rate: + description: The speed of network traffic, allows bps, kbps, + mbps, gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can + be accepted, others will be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values can + be 'from', 'to'. 'from' means packets coming from the 'IPAddress' + or 'Hostname' and going to your server, 'to' means packets + originating from your server and going to the 'IPAddress' + or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of the original + value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string keys and + a set values that used to select physical machines. The + key defines the namespace which physical machine belong, + and each value is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. 0 + is effectively a sleep (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, default + is the total available memory. One can specify the size + as % of total available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify + the percent of physical machines the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify + the max percent of pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a user creates + on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: pod-kill / pod-failure / container-kill Default action: + pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It represents + the duration in seconds before the pod should be deleted. Value + must be non-negative integer. The default value is zero that + indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + description: ScheduleSpec is the specification of a schedule object + properties: + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. + Supported action: ec2-stop / ec2-restart / detach-volume + Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. + Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws server. + Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. + Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. + Supported action: vm-stop / vm-restart / disk-detach Default + action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. Needed + in disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the + data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. + Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every io request. + type: string + type: object + duration: + description: Duration represents the duration of the chaos + action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + default: Forbid + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos action. + Supported action: error, random Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, support + the placeholder ? and wildcard *, or the Specified domain + name. Note: 1. The wildcard * must be at the end of the + string. For example, chaos-*.org is invalid. 2. if the patterns + is empty, will take effect on all the domain names. For + example: The value is ["google.com", "github.*", "chaos-mes?.org"], + will take effect on "google.com", "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. + Supported action: node-stop / node-reset / disk-loss Default + action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed in + disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status + code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, + such as "300ms", "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + method: + description: Method is a rule to select target by http method + in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of target. + properties: + type: + description: Type represents the patch type, only + support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], + ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", "bar"], + ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri path in + http request. + type: string + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents in + target. + properties: + body: + description: Body is a rule to replace http message body + in target. + format: byte + type: string + code: + description: Code is a rule to replace http status code + in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header name + and header value pairs. + type: object + method: + description: Method is a rule to replace http method in + request. + type: string + path: + description: Path is rule to to replace uri path in http + request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": "unknown" + }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target by + http headers in request. The key-value pairs represent header + name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target by + http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file + in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name of cert + file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of key file + in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required + secret resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace + of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. + Supported action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action delay. + A delay string is a possibly signed sequence of decimal + numbers, each with optional fraction and a unit suffix, + such as "300ms". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos + action. It is required when the action is `PodFailureAction`. + 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". + type: string + errno: + description: 'Errno defines the error code that returned by + I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting + I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness are + injected to IO operations + properties: + filling: + description: Filling determines what is filled in the + mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment in + bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting + I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection + errors and provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected + volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. + Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only set it + when action is stress + type: integer + database: + description: the match database default value is "", means + match all database + type: string + duration: + description: Duration represents the duration of the chaos + action + type: string + exception: + description: the exception which needs to throw for action + `exception` or the exception message needs to throw in action + `mysql` + type: string + latency: + description: the latency duration for action 'latency', unit + ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it + when action is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will + generate one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel + injection + properties: + callchain: + description: 'Callchain indicate a special call chain, + such as: ext4_mount -> mount_subtree -> ... -> should_failslab + With an optional set of predicates and an optional set + of parameters, which used with predicates. You can read + call chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep Callchain + empty, which means it will fail at any call chain with + slab alloc (eg: kmalloc).' + items: + description: Frame defines the function signature and + predicate in function's body + properties: + funcname: + description: Funcname can be find from kernel source + or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab error + in `d_alloc_parallel(struct dentry *parent, const + struct qstr *name)` with a special name `bananas`, + you need to set it to `struct dentry *parent, + const struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments + of this Frame, example with Parameters's, you + can set it to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, or omit it to + inject for all d_alloc_parallel call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be + set to ''0'' / ''1'' / ''2'' If `0`, indicates slab + to fail (should_failslab) If `1`, indicates alloc_page + to fail (should_fail_alloc_page) If `2`, indicates bio + to fail (should_fail_bio) You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel + headers you need. Eg: "linux/mmzone.h", "linux/blkdev.h" + and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos action. + Supported action: partition, netem, delay, loss, duplicate, + corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes that + tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be + queued waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate + bucket. For perfect accuracy, should be set to the MTU + of the interface. If a peakrate is needed, but some + burstiness is acceptable, this size can be raised. A + 3000 byte minburst allows around 3mbit/s of peakrate, + given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of + the bucket. The peakrate does not need to be set, it + is only necessary if perfect millisecond timescale shaping + is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, + mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies + on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss + action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos + action + type: string + externalTargets: + description: ExternalTargets represents network targets outside + k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control + action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, + mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + target: + description: Target represents network target, this applies + on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / + random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values + array must be non-empty. If the operator is + Exists or DoesNotExist, the values array must + be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines + the namespace which pods belong, and the each values + is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to + `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device to + be affected in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired state + of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one of + Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock on + which to act. More clock description in linux kernel + can be found in man page of clock_getres, clock_gettime, + clock_settime. Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. if + path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. if + path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. if + path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos + action + type: string + file-append: + properties: + count: + description: Count is the number of times to append the + data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create or + delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create or + delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the + file. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to be + replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside + proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + delay: + description: Delay represents the delay of the target + request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside + proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for action + `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', + unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", means + match all database + type: string + exception: + description: The exception which needs to throw for action + `exception` or the exception message needs to throw + in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' + or the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only + support 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, + will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set + it when action is stress + type: integer + mem-type: + description: the memory type need to locate, only set + it when action is stress, the value can be 'stack' or + 'heap' + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag + can be accepted, others will be dropped. only set when + the IPProtocol is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us (or + µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 is + 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads + to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP address + type: string + rate: + description: The speed of network traffic, allows bps, + kbps, mbps, gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag + can be accepted, others will be dropped. only set when + the IPProtocol is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values + can be 'from', 'to'. 'from' means packets coming from + the 'IPAddress' or 'Hostname' and going to your server, + 'to' means packets originating from your server and + going to the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of the + original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string keys + and a set values that used to select physical machines. + The key defines the namespace which physical machine + belong, and each value is a set of physical machine + names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. + 0 is effectively a sleep (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, + default is the total available memory. One can specify + the size as % of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify + the percent of physical machines the server can do chaos + action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a user creates + on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos action. + Supported action: pod-kill / pod-failure / container-kill + Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action. It is required when the action is `PodFailureAction`. + 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It represents + the duration in seconds before the pod should be deleted. + Value must be non-negative integer. The default value is + zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + exclusiveMinimum: true + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors + just like `Stressors` except that it's an experimental feature + and more powerful. You can define stressors in `stress-ng` + (see also `man stress-ng`) dialect, however not all of the + supported stressors are well tested. It maybe retired in + later releases. You should always use `Stressors` to define + the stressors and use this only when you want more stressors + unsupported by `Stressors`. When both `StressngStressors` + and `Stressors` are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported + to stress system components out. You can use one or more + of them to make up various kinds of stresses. At least one + of the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading per + CPU worker. 0 is effectively a sleep (no load) and + 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to apply + the stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj of + the stress process. See `man 5 proc` to know more + about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per vm + worker, default is the total available memory. One + can specify the size as % of total available memory + or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to apply + the stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id All available + options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected + program. It's a possibly signed sequence of decimal numbers, + such as "300ms", "-1.5h" or "2h45m". Valid time units are + "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + workflow: + properties: + entry: + type: string + templates: + items: + properties: + abortWithStatusCheck: + description: AbortWithStatusCheck describe whether to + abort the workflow when the failure threshold of StatusCheck + is exceeded. Only used when Type is TypeStatusCheck. + type: boolean + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos + action. Supported action: ec2-stop / ec2-restart + / detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the + device. Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the + ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of + the aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS + volume. Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure + chaos action. Supported action: vm-stop / vm-restart + / disk-detach Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the + disk. Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number + of the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name + of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure + subscription. + type: string + vmName: + description: VMName defines the name of Virtual + Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block + chaos action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of + every io request. + type: string + type: object + duration: + description: Duration represents the duration of + the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + children: + description: Children describes the children steps of + serial or parallel node. Only used when Type is TypeSerial + or TypeParallel. + items: + type: string + type: array + conditionalBranches: + description: ConditionalBranches describes the conditional + branches of custom tasks. Only used when Type is TypeTask. + items: + properties: + expression: + description: Expression is the expression for + this conditional branch, expected type of result + is boolean. If expression is empty, this branch + will always be selected/the template will be + spawned. + type: string + target: + description: Target is the name of other template, + if expression is evaluated as true, this template + will be spawned. + type: string + required: + - target + type: object + type: array + deadline: + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state + of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos + action. Supported action: error, random Default + action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take + effect, support the placeholder ? and wildcard + *, or the Specified domain name. Note: 1. The + wildcard * must be at the end of the string. For + example, chaos-*.org is invalid. 2. if the patterns + is empty, will take effect on all the domain names. + For example: The value is ["google.com", "github.*", + "chaos-mes?.org"], will take effect on "google.com", + "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos + action. Supported action: node-stop / node-reset + / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. + Needed in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by + http status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target + request/response. A duration string is a possibly + unsigned sequence of decimal numbers, each with + optional fraction and a unit suffix, such as "300ms", + "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + method: + description: Method is a rule to select target by + http method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. + properties: + body: + description: Body is a rule to patch message + body of target. + properties: + type: + description: Type represents the patch type, + only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http + headers of target. For example: `[["Set-Cookie", + ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri + queries of target(Request only). For example: + `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by + uri path in http request. + type: string + port: + description: Port represents the target port to + be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http + message body in target. + format: byte + type: string + code: + description: Code is a rule to replace http + status code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http + headers of target. The key-value pairs represent + header name and header value pairs. + type: object + method: + description: Method is a rule to replace http + method in request. + type: string + path: + description: Path is rule to to replace uri + path in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri + queries in http request. For example, with + value `{ "foo": "unknown" }`, the `/?foo=bar` + will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select + target by http headers in request. The key-value + pairs represent header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select + target by http headers in response. The key-value + pairs represent header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected + and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override + PodHttpChaos if there are multiple HTTPChaos experiments + are applied + properties: + caName: + description: CAName represents the data name + of ca file in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name + of cert file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name + of key file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name + of required secret resource + type: string + secretNamespace: + description: SecretNamespace represents the + namespace of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of + IOChaos + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: latency / fault / attrOverride + / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos + action delay. A delay string is a possibly signed + sequence of decimal numbers, each with optional + fraction and a unit suffix, such as "300ms". Valid + time units are "ns", "us" (or "µs"), "ms", "s", + "m", "h". + type: string + duration: + description: Duration represents the duration of + the chaos action. It is required when the action + is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that + returned by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for + injecting I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled + in the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment + in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] + segments of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for + injecting I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of + injection errors and provides a number from 0-100. + default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path + of injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state + of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos + action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only + set it when action is stress + type: integer + database: + description: the match database default value is + "", means match all database + type: string + duration: + description: Duration represents the duration of + the chaos action + type: string + exception: + description: the exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only + set it when action is stress, the value can be + 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set to + "8") now + type: string + name: + description: byteman rule name, should be unique, + and will generate one if not set + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action + 'ruleData' + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is + "", means match all SQL type. The value can be + 'select', 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", + means match all table + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state + of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request + of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call + chain, such as: ext4_mount -> mount_subtree + -> ... -> should_failslab With an optional + set of predicates and an optional set of parameters, + which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just + keep Callchain empty, which means it will + fail at any call chain with slab alloc (eg: + kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from + kernel source or `/proc/kallsyms`, such + as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab + error in `d_alloc_parallel(struct dentry + *parent, const struct qstr *name)` with + a special name `bananas`, you need to + set it to `struct dentry *parent, const + struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the + arguments of this Frame, example with + Parameters's, you can set it to `STRNCMP(name->name, + "bananas", 8)` to make inject only with + it, or omit it to inject for all d_alloc_parallel + call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, + can be set to ''0'' / ''1'' / ''2'' If `0`, + indicates slab to fail (should_failslab) If + `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) + You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails + with probability. If you want 1%, please set + this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of + fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + name: + type: string + networkChaos: + description: NetworkChaosSpec defines the desired state + of NetworkChaos + properties: + action: + description: 'Action defines the specific network + chaos action. Supported action: partition, netem, + delay, loss, duplicate, corrupt Default action: + delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about + bandwidth control action + properties: + buffer: + description: Buffer is the maximum amount of + bytes that tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that + can be queued waiting for tokens to become + available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of + the peakrate bucket. For perfect accuracy, + should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness + is acceptable, this size can be raised. A + 3000 byte minburst allows around 3mbit/s of + peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion + rate of the bucket. The peakrate does not + need to be set, it is only necessary if perfect + millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about + corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay + action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of + packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device + to be affected. + type: string + direction: + default: to + description: Direction represents the direction, + this applies on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail + about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of + the chaos action + type: string + externalTargets: + description: ExternalTargets represents network + targets outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss + action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate + control action + properties: + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this + applies on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network + device to be affected in target scope. + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired + state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. + Only one of Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular + clock on which to act. More clock description + in linux kernel can be found in man page of + clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 is + valid value + type: integer + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 is + valid value + type: integer + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of + the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to + append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to + create or delete. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to + create or delete. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + privilege: + description: Privilege is the file privilege + to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to + be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string + of the file. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + line: + description: Line is the line number of the + file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string + of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of + HTTP connection, we will only attack HTTP + connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + delay: + description: Delay represents the delay of the + target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of + HTTP connection, we will only attack HTTP + connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support + GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw + for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action + 'latency', unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value + is "", means match all database + type: string + exception: + description: The exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action + 'latency' or the latency duration in action + `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set + to "8") now + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value + is "", means match all SQL type. The value + can be 'select', 'insert', 'update', 'delete', + 'replace'. + type: string + table: + description: the match table default value is + "", means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule + file's data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, + only set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, + only set it when action is stress, the value + can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the + tcp flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used + for partition. + type: string + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: + ns, us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the + iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client + threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on + the IP address + type: string + rate: + description: The speed of network traffic, allows + bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the + tcp flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used + for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means packets + coming from the 'IPAddress' or 'Hostname' + and going to your server, 'to' means packets + originating from your server and going to + the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these + IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process + ID + type: string + recoverCmd: + description: the command to be run when recovering + experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical + machines that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string + keys and a set values that used to select + physical machines. The key defines the namespace + which physical machine belong, and each value + is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per + CPU worker. 0 is effectively a sleep (no load) + and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the + stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per + vm worker, default is the total available + memory. One can specify the size as % of total + available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when + attack + type: string + recoverCmd: + description: The command to be executed when + recover + type: string + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of physical + machines to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent + of physical machines the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do + chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that + a user creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: pod-kill / pod-failure + / container-kill Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action. It is required when the action + is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. + It represents the duration in seconds before the + pod should be deleted. Value must be non-negative + integer. The default value is zero that indicates + delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + description: Schedule describe the Schedule(describing + scheduled chaos) to be injected with chaos nodes. + Only used when Type is TypeSchedule. + properties: + awsChaos: + description: AWSChaosSpec is the content of the + specification for an AWSChaos + properties: + action: + description: 'Action defines the specific aws + chaos action. Supported action: ec2-stop / + ec2-restart / detach-volume Default action: + ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of + aws. + type: string + deviceName: + description: DeviceName indicates the name of + the device. Needed in detach-volume. + type: string + duration: + description: Duration represents the duration + of the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of + the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint + of the aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of + kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the + EBS volume. Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the + specification for an AzureChaos + properties: + action: + description: 'Action defines the specific azure + chaos action. Supported action: vm-stop / + vm-restart / disk-detach Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of + the disk. Needed in disk-detach. + type: string + duration: + description: Duration represents the duration + of the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit + Number of the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name + of ResourceGroup + type: string + secretName: + description: SecretName defines the name of + kubernetes secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of + Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual + Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the + specification for a BlockChaos + properties: + action: + description: 'Action defines the specific block + chaos action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency + of every io request. + type: string + type: object + duration: + description: Duration represents the duration + of the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state + of DNSChaos + properties: + action: + description: 'Action defines the specific DNS + chaos action. Supported action: error, random + Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take + effect, support the placeholder ? and wildcard + *, or the Specified domain name. Note: 1. + The wildcard * must be at the end of the string. + For example, chaos-*.org is invalid. 2. if + the patterns is empty, will take effect on + all the domain names. For example: The value + is ["google.com", "github.*", "chaos-mes?.org"], + will take effect on "google.com", "github.com" + and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the + specification for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp + chaos action. Supported action: node-stop + / node-reset / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. + Needed in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action. + type: string + instance: + description: Instance defines the name of the + instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of + kubernetes secret. It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http + session. + type: boolean + code: + description: Code is a rule to select target + by http status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the + target request/response. A duration string + is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a + unit suffix, such as "300ms", "2h45m". Valid + time units are "ns", "us" (or "µs"), "ms", + "s", "m", "h". + type: string + duration: + description: Duration represents the duration + of the chaos action. + type: string + method: + description: Method is a rule to select target + by http method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. + properties: + body: + description: Body is a rule to patch message + body of target. + properties: + type: + description: Type represents the patch + type, only support `JSON` as [merge + patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append + http headers of target. For example: `[["Set-Cookie", + ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append + uri queries of target(Request only). For + example: `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target + by uri path in http request. + type: string + port: + description: Port represents the target port + to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some + contents in target. + properties: + body: + description: Body is a rule to replace http + message body in target. + format: byte + type: string + code: + description: Code is a rule to replace http + status code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace + http headers of target. The key-value + pairs represent header name and header + value pairs. + type: object + method: + description: Method is a rule to replace + http method in request. + type: string + path: + description: Path is rule to to replace + uri path in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace + uri queries in http request. For example, + with value `{ "foo": "unknown" }`, the + `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select + target by http headers in request. The key-value + pairs represent header name and header value + pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select + target by http headers in response. The key-value + pairs represent header name and header value + pairs. + type: object + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + target: + description: Target is the object to be selected + and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override + PodHttpChaos if there are multiple HTTPChaos + experiments are applied + properties: + caName: + description: CAName represents the data + name of ca file in secret, `ca.crt` for + example + type: string + certName: + description: CertName represents the data + name of cert file in secret, `tls.crt` + for example + type: string + keyName: + description: KeyName represents the data + name of key file in secret, `tls.key` + for example + type: string + secretName: + description: SecretName represents the name + of required secret resource + type: string + secretNamespace: + description: SecretNamespace represents + the namespace of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state + of IOChaos + properties: + action: + description: 'Action defines the specific pod + chaos action. Supported action: latency / + fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of + file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O + chaos action delay. A delay string is a possibly + signed sequence of decimal numbers, each with + optional fraction and a unit suffix, such + as "300ms". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration + of the chaos action. It is required when the + action is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that + returned by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods + for injecting I/O chaos action. default: all + I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is + filled in the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data + segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] + segments of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files + for injecting I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage + of injection errors and provides a number + from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount + path of injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state + of JVMChaos + properties: + action: + description: 'Action defines the specific jvm + chaos action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, + only set it when action is stress + type: integer + database: + description: the match database default value + is "", means match all database + type: string + duration: + description: Duration represents the duration + of the chaos action + type: string + exception: + description: the exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action + 'latency', unit ms or the latency duration + in action `mysql` + type: integer + memType: + description: the memory type needs to locate, + only set it when action is stress, the value + can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set + to "8") now + type: string + name: + description: byteman rule name, should be unique, + and will generate one if not set + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action + 'ruleData' + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + sqlType: + description: the match sql type default value + is "", means match all SQL type. The value + can be 'select', 'insert', 'update', 'delete', + 'replace'. + type: string + table: + description: the match table default value is + "", means match all table + type: string + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired + state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request + of kernel injection + properties: + callchain: + description: 'Callchain indicate a special + call chain, such as: ext4_mount -> mount_subtree + -> ... -> should_failslab With an optional + set of predicates and an optional set + of parameters, which used with predicates. + You can read call chan and predicate examples + from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, + just keep Callchain empty, which means + it will fail at any call chain with slab + alloc (eg: kmalloc).' + items: + description: Frame defines the function + signature and predicate in function's + body + properties: + funcname: + description: Funcname can be find + from kernel source or `/proc/kallsyms`, + such as `ext4_mount` + type: string + parameters: + description: Parameters is used with + predicate, for example, if you want + to inject slab error in `d_alloc_parallel(struct + dentry *parent, const struct qstr + *name)` with a special name `bananas`, + you need to set it to `struct dentry + *parent, const struct qstr *name` + otherwise omit it. + type: string + predicate: + description: Predicate will access + the arguments of this Frame, example + with Parameters's, you can set it + to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, + or omit it to inject for all d_alloc_parallel + call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to + fail, can be set to ''0'' / ''1'' / ''2'' + If `0`, indicates slab to fail (should_failslab) + If `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) + You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails + with probability. If you want 1%, please + set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times + of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired + state of NetworkChaos + properties: + action: + description: 'Action defines the specific network + chaos action. Supported action: partition, + netem, delay, loss, duplicate, corrupt Default + action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail + about bandwidth control action + properties: + buffer: + description: Buffer is the maximum amount + of bytes that tokens can be available + for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes + that can be queued waiting for tokens + to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size + of the peakrate bucket. For perfect accuracy, + should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness + is acceptable, this size can be raised. + A 3000 byte minburst allows around 3mbit/s + of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion + rate of the bucket. The peakrate does + not need to be set, it is only necessary + if perfect millisecond timescale shaping + is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, + mbps, gbps, tbps unit. bps means bytes + per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about + corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about + delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details + of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device + to be affected. + type: string + direction: + default: to + description: Direction represents the direction, + this applies on netem and network partition + action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail + about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration + of the chaos action + type: string + externalTargets: + description: ExternalTargets represents network + targets outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about + loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about + rate control action + properties: + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, + mbps, gbps, tbps unit. bps means bytes + per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + target: + description: Target represents network target, + this applies on netem and network partition + action + properties: + mode: + description: 'Mode defines the mode to run + chaos action. Supported mode: one / all + / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select + pods that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and + values that can be used to select + objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector + expressions that can be used to select + objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and + values that can be used to select + objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and + values that can be used to select + objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of + namespace to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and + values that can be used to select + nodes. Selector which must match a + node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node + name and objects must belong to these + nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a + set of condition of a pod at the current + time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string + keys and a set values that used to + select pods. The key defines the namespace + which pods belong, and the each values + is a set of pod names. + type: object + type: object + value: + description: Value is required when the + mode is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent + of pods the server can do chaos action. + IF `RandomMaxPercentMode`, provide a + number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network + device to be affected in target scope. + type: string + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the + desired state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. + Only one of Address and Selector could be + specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular + clock on which to act. More clock description + in linux kernel can be found in man page + of clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time + offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill + data in. if path not provided, payload + will read/write from/into a temp file, + temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of + data will write into the file path. support + unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | + 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload + will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 + is valid value + type: integer + size: + description: 'specifies how many units of + data will write into the file path. support + unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | + 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload + will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 + is valid value + type: integer + size: + description: 'specifies how many units of + data will write into the file path. support + unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | + 512kB' + type: string + type: object + duration: + description: Duration represents the duration + of the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times + to append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name + to create or delete. + type: string + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name + to create or delete. + type: string + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege + to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be + renamed. + type: string + source-file: + description: SourceFile is the name need + to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination + string of the file. + type: string + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + line: + description: Line is the line number of + the file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string + of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target + service listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port + of HTTP connection, we will only attack + HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + delay: + description: Delay represents the delay + of the target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target + service listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port + of HTTP connection, we will only attack + HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only + support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to + throw for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action + 'latency', unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default + value is "", means match all database + type: string + exception: + description: The exception which needs to + throw for action `exception` or the exception + message needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action + 'latency' or the latency duration in action + `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set + to "8") now + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default + value is "", means match all SQL type. + The value can be 'select', 'insert', 'update', + 'delete', 'replace'. + type: string + table: + description: the match table default value + is "", means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + value: + description: the return value for action + 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule + file's data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to + use, only set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, + only set it when action is stress, the + value can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka + config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 + is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic + to these destination ports, use a ',' + to separate or to indicate the range, + such as 80, 8001:8010. it can only be + used in conjunction with -p tcp or -p + udp + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using + this IP protocol, supported: tcp, udp, + icmp, all' + type: string + percent: + description: percentage of packets to corrupt + (10 is 10%) + type: string + source-port: + description: only impact egress traffic + from these source ports, use a ',' to + separate or to indicate the range, such + as 80, 8001:8010. it can only be used + in conjunction with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match + the tcp flag can be accepted, others will + be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 + is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic + to these destination ports, use a ',' + to separate or to indicate the range, + such as 80, 8001:8010. it can only be + used in conjunction with -p tcp or -p + udp + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using + this IP protocol, supported: tcp, udp, + icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: + ns, us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic + from these source ports, use a ',' to + separate or to indicate the range, such + as 80, 8001:8010. it can only be used + in conjunction with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified + IP + type: string + dns-ip: + description: map specified host to this + IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: + ns, us (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 + is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic + to these destination ports, use a ',' + to separate or to indicate the range, + such as 80, 8001:8010. it can only be + used in conjunction with -p tcp or -p + udp + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using + this IP protocol, supported: tcp, udp, + icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic + from these source ports, use a ',' to + separate or to indicate the range, such + as 80, 8001:8010. it can only be used + in conjunction with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run + the iperf test + type: string + ip-address: + description: Generate traffic to this IP + address + type: string + parallel: + description: The number of iperf parallel + client threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port + on the IP address + type: string + rate: + description: The speed of network traffic, + allows bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 + is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic + to these destination ports, use a ',' + to separate or to indicate the range, + such as 80, 8001:8010. it can only be + used in conjunction with -p tcp or -p + udp + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using + this IP protocol, supported: tcp, udp, + icmp, all' + type: string + percent: + description: percentage of packets to loss + (10 is 10%) + type: string + source-port: + description: only impact egress traffic + from these source ports, use a ',' to + separate or to indicate the range, such + as 80, 8001:8010. it can only be used + in conjunction with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match + the tcp flag can be accepted, others will + be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means + packets coming from the 'IPAddress' or + 'Hostname' and going to your server, 'to' + means packets originating from your server + and going to the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic + to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process + ID + type: string + recoverCmd: + description: the command to be run when + recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be + sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines + whether to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` + command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines + whether to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` + command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical + machines that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of + string keys and a set values that used + to select physical machines. The key defines + the namespace which physical machine belong, + and each value is a set of physical machine + names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading + per CPU worker. 0 is effectively a sleep + (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply + the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % + of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed + when attack + type: string + recoverCmd: + description: The command to be executed + when recover + type: string + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent + of physical machines the server can do chaos + action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes + that a user creates on a chaos experiment about + pods. + properties: + action: + description: 'Action defines the specific pod + chaos action. Supported action: pod-kill / + pod-failure / container-kill Default action: + pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action. It is required when the + action is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill + action. It represents the duration in seconds + before the pod should be deleted. Value must + be non-negative integer. The default value + is zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired + state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty + of stressors just like `Stressors` except + that it's an experimental feature and more + powerful. You can define stressors in `stress-ng` + (see also `man stress-ng`) dialect, however + not all of the supported stressors are well + tested. It maybe retired in later releases. + You should always use `Stressors` to define + the stressors and use this only when you want + more stressors unsupported by `Stressors`. + When both `StressngStressors` and `Stressors` + are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors + supported to stress system components out. + You can use one or more of them to make up + various kinds of stresses. At least one of + the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent + loading per CPU worker. 0 is effectively + a sleep (no load) and 100 is full + loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 + workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual + memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 + proc` to know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes + consumed per vm worker, default is + the total available memory. One can + specify the size as % of total available + memory or in units of B, KB/KiB, MB/MiB, + GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 + workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state + of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock + id All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time + of injected program. It's a possibly signed + sequence of decimal numbers, such as "300ms", + "-1.5h" or "2h45m". Valid time units are "ns", + "us" (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + required: + - schedule + - type + type: object + statusCheck: + description: StatusCheck describe the behavior of StatusCheck. + Only used when Type is TypeStatusCheck. + properties: + duration: + description: Duration defines the duration of the + whole status check if the number of failed execution + does not exceed the failure threshold. Duration + is available to both `Synchronous` and `Continuous` + mode. 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum + consecutive failure for the status check to be + considered failed. + minimum: 1 + type: integer + http: + properties: + body: + type: string + criteria: + description: Criteria defines how to determine + the result of the status check. + properties: + statusCode: + description: StatusCode defines the expected + http status code for the request. A statusCode + string could be a single code (e.g. 200), + or an inclusive range (e.g. 200-400, both + `200` and `400` are included). + type: string + required: + - statusCode + type: object + headers: + additionalProperties: + items: + type: string + type: array + description: "A Header represents the key-value + pairs in an HTTP header. \n The keys should + be in canonical form, as returned by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in + seconds) to perform an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of + the status check. Support type: Synchronous / + Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number + of record to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum + consecutive successes for the status check to + be considered successful. SuccessThreshold only + works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of + seconds after which an execution of status check + times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check + type. Support type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + stressChaos: + description: StressChaosSpec defines the desired state + of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of + stressors just like `Stressors` except that it's + an experimental feature and more powerful. You + can define stressors in `stress-ng` (see also + `man stress-ng`) dialect, however not all of the + supported stressors are well tested. It maybe + retired in later releases. You should always use + `Stressors` to define the stressors and use this + only when you want more stressors unsupported + by `Stressors`. When both `StressngStressors` + and `Stressors` are defined, `StressngStressors` + wins. + type: string + stressors: + description: Stressors defines plenty of stressors + supported to stress system components out. You + can use one or more of them to make up various + kinds of stresses. At least one of the stressors + should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading + per CPU worker. 0 is effectively a sleep + (no load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 workers + can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual + memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` + to know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % + of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 workers + can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + task: + description: Task describes the behavior of the custom + task. Only used when Type is TypeTask. + properties: + container: + description: Container is the main container image + to run in the pod + properties: + args: + description: 'Arguments to the entrypoint. The + container image''s CMD is used if this is + not provided. Variable references $(VAR_NAME) + are expanded using the container''s environment. + If a variable cannot be resolved, the reference + in the input string will be unchanged. Double + $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal + "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable + exists or not. Cannot be updated. More info: + https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed + within a shell. The container image''s ENTRYPOINT + is used if this is not provided. Variable + references $(VAR_NAME) are expanded using + the container''s environment. If a variable + cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, + regardless of whether the variable exists + or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to + set in the container. Cannot be updated. + items: + description: EnvVar represents an environment + variable present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined + environment variables in the container + and any service environment variables. + If a variable cannot be resolved, the + reference in the input string will be + unchanged. Double $$ are reduced to + a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, + regardless of whether the variable exists + or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment + variable's value. Cannot be used if + value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the + ConfigMap or its key must be + defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the + pod: supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in + terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field + to select in the specified API + version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: + required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret + in the pod's namespace + properties: + key: + description: The key of the secret + to select from. Must be a valid + secret key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the + Secret or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined + within a source must be a C_IDENTIFIER. All + invalid keys will be reported as an event + when the container is starting. When a key + exists in multiple sources, the value associated + with the last source will take precedence. + Values defined by an Env with a duplicate + key will take precedence. Cannot be updated. + items: + description: EnvFromSource represents the + source of a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to + prepend to each key in the ConfigMap. + Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: + https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level + config management to default or override container + images in workload controllers like Deployments + and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, + Never, IfNotPresent. Defaults to Always if + :latest tag is specified, or IfNotPresent + otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system + should take in response to container lifecycle + events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately + after a container is created. If the handler + fails, the container is terminated and + restarted according to its restart policy. + Other management of the container blocks + until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action + to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the + command is root ('/') in the + container's filesystem. The command + is simply exec'd, it is not run + inside a shell, so traditional + shell instructions ('|', etc) + won't work. To use a shell, you + need to explicitly call out to + that shell. Exit status of 0 is + treated as live/healthy and non-zero + is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood + as the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is + NOT supported as a LifecycleHandler + and kept for the backward compatibility. + There are no validation of this field + and lifecycle hooks will fail in runtime + when tcp handler is specified. + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the + pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately + before a container is terminated due to + an API request or management event such + as liveness/startup probe failure, preemption, + resource contention, etc. The handler + is not called if the container crashes + or exits. The Pod''s termination grace + period countdown begins before the PreStop + hook is executed. Regardless of the outcome + of the handler, the container will eventually + terminate within the Pod''s termination + grace period (unless delayed by finalizers). + Other management of the container blocks + until the hook completes or until the + termination grace period is reached. More + info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action + to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the + command is root ('/') in the + container's filesystem. The command + is simply exec'd, it is not run + inside a shell, so traditional + shell instructions ('|', etc) + won't work. To use a shell, you + need to explicitly call out to + that shell. Exit status of 0 is + treated as live/healthy and non-zero + is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood + as the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is + NOT supported as a LifecycleHandler + and kept for the backward compatibility. + There are no validation of this field + and lifecycle hooks will fail in runtime + when tcp handler is specified. + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the + pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed + after having succeeded. Defaults to 3. + Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC + service. Number must be in the range + 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of + the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness + probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum + value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully + upon probe failure. The grace period is + the duration in seconds after the processes + running in the pod are sent a termination + signal and the time when the processes + are forcibly halted with a kill signal. + Set this value longer than the expected + cleanup time for your process. If this + value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value + zero indicates stop immediately via the + kill signal (no opportunity to shut down). + This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified + as a DNS_LABEL. Each container in a pod must + have a unique name (DNS_LABEL). Cannot be + updated. + type: string + ports: + description: List of ports to expose from the + container. Not specifying a port here DOES + NOT prevent that port from being exposed. + Any port which is listening on the default + "0.0.0.0" address inside a container will + be accessible from the network. Modifying + this array with strategic merge patch may + corrupt the data. For more information See + https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network + port in a single container. + properties: + containerPort: + description: Number of port to expose + on the pod's IP address. This must be + a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the + external port to. + type: string + hostPort: + description: Number of port to expose + on the host. If specified, this must + be a valid port number, 0 < x < 65536. + If HostNetwork is specified, this must + match ContainerPort. Most containers + do not need this. + format: int32 + type: integer + name: + description: If specified, this must be + an IANA_SVC_NAME and unique within the + pod. Each named port in a pod must have + a unique name. Name for the port that + can be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be + UDP, TCP, or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service + readiness. Container will be removed from + service endpoints if the probe fails. Cannot + be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed + after having succeeded. Defaults to 3. + Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC + service. Number must be in the range + 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of + the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness + probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum + value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully + upon probe failure. The grace period is + the duration in seconds after the processes + running in the pod are sent a termination + signal and the time when the processes + are forcibly halted with a kill signal. + Set this value longer than the expected + cleanup time for your process. If this + value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value + zero indicates stop immediately via the + kill signal (no opportunity to shut down). + This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the + container. + items: + description: ContainerResizePolicy represents + resource resize policy for the container. + properties: + resourceName: + description: 'Name of the resource to + which this resource resize policy applies. + Supported values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when + specified resource is resized. If not + specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by + this container. Cannot be updated. More info: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of + resources, defined in spec.resourceClaims, + that are used by this container. \n This + is an alpha field and requires enabling + the DynamicResourceAllocation feature + gate. \n This field is immutable. It can + only be set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum + amount of compute resources allowed. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. + If Requests is omitted for a container, + it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined + value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + restartPolicy: + description: 'RestartPolicy defines the restart + behavior of individual containers in a pod. + This field may only be set for init containers, + and the only allowed value is "Always". For + non-init containers or when this field is + not specified, the restart behavior is defined + by the Pod''s restart policy and the container + type. Setting the RestartPolicy as "Always" + for the init container will have the following + effect: this init container will be continually + restarted on exit until all regular containers + have terminated. Once all regular containers + have completed, all init containers with restartPolicy + "Always" will be shut down. This lifecycle + differs from normal init containers and is + often referred to as a "sidecar" container. + Although this init container still starts + in the init container sequence, it does not + wait for the container to complete before + proceeding to the next init container. Instead, + the next init container starts immediately + after this init container is started, or after + any startupProbe has successfully completed.' + type: string + securityContext: + description: 'SecurityContext defines the security + options the container should be run with. + If set, the fields of SecurityContext override + the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges + than its parent process. This bool directly + controls if the no_new_privs flag will + be set on the container process. AllowPrivilegeEscalation + is true always when the container is: + 1) run as Privileged 2) has CAP_SYS_ADMIN + Note that this field cannot be set when + spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop + when running containers. Defaults to the + default set of capabilities granted by + the container runtime. Note that this + field cannot be set when spec.os.name + is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent + POSIX capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent + POSIX capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged + mode. Processes in privileged containers + are essentially equivalent to root on + the host. Defaults to false. Note that + this field cannot be set when spec.os.name + is windows. + type: boolean + procMount: + description: procMount denotes the type + of proc mount to use for the containers. + The default is DefaultProcMount which + uses the container runtime defaults for + readonly paths and masked paths. This + requires the ProcMountType feature flag + to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has + a read-only root filesystem. Default is + false. Note that this field cannot be + set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint + of the container process. Uses runtime + default if unset. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. Note that this field + cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container + must run as a non-root user. If true, + the Kubelet will validate the image at + runtime to ensure that it does not run + as UID 0 (root) and fail to start the + container if it does. If unset or false, + no such validation will be performed. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint + of the container process. Defaults to + user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. Note that this field + cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied + to the container. If unspecified, the + container runtime will allocate a random + SELinux context for each container. May + also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. Note that this field + cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level + label that applies to the container. + type: string + role: + description: Role is a SELinux role + label that applies to the container. + type: string + type: + description: Type is a SELinux type + label that applies to the container. + type: string + user: + description: User is a SELinux user + label that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use + by this container. If seccomp options + are provided at both the pod & container + level, the container options override + the pod options. Note that this field + cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: localhostProfile indicates + a profile defined in a file on the + node should be used. The profile must + be preconfigured on the node to work. + Must be a descending path, relative + to the kubelet's configured seccomp + profile location. Must be set if type + is "Localhost". Must NOT be set for + any other type. + type: string + type: + description: "type indicates which kind + of seccomp profile will be applied. + Valid options are: \n Localhost - + a profile defined in a file on the + node should be used. RuntimeDefault + - the container runtime default profile + should be used. Unconfined - no profile + should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings + applied to all containers. If unspecified, + the options from the PodSecurityContext + will be used. If set in both SecurityContext + and PodSecurityContext, the value specified + in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name + is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where + the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName + field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName + is the name of the GMSA credential + spec to use. + type: string + hostProcess: + description: HostProcess determines + if a container should be run as a + 'Host Process' container. All of a + Pod's containers must have the same + effective HostProcess value (it is + not allowed to have a mix of HostProcess + containers and non-HostProcess containers). + In addition, if HostProcess is true + then HostNetwork must also be set + to true. + type: boolean + runAsUserName: + description: The UserName in Windows + to run the entrypoint of the container + process. Defaults to the user specified + in image metadata if unspecified. + May also be set in PodSecurityContext. + If set in both SecurityContext and + PodSecurityContext, the value specified + in SecurityContext takes precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the + Pod has successfully initialized. If specified, + no other probes are executed until this completes + successfully. If this probe fails, the Pod + will be restarted, just as if the livenessProbe + failed. This can be used to provide different + probe parameters at the beginning of a Pod''s + lifecycle, when it might take a long time + to load data or warm a cache, than during + steady-state operation. This cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed + after having succeeded. Defaults to 3. + Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC + service. Number must be in the range + 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of + the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness + probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum + value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully + upon probe failure. The grace period is + the duration in seconds after the processes + running in the pod are sent a termination + signal and the time when the processes + are forcibly halted with a kill signal. + Set this value longer than the expected + cleanup time for your process. If this + value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value + zero indicates stop immediately via the + kill signal (no opportunity to shut down). + This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. + If this is not set, reads from stdin in the + container will always result in EOF. Default + is false. + type: boolean + stdinOnce: + description: Whether the container runtime should + close the stdin channel after it has been + opened by a single attach. When stdin is true + the stdin stream will remain open across multiple + attach sessions. If stdinOnce is set to true, + stdin is opened on container start, is empty + until the first client attaches to stdin, + and then remains open and accepts data until + the client disconnects, at which time stdin + is closed and remains closed until the container + is restarted. If this flag is false, a container + processes that reads from stdin will never + receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file + to which the container''s termination message + will be written is mounted into the container''s + filesystem. Message written is intended to + be brief final status, such as an assertion + failure message. Will be truncated by the + node if greater than 4096 bytes. The total + message length across all containers will + be limited to 12kb. Defaults to /dev/termination-log. + Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message + should be populated. File will use the contents + of terminationMessagePath to populate the + container status message on both success and + failure. FallbackToLogsOnError will use the + last chunk of container log output if the + termination message file is empty and the + container exited with an error. The log output + is limited to 2048 bytes or 80 lines, whichever + is smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to + be true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block + devices to be used by the container. + items: + description: volumeDevice describes a mapping + of a raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside + of the container that the device will + be mapped to. + type: string + name: + description: name must match the name + of a persistentVolumeClaim in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting + of a Volume within a container. + properties: + mountPath: + description: Path within the container + at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines + how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is + used. This field is beta in 1.10. + type: string + name: + description: This must match the Name + of a Volume. + type: string + readOnly: + description: Mounted read-only if true, + read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + subPath: + description: Path within the volume from + which the container's volume should + be mounted. Defaults to "" (volume's + root). + type: string + subPathExpr: + description: Expanded path within the + volume from which the container's volume + should be mounted. Behaves similarly + to SubPath but environment variable + references $(VAR_NAME) are expanded + using the container's environment. Defaults + to "" (volume's root). SubPathExpr and + SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. + If not specified, the container runtime's + default will be used, which might be configured + in the container image. Cannot be updated. + type: string + required: + - name + type: object + volumes: + description: Volumes is a list of volumes that can + be mounted by containers in a template. + items: + description: Volume represents a named volume + in a pod that may be accessed by any container + in the pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents + an AWS Disk resource that is attached to + a kubelet''s host machine and then exposed + to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem + type of the volume that you want to + mount. Tip: Ensure that the filesystem + type is supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + partition: + description: 'partition is the partition + in the volume that you want to mount. + If omitted, the default is to mount + by volume name. Examples: For volume + /dev/sda1, you specify the partition + as "1". Similarly, the volume partition + for /dev/sda is "0" (or you can leave + the property empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will + force the readOnly setting in VolumeMounts. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of + the persistent disk resource in AWS + (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure + Data Disk mount on the host and bind mount + to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host + Caching mode: None, Read Only, Read + Write.' + type: string + diskName: + description: diskName is the Name of the + data disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data + disk in the blob storage + type: string + fsType: + description: fsType is Filesystem type + to mount. Must be a filesystem type + supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are + Shared: multiple blob disks per storage + account Dedicated: single blob disk + per storage account Managed: azure + managed data disk (only in managed availability + set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure + File Service mount on the host and bind + mount to the pod. + properties: + readOnly: + description: readOnly defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of + secret that contains Azure Storage Account + Name and Key + type: string + shareName: + description: shareName is the azure share + Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount + on the host that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors + is a collection of Ceph monitors More + info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as + the mounted root, rather than the full + Ceph tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here + will force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: + SecretFile is the path to key ring for + User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef + is reference to the authentication secret + for User, default is empty. More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is + the rados user name, default is admin + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume + attached and mounted on kubelets host machine. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if + unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points + to a secret object containing parameters + used to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify + the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap + that should populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: + mode bits used to set permissions on + created files by default. Must be an + octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML + accepts both octal and decimal values, + JSON requires decimal values for mode + bits. Defaults to 0644. Directories + within the path are not affected by + this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + items: + description: items if unspecified, each + key-value pair in the Data field of + the referenced ConfigMap will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will be + projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not present + in the ConfigMap, the volume setup will + error unless it is marked optional. + Paths must be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key to a + path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 or + a decimal value between 0 and + 511. YAML accepts both octal and + decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume defaultMode + will be used. This might be in + conflict with other options that + affect the file mode, like fsGroup, + and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the key + to. May not be an absolute path. + May not contain the path element + '..'. May not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) + represents ephemeral storage that is handled + by certain external CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the + CSI driver that handles this volume. + Consult with your admin for the correct + name as registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", + "xfs", "ntfs". If not provided, the + empty value is passed to the associated + CSI driver which will determine the + default filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a + reference to the secret object containing + sensitive information to pass to the + CSI driver to complete the CSI NodePublishVolume + and NodeUnpublishVolume calls. This + field is optional, and may be empty + if no secret is required. If the secret + object contains more than one secret, + all secret references are passed. + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only + configuration for the volume. Defaults + to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI + driver. Consult your driver's documentation + for supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward + API about the pod that should populate this + volume + properties: + defaultMode: + description: 'Optional: mode bits to use + on created files by default. Must be + a Optional: mode bits used to set permissions + on created files by default. Must be + an octal value between 0000 and 0777 + or a decimal value between 0 and 511. + YAML accepts both octal and decimal + values, JSON requires decimal values + for mode bits. Defaults to 0644. Directories + within the path are not affected by + this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + items: + description: Items is a list of downward + API volume file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only annotations, + labels, name and namespace are + supported.' + properties: + apiVersion: + description: Version of the + schema the FieldPath is written + in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field + to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits + used to set permissions on this + file, must be an octal value between + 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts + both octal and decimal values, + JSON requires decimal values for + mode bits. If not specified, the + volume defaultMode will be used. + This might be in conflict with + other options that affect the + file mode, like fsGroup, and the + result can be other mode bits + set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file + to be created. Must not be absolute + or contain the ''..'' path. Must + be utf-8 encoded. The first item + of the relative path must not + start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource + of the container: only resources + limits and requests (limits.cpu, + limits.memory, requests.cpu and + requests.memory) are currently + supported.' + properties: + containerName: + description: 'Container name: + required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary + directory that shares a pod''s lifetime. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type + of storage medium should back this directory. + The default is "" which means to use + the node''s default medium. Must be + an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount + of local storage required for this EmptyDir + volume. The size limit is also applicable + for memory medium. The maximum usage + on memory medium EmptyDir would be the + minimum value between the SizeLimit + specified here and the sum of memory + limits of all containers in a pod. The + default is nil which means that the + limit is undefined. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume + that is handled by a cluster storage driver. + The volume's lifecycle is tied to the pod + that defines it - it will be created before + the pod starts, and deleted when the pod + is removed. \n Use this if: a) the volume + is only needed while the pod runs, b) features + of normal volumes like restoring from snapshot + or capacity tracking are needed, c) the + storage driver is specified through a storage + class, and d) the storage driver supports + dynamic volume provisioning through a PersistentVolumeClaim + (see EphemeralVolumeSource for more information + on the connection between this volume type + and PersistentVolumeClaim). \n Use PersistentVolumeClaim + or one of the vendor-specific APIs for volumes + that persist for longer than the lifecycle + of an individual pod. \n Use CSI for light-weight + local ephemeral volumes if the CSI driver + is meant to be used that way - see the documentation + of the driver for more information. \n A + pod can use both types of ephemeral volumes + and persistent volumes at the same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a + stand-alone PVC to provision the volume. + The pod in which this EphemeralVolumeSource + is embedded will be the owner of the + PVC, i.e. the PVC will be deleted together + with the pod. The name of the PVC will + be `-` where + `` is the name from the + `PodSpec.Volumes` array entry. Pod validation + will reject the pod if the concatenated + name is not valid for a PVC (for example, + too long). \n An existing PVC with that + name that is not owned by the pod will + *not* be used for the pod to avoid using + an unrelated volume by mistake. Starting + the pod is then blocked until the unrelated + PVC is removed. If such a pre-created + PVC is meant to be used by the pod, + the PVC has to updated with an owner + reference to the pod once the pod exists. + Normally this should not be necessary, + but it may be useful when manually reconstructing + a broken cluster. \n This field is read-only + and no changes will be made by Kubernetes + to the PVC after it has been created. + \n Required, must not be nil." + properties: + metadata: + description: May contain labels and + annotations that will be copied + into the PVC when creating it. No + other fields are allowed and will + be rejected during validation. + type: object + spec: + description: The specification for + the PersistentVolumeClaim. The entire + content is copied unchanged into + the PVC that gets created from this + template. The same fields as in + a PersistentVolumeClaim are also + valid here. + properties: + accessModes: + description: 'accessModes contains + the desired access modes the + volume should have. More info: + https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field + can be used to specify either: + * An existing VolumeSnapshot + object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external + controller can support the specified + data source, it will create + a new volume based on the contents + of the specified data source. + When the AnyVolumeDataSource + feature gate is enabled, dataSource + contents will be copied to dataSourceRef, + and dataSourceRef contents will + be copied to dataSource when + dataSourceRef.namespace is not + specified. If the namespace + is specified, then dataSourceRef + will not be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the + group for the resource being + referenced. If APIGroup + is not specified, the specified + Kind must be in the core + API group. For any other + third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies + the object from which to populate + the volume with data, if a non-empty + volume is desired. This may + be any object from a non-empty + API group (non core object) + or a PersistentVolumeClaim object. + When this field is specified, + volume binding will only succeed + if the type of the specified + object matches some installed + volume populator or dynamic + provisioner. This field will + replace the functionality of + the dataSource field and as + such if both fields are non-empty, + they must have the same value. + For backwards compatibility, + when namespace isn''t specified + in dataSourceRef, both fields + (dataSource and dataSourceRef) + will be set to the same value + automatically if one of them + is empty and the other is non-empty. + When namespace is specified + in dataSourceRef, dataSource + isn''t set to the same value + and must be empty. There are + three important differences + between dataSource and dataSourceRef: + * While dataSource only allows + two specific types of objects, + dataSourceRef allows any non-core + object, as well as PersistentVolumeClaim + objects. * While dataSource + ignores disallowed values (dropping + them), dataSourceRef preserves + all values, and generates an + error if a disallowed value + is specified. * While dataSource + only allows local objects, dataSourceRef + allows objects in any namespaces. + (Beta) Using this field requires + the AnyVolumeDataSource feature + gate to be enabled. (Alpha) + Using the namespace field of + dataSourceRef requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the + group for the resource being + referenced. If APIGroup + is not specified, the specified + Kind must be in the core + API group. For any other + third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + namespace: + description: Namespace is + the namespace of resource + being referenced Note that + when a namespace is specified, + a gateway.networking.k8s.io/ReferenceGrant + object is required in the + referent namespace to allow + that namespace's owner to + accept the reference. See + the ReferenceGrant documentation + for details. (Alpha) This + field requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents + the minimum resources the volume + should have. If RecoverVolumeExpansionFailure + feature is enabled users are + allowed to specify resource + requirements that are lower + than previous value but must + still be higher than capacity + recorded in the status field + of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists + the names of resources, + defined in spec.resourceClaims, + that are used by this container. + \n This is an alpha field + and requires enabling the + DynamicResourceAllocation + feature gate. \n This field + is immutable. It can only + be set for containers." + items: + description: ResourceClaim + references one entry in + PodSpec.ResourceClaims. + properties: + name: + description: Name must + match the name of + one entry in pod.spec.resourceClaims + of the Pod where this + field is used. It + makes that resource + available inside a + container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes + the maximum amount of compute + resources allowed. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes + the minimum amount of compute + resources required. If Requests + is omitted for a container, + it defaults to Limits if + that is explicitly specified, + otherwise to an implementation-defined + value. Requests cannot exceed + Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label + query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, + a key, and an operator + that relates the key and + values. + properties: + key: + description: key is + the label key that + the selector applies + to. + type: string + operator: + description: operator + represents a key's + relationship to a + set of values. Valid + operators are In, + NotIn, Exists and + DoesNotExist. + type: string + values: + description: values + is an array of string + values. If the operator + is In or NotIn, the + values array must + be non-empty. If the + operator is Exists + or DoesNotExist, the + values array must + be empty. This array + is replaced during + a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is + a map of {key,value} pairs. + A single {key,value} in + the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", + the operator is "In", and + the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName + is the name of the StorageClass + required by the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines + what type of volume is required + by the claim. Value of Filesystem + is implied when not included + in claim spec. + type: string + volumeName: + description: volumeName is the + binding reference to the PersistentVolume + backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel + resource that is attached to a kubelet's + host machine and then exposed to the pod. + properties: + fsType: + description: 'fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target + lun number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here + will force the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: + FC target worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume + world wide identifiers (wwids) Either + wwids or combination of targetWWNs and + lun must be set, but not both simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic + volume resource that is provisioned/attached + using an exec based plugin. + properties: + driver: + description: driver is the name of the + driver to use for this volume. + type: string + fsType: + description: fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". The + default filesystem depends on FlexVolume + script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this + field holds extra command options if + any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults + to false (read/write). ReadOnly here + will force the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef + is reference to the secret object containing + sensitive information to pass to the + plugin scripts. This may be empty if + no secret object is specified. If the + secret object contains more than one + secret, all secrets are passed to the + plugin scripts.' + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker + volume attached to a kubelet's host machine. + This depends on the Flocker control service + being running + properties: + datasetName: + description: datasetName is Name of the + dataset stored as metadata -> name on + the dataset for Flocker should be considered + as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of + the dataset. This is unique identifier + of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents + a GCE Disk resource that is attached to + a kubelet''s host machine and then exposed + to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type + of the volume that you want to mount. + Tip: Ensure that the filesystem type + is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + partition: + description: 'partition is the partition + in the volume that you want to mount. + If omitted, the default is to mount + by volume name. Examples: For volume + /dev/sda1, you specify the partition + as "1". Similarly, the volume partition + for /dev/sda is "0" (or you can leave + the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of + the PD resource in GCE. Used to identify + the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force + the ReadOnly setting in VolumeMounts. + Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository + at a particular revision. DEPRECATED: GitRepo + is deprecated. To provision a container + with a git repo, mount an EmptyDir into + an InitContainer that clones the repo using + git, then mount the EmptyDir into the Pod''s + container.' + properties: + directory: + description: directory is the target directory + name. Must not contain or start with + '..'. If '.' is supplied, the volume + directory will be the git repository. Otherwise, + if specified, the volume will contain + the git repository in the subdirectory + with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash + for the specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint + name that details Glusterfs topology. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume + path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force + the Glusterfs volume to be mounted with + read-only permissions. Defaults to false. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing + file or directory on the host machine that + is directly exposed to the container. This + is generally used for system agents or other + privileged things that are allowed to see + the host machine. Most containers will NOT + need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who + can use host directory mounts and who can/can + not mount host directories as read/write.' + properties: + path: + description: 'path of the directory on + the host. If the path is a symlink, + it will follow the link to the real + path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume + Defaults to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk + resource that is attached to a kubelet''s + host machine and then exposed to the pod. + More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines + whether support iSCSI Discovery CHAP + authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether + support iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem + type of the volume that you want to + mount. Tip: Ensure that the filesystem + type is supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom + iSCSI Initiator Name. If initiatorName + is specified with iscsiInterface simultaneously, + new iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified + Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface + Name that uses an iSCSI transport. Defaults + to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target + Lun number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target + Portal List. The portal is either an + IP or ip_addr:port if the port is other + than default (typically TCP ports 860 + and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force + the ReadOnly setting in VolumeMounts. + Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret + for iSCSI target and initiator authentication + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target + Portal. The Portal is either an IP or + ip_addr:port if the port is other than + default (typically TCP ports 860 and + 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be + a DNS_LABEL and unique within the pod. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount + on the host that shares a pod''s lifetime + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by + the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force + the NFS export to be mounted with read-only + permissions. Defaults to false. More + info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or + IP address of the NFS server. More info: + https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource + represents a reference to a PersistentVolumeClaim + in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of + a PersistentVolumeClaim in the same + namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents + a PhotonController persistent disk attached + and mounted on kubelets host machine + properties: + fsType: + description: fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies + Photon Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx + volume attached and mounted on kubelets + host machine + properties: + fsType: + description: fSType represents the filesystem + type to mount Must be a filesystem type + supported by the host operating system. + Ex. "ext4", "xfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies + a Portworx volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one + resources secrets, configmaps, and downward + API + properties: + defaultMode: + description: defaultMode are the mode + bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both + octal and decimal values, JSON requires + decimal values for mode bits. Directories + within the path are not affected by + this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume + projections + items: + description: Projection that may be + projected along with other supported + volume types + properties: + configMap: + description: configMap information + about the configMap data to project + properties: + items: + description: items if unspecified, + each key-value pair in the + Data field of the referenced + ConfigMap will be projected + into the volume as a file + whose name is the key and + content is the value. If specified, + the listed keys will be projected + into the specified paths, + and unlisted keys will not + be present. If a key is specified + which is not present in the + ConfigMap, the volume setup + will error unless it is marked + optional. Paths must be relative + and may not contain the '..' + path or start with '..'. + items: + description: Maps a string + key to a path within a volume. + properties: + key: + description: key is the + key to project. + type: string + mode: + description: 'mode is + Optional: mode bits + used to set permissions + on this file. Must be + an octal value between + 0000 and 0777 or a decimal + value between 0 and + 511. YAML accepts both + octal and decimal values, + JSON requires decimal + values for mode bits. + If not specified, the + volume defaultMode will + be used. This might + be in conflict with + other options that affect + the file mode, like + fsGroup, and the result + can be other mode bits + set.' + format: int32 + type: integer + path: + description: path is the + relative path of the + file to map the key + to. May not be an absolute + path. May not contain + the path element '..'. + May not start with the + string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: optional specify + whether the ConfigMap or its + keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information + about the downwardAPI data to + project + properties: + items: + description: Items is a list + of DownwardAPIVolume file + items: + description: DownwardAPIVolumeFile + represents information to + create the file containing + the pod field + properties: + fieldRef: + description: 'Required: + Selects a field of the + pod: only annotations, + labels, name and namespace + are supported.' + properties: + apiVersion: + description: Version + of the schema the + FieldPath is written + in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path + of the field to + select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: + mode bits used to set + permissions on this + file, must be an octal + value between 0000 and + 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and + decimal values, JSON + requires decimal values + for mode bits. If not + specified, the volume + defaultMode will be + used. This might be + in conflict with other + options that affect + the file mode, like + fsGroup, and the result + can be other mode bits + set.' + format: int32 + type: integer + path: + description: 'Required: + Path is the relative + path name of the file + to be created. Must + not be absolute or contain + the ''..'' path. Must + be utf-8 encoded. The + first item of the relative + path must not start + with ''..''' + type: string + resourceFieldRef: + description: 'Selects + a resource of the container: + only resources limits + and requests (limits.cpu, + limits.memory, requests.cpu + and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container + name: required for + volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies + the output format + of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: + resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information + about the secret data to project + properties: + items: + description: items if unspecified, + each key-value pair in the + Data field of the referenced + Secret will be projected into + the volume as a file whose + name is the key and content + is the value. If specified, + the listed keys will be projected + into the specified paths, + and unlisted keys will not + be present. If a key is specified + which is not present in the + Secret, the volume setup will + error unless it is marked + optional. Paths must be relative + and may not contain the '..' + path or start with '..'. + items: + description: Maps a string + key to a path within a volume. + properties: + key: + description: key is the + key to project. + type: string + mode: + description: 'mode is + Optional: mode bits + used to set permissions + on this file. Must be + an octal value between + 0000 and 0777 or a decimal + value between 0 and + 511. YAML accepts both + octal and decimal values, + JSON requires decimal + values for mode bits. + If not specified, the + volume defaultMode will + be used. This might + be in conflict with + other options that affect + the file mode, like + fsGroup, and the result + can be other mode bits + set.' + format: int32 + type: integer + path: + description: path is the + relative path of the + file to map the key + to. May not be an absolute + path. May not contain + the path element '..'. + May not start with the + string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: optional field + specify whether the Secret + or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken + is information about the serviceAccountToken + data to project + properties: + audience: + description: audience is the + intended audience of the token. + A recipient of a token must + identify itself with an identifier + specified in the audience + of the token, and otherwise + should reject the token. The + audience defaults to the identifier + of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds + is the requested duration + of validity of the service + account token. As the token + approaches expiration, the + kubelet volume plugin will + proactively rotate the service + account token. The kubelet + will start trying to rotate + the token if the token is + older than 80 percent of its + time to live or if the token + is older than 24 hours.Defaults + to 1 hour and must be at least + 10 minutes. + format: int64 + type: integer + path: + description: path is the path + relative to the mount point + of the file to project the + token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte + mount on the host that shares a pod's lifetime + properties: + group: + description: group to map volume access + to Default is no group + type: string + readOnly: + description: readOnly here will force + the Quobyte volume to be mounted with + read-only permissions. Defaults to false. + type: boolean + registry: + description: registry represents a single + or multiple Quobyte Registry services + specified as a string as host:port pair + (multiple entries are separated with + commas) which acts as the central registry + for volumes + type: string + tenant: + description: tenant owning the given Quobyte + volume in the Backend Used with dynamically + provisioned Quobyte volumes, value is + set by the plugin + type: string + user: + description: user to map volume access + to Defaults to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by + name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block + Device mount on the host that shares a pod''s + lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem + type of the volume that you want to + mount. Tip: Ensure that the filesystem + type is supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + image: + description: 'image is the rados image + name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key + ring for RBDUser. Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection + of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. + Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force + the ReadOnly setting in VolumeMounts. + Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the + authentication secret for RBDUser. If + provided overrides keyring. Default + is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. + Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO + persistent volume attached and mounted on + Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Default + is "xfs". + type: string + gateway: + description: gateway is the host address + of the ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name + of the ScaleIO Protection Domain for + the configured storage. + type: string + readOnly: + description: readOnly Defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the + secret for ScaleIO user and other sensitive + information. If this is not provided, + Login operation will fail. + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable + SSL communication with Gateway, default + false + type: boolean + storageMode: + description: storageMode indicates whether + the storage for a volume should be ThickProvisioned + or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO + Storage Pool associated with the protection + domain. + type: string + system: + description: system is the name of the + storage system as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of + a volume already created in the ScaleIO + system that is associated with this + volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that + should populate this volume. More info: + https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: + mode bits used to set permissions on + created files by default. Must be an + octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML + accepts both octal and decimal values, + JSON requires decimal values for mode + bits. Defaults to 0644. Directories + within the path are not affected by + this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + items: + description: items If unspecified, each + key-value pair in the Data field of + the referenced Secret will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will be + projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not present + in the Secret, the volume setup will + error unless it is marked optional. + Paths must be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key to a + path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 or + a decimal value between 0 and + 511. YAML accepts both octal and + decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume defaultMode + will be used. This might be in + conflict with other options that + affect the file mode, like fsGroup, + and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the key + to. May not be an absolute path. + May not contain the path element + '..'. May not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether + the Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of + the secret in the pod''s namespace to + use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS + volume attached and mounted on Kubernetes + nodes. + properties: + fsType: + description: fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret + to use for obtaining the StorageOS API + credentials. If not specified, default + values will be attempted. + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable + name of the StorageOS volume. Volume + names are only unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies + the scope of the volume within StorageOS. If + no namespace is specified then the Pod's + namespace will be used. This allows + the Kubernetes name scoping to be mirrored + within StorageOS for tighter integration. + Set VolumeName to any name to override + the default behaviour. Set to "default" + if you are not using namespaces within + StorageOS. Namespaces that do not pre-exist + within StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere + volume attached and mounted on kubelets + host machine + properties: + fsType: + description: fsType is filesystem type + to mount. Must be a filesystem type + supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage + Policy Based Management (SPBM) profile + ID associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the + storage Policy Based Management (SPBM) + profile name. + type: string + volumePath: + description: volumePath is the path that + identifies vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + templateType: + type: string + timeChaos: + description: TimeChaosSpec defines the desired state + of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock + id All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of + injected program. It's a possibly signed sequence + of decimal numbers, such as "300ms", "-1.5h" or + "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + required: + - name + - templateType + type: object + type: array + required: + - entry + - templates + type: object + required: + - schedule + - type + type: object + startTime: + format: date-time + type: string + statusCheck: + description: StatusCheck describe the behavior of StatusCheck. Only + used when Type is TypeStatusCheck. + properties: + duration: + description: Duration defines the duration of the whole status + check if the number of failed execution does not exceed the + failure threshold. Duration is available to both `Synchronous` + and `Continuous` mode. 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum consecutive + failure for the status check to be considered failed. + minimum: 1 + type: integer + http: + properties: + body: + type: string + criteria: + description: Criteria defines how to determine the result + of the status check. + properties: + statusCode: + description: StatusCode defines the expected http status + code for the request. A statusCode string could be a + single code (e.g. 200), or an inclusive range (e.g. + 200-400, both `200` and `400` are included). + type: string + required: + - statusCode + type: object + headers: + additionalProperties: + items: + type: string + type: array + description: "A Header represents the key-value pairs in an + HTTP header. \n The keys should be in canonical form, as + returned by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in seconds) to + perform an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of the status check. + Support type: Synchronous / Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number of record + to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum consecutive + successes for the status check to be considered successful. + SuccessThreshold only works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of seconds after + which an execution of status check times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check type. Support + type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + stressChaos: + description: StressChaosSpec defines the desired state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors just + like `Stressors` except that it's an experimental feature and + more powerful. You can define stressors in `stress-ng` (see + also `man stress-ng`) dialect, however not all of the supported + stressors are well tested. It maybe retired in later releases. + You should always use `Stressors` to define the stressors and + use this only when you want more stressors unsupported by `Stressors`. + When both `StressngStressors` and `Stressors` are defined, `StressngStressors` + wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported to + stress system components out. You can use one or more of them + to make up various kinds of stresses. At least one of the stressors + should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading per CPU + worker. 0 is effectively a sleep (no load) and 100 is + full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to apply the + stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj of the + stress process. See `man 5 proc` to know more about + this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per vm worker, + default is the total available memory. One can specify + the size as % of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to apply the + stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + type: object + task: + properties: + container: + description: Container is the main container image to run in the + pod + properties: + args: + description: 'Arguments to the entrypoint. The container image''s + CMD is used if this is not provided. Variable references + $(VAR_NAME) are expanded using the container''s environment. + If a variable cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced to a single + $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of + whether the variable exists or not. Cannot be updated. More + info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within a shell. + The container image''s ENTRYPOINT is used if this is not + provided. Variable references $(VAR_NAME) are expanded using + the container''s environment. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double + $$ are reduced to a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references will + never be expanded, regardless of whether the variable exists + or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables + in the container and any service environment variables. + If a variable cannot be resolved, the reference in + the input string will be unchanged. Double $$ are + reduced to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment variables + in the container. The keys defined within a source must + be a C_IDENTIFIER. All invalid keys will be reported as + an event when the container is starting. When a key exists + in multiple sources, the value associated with the last + source will take precedence. Values defined by an Env with + a duplicate key will take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to each + key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management + to default or override container images in workload controllers + like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent + otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system should take + in response to container lifecycle events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately after a + container is created. If the handler fails, the container + is terminated and restarted according to its restart + policy. Other management of the container blocks until + the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory + for the command is root ('/') in the container's + filesystem. The command is simply exec'd, it + is not run inside a shell, so traditional shell + instructions ('|', etc) won't work. To use a + shell, you need to explicitly call out to that + shell. Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to + perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the + host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of this field + and lifecycle hooks will fail in runtime when tcp + handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately before a container + is terminated due to an API request or management event + such as liveness/startup probe failure, preemption, + resource contention, etc. The handler is not called + if the container crashes or exits. The Pod''s termination + grace period countdown begins before the PreStop hook + is executed. Regardless of the outcome of the handler, + the container will eventually terminate within the Pod''s + termination grace period (unless delayed by finalizers). + Other management of the container blocks until the hook + completes or until the termination grace period is reached. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory + for the command is root ('/') in the container's + filesystem. The command is simply exec'd, it + is not run inside a shell, so traditional shell + instructions ('|', etc) won't work. To use a + shell, you need to explicitly call out to that + shell. Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to + perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the + host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of this field + and lifecycle hooks will fail in runtime when tcp + handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. Container + will be restarted if the probe fails. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', + etc) won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC + port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a + TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and + the time when the processes are forcibly halted with + a kill signal. Set this value longer than the expected + cleanup time for your process. If this value is nil, + the pod's terminationGracePeriodSeconds will be used. + Otherwise, this value overrides the value provided by + the pod spec. Value must be non-negative integer. The + value zero indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta field + and requires enabling ProbeTerminationGracePeriod feature + gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe + times out. Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. Not + specifying a port here DOES NOT prevent that port from being + exposed. Any port which is listening on the default "0.0.0.0" + address inside a container will be accessible from the network. + Modifying this array with strategic merge patch may corrupt + the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port in + a single container. + properties: + containerPort: + description: Number of port to expose on the pod's IP + address. This must be a valid port number, 0 < x < + 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external port + to. + type: string + hostPort: + description: Number of port to expose on the host. If + specified, this must be a valid port number, 0 < x + < 65536. If HostNetwork is specified, this must match + ContainerPort. Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an IANA_SVC_NAME + and unique within the pod. Each named port in a pod + must have a unique name. Name for the port that can + be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, TCP, or + SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service readiness. + Container will be removed from service endpoints if the + probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', + etc) won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC + port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a + TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and + the time when the processes are forcibly halted with + a kill signal. Set this value longer than the expected + cleanup time for your process. If this value is nil, + the pod's terminationGracePeriodSeconds will be used. + Otherwise, this value overrides the value provided by + the pod spec. Value must be non-negative integer. The + value zero indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta field + and requires enabling ProbeTerminationGracePeriod feature + gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe + times out. Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource resize + policy for the container. + properties: + resourceName: + description: 'Name of the resource to which this resource + resize policy applies. Supported values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when specified + resource is resized. If not specified, it defaults + to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this container. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. \n This field + is immutable. It can only be set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry + in pod.spec.resourceClaims of the Pod where this + field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of + compute resources required. If Requests is omitted for + a container, it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined value. + Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + restartPolicy: + description: 'RestartPolicy defines the restart behavior of + individual containers in a pod. This field may only be set + for init containers, and the only allowed value is "Always". + For non-init containers or when this field is not specified, + the restart behavior is defined by the Pod''s restart policy + and the container type. Setting the RestartPolicy as "Always" + for the init container will have the following effect: this + init container will be continually restarted on exit until + all regular containers have terminated. Once all regular + containers have completed, all init containers with restartPolicy + "Always" will be shut down. This lifecycle differs from + normal init containers and is often referred to as a "sidecar" + container. Although this init container still starts in + the init container sequence, it does not wait for the container + to complete before proceeding to the next init container. + Instead, the next init container starts immediately after + this init container is started, or after any startupProbe + has successfully completed.' + type: string + securityContext: + description: 'SecurityContext defines the security options + the container should be run with. If set, the fields of + SecurityContext override the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether + a process can gain more privileges than its parent process. + This bool directly controls if the no_new_privs flag + will be set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run as Privileged + 2) has CAP_SYS_ADMIN Note that this field cannot be + set when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running + containers. Defaults to the default set of capabilities + granted by the container runtime. Note that this field + cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes + in privileged containers are essentially equivalent + to root on the host. Defaults to false. Note that this + field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc mount + to use for the containers. The default is DefaultProcMount + which uses the container runtime defaults for readonly + paths and masked paths. This requires the ProcMountType + feature flag to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root + filesystem. Default is false. Note that this field cannot + be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set + when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as + a non-root user. If true, the Kubelet will validate + the image at runtime to ensure that it does not run + as UID 0 (root) and fail to start the container if it + does. If unset or false, no such validation will be + performed. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container + process. Defaults to user specified in image metadata + if unspecified. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to the + container. If unspecified, the container runtime will + allocate a random SELinux context for each container. May + also be set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set + when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this container. + If seccomp options are provided at both the pod & container + level, the container options override the pod options. + Note that this field cannot be set when spec.os.name + is windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. The + profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's + configured seccomp profile location. Must be set + if type is "Localhost". Must NOT be set for any + other type. + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: \n Localhost + - a profile defined in a file on the node should + be used. RuntimeDefault - the container runtime + default profile should be used. Unconfined - no + profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied to + all containers. If unspecified, the options from the + PodSecurityContext will be used. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set + when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA + admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec + named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of + the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. All + of a Pod's containers must have the same effective + HostProcess value (it is not allowed to have a mix + of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork + must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set + in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the Pod has successfully + initialized. If specified, no other probes are executed + until this completes successfully. If this probe fails, + the Pod will be restarted, just as if the livenessProbe + failed. This can be used to provide different probe parameters + at the beginning of a Pod''s lifecycle, when it might take + a long time to load data or warm a cache, than during steady-state + operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', + etc) won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC + port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a + TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and + the time when the processes are forcibly halted with + a kill signal. Set this value longer than the expected + cleanup time for your process. If this value is nil, + the pod's terminationGracePeriodSeconds will be used. + Otherwise, this value overrides the value provided by + the pod spec. Value must be non-negative integer. The + value zero indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta field + and requires enabling ProbeTerminationGracePeriod feature + gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe + times out. Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate a buffer + for stdin in the container runtime. If this is not set, + reads from stdin in the container will always result in + EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close the + stdin channel after it has been opened by a single attach. + When stdin is true the stdin stream will remain open across + multiple attach sessions. If stdinOnce is set to true, stdin + is opened on container start, is empty until the first client + attaches to stdin, and then remains open and accepts data + until the client disconnects, at which time stdin is closed + and remains closed until the container is restarted. If + this flag is false, a container processes that reads from + stdin will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to which the + container''s termination message will be written is mounted + into the container''s filesystem. Message written is intended + to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. + The total message length across all containers will be limited + to 12kb. Defaults to /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message should be + populated. File will use the contents of terminationMessagePath + to populate the container status message on both success + and failure. FallbackToLogsOnError will use the last chunk + of container log output if the termination message file + is empty and the container exited with an error. The log + output is limited to 2048 bytes or 80 lines, whichever is + smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate a TTY + for itself, also requires 'stdin' to be true. Default is + false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to + be used by the container. + items: + description: volumeDevice describes a mapping of a raw block + device within a container. + properties: + devicePath: + description: devicePath is the path inside of the container + that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's filesystem. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a Volume + within a container. + properties: + mountPath: + description: Path within the container at which the + volume should be mounted. Must not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts + are propagated from the host to container and the + other way around. When not set, MountPropagationNone + is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write otherwise + (false or unspecified). Defaults to false. + type: boolean + subPath: + description: Path within the volume from which the container's + volume should be mounted. Defaults to "" (volume's + root). + type: string + subPathExpr: + description: Expanded path within the volume from which + the container's volume should be mounted. Behaves + similarly to SubPath but environment variable references + $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). SubPathExpr and SubPath + are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not specified, + the container runtime's default will be used, which might + be configured in the container image. Cannot be updated. + type: string + required: + - name + type: object + volumes: + description: Volumes is a list of volumes that can be mounted + by containers in a template. + items: + description: Volume represents a named volume in a pod that + may be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents an AWS Disk + resource that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume + that you want to mount. If omitted, the default is + to mount by volume name. Examples: For volume /dev/sda1, + you specify the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can leave the + property empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force the readOnly + setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the persistent + disk resource in AWS (Amazon EBS volume). More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data Disk mount + on the host and bind mount to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching mode: + None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data disk in + the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in the + blob storage + type: string + fsType: + description: fsType is Filesystem type to mount. Must + be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: multiple + blob disks per storage account Dedicated: single + blob disk per storage account Managed: azure managed + data disk (only in managed availability set). defaults + to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File Service + mount on the host and bind mount to the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret that + contains Azure Storage Account Name and Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount on the host + that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors is a collection + of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the mounted + root, rather than the full Ceph tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile is + the path to key ring for User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef is reference + to the authentication secret for User, default is + empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the rados user + name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume attached + and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points to a secret + object containing parameters used to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the volume in + cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that should + populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value pair + in the Data field of the referenced ConfigMap will + be projected into the volume as a file whose name + is the key and content is the value. If specified, + the listed keys will be projected into the specified + paths, and unlisted keys will not be present. If a + key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. + Paths must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within a + volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used + to set permissions on this file. Must be an + octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal values + for mode bits. If not specified, the volume + defaultMode will be used. This might be in conflict + with other options that affect the file mode, + like fsGroup, and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative path of the + file to map the key to. May not be an absolute + path. May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents + ephemeral storage that is handled by certain external + CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI driver that + handles this volume. Consult with your admin for the + correct name as registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the + associated CSI driver which will determine the default + filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference to + the secret object containing sensitive information + to pass to the CSI driver to complete the CSI NodePublishVolume + and NodeUnpublishVolume calls. This field is optional, + and may be empty if no secret is required. If the + secret object contains more than one secret, all secret + references are passed. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only configuration + for the volume. Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. Consult + your driver's documentation for supported values. + type: object + required: + - driver type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key that the selector - applies to. + downwardAPI: + description: downwardAPI represents downward API about the + pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on created + files by default. Must be a Optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + items: + description: Items is a list of downward API volume + file + items: + description: DownwardAPIVolumeFile represents information + to create the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects a field of the + pod: only annotations, labels, name and namespace + are supported.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used to set + permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for mode + bits. If not specified, the volume defaultMode + will be used. This might be in conflict with + other options that affect the file mode, like + fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must not + be absolute or contain the ''..'' path. Must + be utf-8 encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary directory + that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type of storage + medium should back this directory. The default is + "" which means to use the node''s default medium. + Must be an empty string (default) or Memory. More + info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount of local + storage required for this EmptyDir volume. The size + limit is also applicable for memory medium. The maximum + usage on memory medium EmptyDir would be the minimum + value between the SizeLimit specified here and the + sum of memory limits of all containers in a pod. The + default is nil which means that the limit is undefined. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume that is handled + by a cluster storage driver. The volume's lifecycle is + tied to the pod that defines it - it will be created before + the pod starts, and deleted when the pod is removed. \n + Use this if: a) the volume is only needed while the pod + runs, b) features of normal volumes like restoring from + snapshot or capacity tracking are needed, c) the storage + driver is specified through a storage class, and d) the + storage driver supports dynamic volume provisioning through + a PersistentVolumeClaim (see EphemeralVolumeSource for + more information on the connection between this volume + type and PersistentVolumeClaim). \n Use PersistentVolumeClaim + or one of the vendor-specific APIs for volumes that persist + for longer than the lifecycle of an individual pod. \n + Use CSI for light-weight local ephemeral volumes if the + CSI driver is meant to be used that way - see the documentation + of the driver for more information. \n A pod can use both + types of ephemeral volumes and persistent volumes at the + same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone PVC + to provision the volume. The pod in which this EphemeralVolumeSource + is embedded will be the owner of the PVC, i.e. the + PVC will be deleted together with the pod. The name + of the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` + array entry. Pod validation will reject the pod if + the concatenated name is not valid for a PVC (for + example, too long). \n An existing PVC with that name + that is not owned by the pod will *not* be used for + the pod to avoid using an unrelated volume by mistake. + Starting the pod is then blocked until the unrelated + PVC is removed. If such a pre-created PVC is meant + to be used by the pod, the PVC has to updated with + an owner reference to the pod once the pod exists. + Normally this should not be necessary, but it may + be useful when manually reconstructing a broken cluster. + \n This field is read-only and no changes will be + made by Kubernetes to the PVC after it has been created. + \n Required, must not be nil." + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when creating + it. No other fields are allowed and will be rejected + during validation. + type: object + spec: + description: The specification for the PersistentVolumeClaim. + The entire content is copied unchanged into the + PVC that gets created from this template. The + same fields as in a PersistentVolumeClaim are + also valid here. + properties: + accessModes: + description: 'accessModes contains the desired + access modes the volume should have. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can be used to + specify either: * An existing VolumeSnapshot + object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller + can support the specified data source, it + will create a new volume based on the contents + of the specified data source. When the AnyVolumeDataSource + feature gate is enabled, dataSource contents + will be copied to dataSourceRef, and dataSourceRef + contents will be copied to dataSource when + dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef + will not be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the group for the + resource being referenced. If APIGroup + is not specified, the specified Kind must + be in the core API group. For any other + third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies the object + from which to populate the volume with data, + if a non-empty volume is desired. This may + be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding + will only succeed if the type of the specified + object matches some installed volume populator + or dynamic provisioner. This field will replace + the functionality of the dataSource field + and as such if both fields are non-empty, + they must have the same value. For backwards + compatibility, when namespace isn''t specified + in dataSourceRef, both fields (dataSource + and dataSourceRef) will be set to the same + value automatically if one of them is empty + and the other is non-empty. When namespace + is specified in dataSourceRef, dataSource + isn''t set to the same value and must be empty. + There are three important differences between + dataSource and dataSourceRef: * While dataSource + only allows two specific types of objects, + dataSourceRef allows any non-core object, + as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values + (dropping them), dataSourceRef preserves all + values, and generates an error if a disallowed + value is specified. * While dataSource only + allows local objects, dataSourceRef allows + objects in any namespaces. (Beta) Using this + field requires the AnyVolumeDataSource feature + gate to be enabled. (Alpha) Using the namespace + field of dataSourceRef requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the group for the + resource being referenced. If APIGroup + is not specified, the specified Kind must + be in the core API group. For any other + third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: Namespace is the namespace + of resource being referenced Note that + when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent namespace + to allow that namespace's owner to accept + the reference. See the ReferenceGrant + documentation for details. (Alpha) This + field requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents the minimum + resources the volume should have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed to specify + resource requirements that are lower than + previous value but must still be higher than + capacity recorded in the status field of the + claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the names of + resources, defined in spec.resourceClaims, + that are used by this container. \n This + is an alpha field and requires enabling + the DynamicResourceAllocation feature + gate. \n This field is immutable. It can + only be set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum + amount of compute resources allowed. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. + If Requests is omitted for a container, + it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined + value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName is the name of + the StorageClass required by the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type of + volume is required by the claim. Value of + Filesystem is implied when not included in + claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource that + is attached to a kubelet's host machine and then exposed + to the pod. + properties: + fsType: + description: 'fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. TODO: how do we prevent + errors in the filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target worldwide + names (WWNs)' + items: type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. + type: array + wwids: + description: 'wwids Optional: FC volume world wide identifiers + (wwids) Either wwids or combination of targetWWNs + and lun must be set, but not both simultaneously.' + items: type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. This - array is replaced during a strategic merge patch. - items: + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume resource + that is provisioned/attached using an exec based plugin. + properties: + driver: + description: driver is the name of the driver to use + for this volume. + type: string + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". The default filesystem + depends on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field holds + extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef is reference + to the secret object containing sensitive information + to pass to the plugin scripts. This may be empty if + no secret object is specified. If the secret object + contains more than one secret, all secrets are passed + to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. + type: object + x-kubernetes-map-type: atomic + required: + - driver type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. + flocker: + description: flocker represents a Flocker volume attached + to a kubelet's host machine. This depends on the Flocker + control service being running + properties: + datasetName: + description: datasetName is Name of the dataset stored + as metadata -> name on the dataset for Flocker should + be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. + This is unique identifier of a Flocker dataset + type: string type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE Disk resource + that is attached to a kubelet''s host machine and then + exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume + that you want to mount. If omitted, the default is + to mount by volume name. Examples: For volume /dev/sda1, + you specify the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can leave the + property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the PD resource + in GCE. Used to identify the disk in GCE. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of - a pod at the current time. supported value: Pending / - Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + gitRepo: + description: 'gitRepo represents a git repository at a particular + revision. DEPRECATED: GitRepo is deprecated. To provision + a container with a git repo, mount an EmptyDir into an + InitContainer that clones the repo using git, then mount + the EmptyDir into the Pod''s container.' + properties: + directory: + description: directory is the target directory name. + Must not contain or start with '..'. If '.' is supplied, + the volume directory will be the git repository. Otherwise, + if specified, the volume will contain the git repository + in the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the specified + revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs mount on + the host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name that details + Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume path. More + info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the Glusterfs + volume to be mounted with read-only permissions. Defaults + to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing file or + directory on the host machine that is directly exposed + to the container. This is generally used for system agents + or other privileged things that are allowed to see the + host machine. Most containers will NOT need this. More + info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can use host + directory mounts and who can/can not mount host directories + as read/write.' + properties: + path: + description: 'path of the directory on the host. If + the path is a symlink, it will follow the link to + the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults to "" + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource that + is attached to a kubelet''s host machine and then exposed + to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether support + iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support + iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI Initiator + Name. If initiatorName is specified with iscsiInterface + simultaneously, new iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface Name that + uses an iSCSI transport. Defaults to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal List. + The portal is either an IP or ip_addr:port if the + port is other than default (typically TCP ports 860 + and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the ReadOnly setting + in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for iSCSI + target and initiator authentication + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target Portal. The + Portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and + 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL and + unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the host that + shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the NFS export + to be mounted with read-only permissions. Defaults + to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP address of + the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource represents + a reference to a PersistentVolumeClaim in the same namespace. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly setting + in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets host + machine + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon Controller + persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx volume + attached and mounted on kubelets host machine + properties: + fsType: + description: fSType represents the filesystem type to + mount Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx + volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources secrets, + configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits used to set + permissions on created files by default. Must be an + octal value between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for mode bits. + Directories within the path are not affected by this + setting. This might be in conflict with other options + that affect the file mode, like fsGroup, and the result + can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume projections + items: + description: Projection that may be projected along + with other supported volume types + properties: + configMap: + description: configMap information about the configMap + data to project + properties: + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced + ConfigMap will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the ConfigMap, the volume setup will + error unless it is marked optional. Paths + must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether the + ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about the + downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used + to set permissions on this file, must + be an octal value between 0000 and + 0777 or a decimal value between 0 + and 511. YAML accepts both octal and + decimal values, JSON requires decimal + values for mode bits. If not specified, + the volume defaultMode will be used. + This might be in conflict with other + options that affect the file mode, + like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file to + be created. Must not be absolute or + contain the ''..'' path. Must be utf-8 + encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env + vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about the secret + data to project + properties: + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced + Secret will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the Secret, the volume setup will error + unless it is marked optional. Paths must + be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional field specify whether + the Secret or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to project + properties: + audience: + description: audience is the intended audience + of the token. A recipient of a token must + identify itself with an identifier specified + in the audience of the token, and otherwise + should reject the token. The audience defaults + to the identifier of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is the requested + duration of validity of the service account + token. As the token approaches expiration, + the kubelet volume plugin will proactively + rotate the service account token. The kubelet + will start trying to rotate the token if + the token is older than 80 percent of its + time to live or if the token is older than + 24 hours.Defaults to 1 hour and must be + at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative to + the mount point of the file to project the + token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount on the host + that shares a pod's lifetime + properties: + group: + description: group to map volume access to Default is + no group + type: string + readOnly: + description: readOnly here will force the Quobyte volume + to be mounted with read-only permissions. Defaults + to false. + type: boolean + registry: + description: registry represents a single or multiple + Quobyte Registry services specified as a string as + host:port pair (multiple entries are separated with + commas) which acts as the central registry for volumes + type: string + tenant: + description: tenant owning the given Quobyte volume + in the Backend Used with dynamically provisioned Quobyte + volumes, value is set by the plugin + type: string + user: + description: user to map volume access to Defaults to + serivceaccount user + type: string + volume: + description: volume is a string that references an already + created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device mount + on the host that shares a pod''s lifetime. More info: + https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + image: + description: 'image is the rados image name. More info: + https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring for RBDUser. + Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of Ceph monitors. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. Default is + rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. More info: + https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides keyring. + Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. Default is + admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent volume + attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of the ScaleIO + API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the ScaleIO + Protection Domain for the configured storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret for + ScaleIO user and other sensitive information. If this + is not provided, Login operation will fail. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL communication + with Gateway, default false + type: boolean + storageMode: + description: storageMode indicates whether the storage + for a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage Pool + associated with the protection domain. + type: string + system: + description: system is the name of the storage system + as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume already + created in the ScaleIO system that is associated with + this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that should populate + this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer items: + description: items If unspecified, each key-value pair + in the Data field of the referenced Secret will be + projected into the volume as a file whose name is + the key and content is the value. If specified, the + listed keys will be projected into the specified paths, + and unlisted keys will not be present. If a key is + specified which is not present in the Secret, the + volume setup will error unless it is marked optional. + Paths must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within a + volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used + to set permissions on this file. Must be an + octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal values + for mode bits. If not specified, the volume + defaultMode will be used. This might be in conflict + with other options that affect the file mode, + like fsGroup, and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative path of the + file to map the key to. May not be an absolute + path. May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether the Secret + or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the secret in + the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' type: string - type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. type: object + storageos: + description: storageOS represents a StorageOS volume attached + and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret to use for + obtaining the StorageOS API credentials. If not specified, + default values will be attempted. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable name of + the StorageOS volume. Volume names are only unique + within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the scope of + the volume within StorageOS. If no namespace is specified + then the Pod's namespace will be used. This allows + the Kubernetes name scoping to be mirrored within + StorageOS for tighter integration. Set VolumeName + to any name to override the default behaviour. Set + to "default" if you are not using namespaces within + StorageOS. Namespaces that do not pre-exist within + StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere volume attached + and mounted on kubelets host machine + properties: + fsType: + description: fsType is filesystem type to mount. Must + be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy Based + Management (SPBM) profile ID associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage Policy + Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name type: object - value: - description: TargetValue is required when the mode is set to - `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - If `FixedPodMode`, provide an integer of pods to do chaos - action. If `FixedPercentPodMod`, provide a number from 0-100 - to specify the percent of pods the server can do chaos action. - If `RandomMaxPercentPodMod`, provide a number from 0-100 - to specify the max percent of pods to do chaos action + type: array + type: object + templateName: + type: string + timeChaos: + description: TimeChaosSpec defines the desired state of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id All available + options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: type: string - required: - - mode - - selector - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - action - - mode - - selector - type: object - pod_chaos: - description: PodChaosSpec defines the attributes that a user creates - on a chaos experiment about pods. - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: pod-kill / pod-failure / container-kill Default action: - pod-kill' - enum: - - pod-kill - - pod-failure - - container-kill - type: string - containerName: - description: ContainerName indicates the name of the container. - Needed in container-kill. - type: string - duration: - description: Duration represents the duration of the chaos action. - It is required when the action is `PodFailureAction`. 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". - type: string - gracePeriod: - description: GracePeriod is used in pod-kill action. It represents - the duration in seconds before the pod should be deleted. Value - must be non-negative integer. The default value is zero that indicates - delete immediately. - format: int64 - minimum: 0 - type: integer - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + type: array + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - action - - mode - - selector - type: object - start_time: - format: date-time - type: string - stress_chaos: - description: StressChaosSpec defines the desired state of StressChaos - properties: - containerName: - description: ContainerName indicates the target container to inject - stress in - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - stressngStressors: - description: StressngStressors defines plenty of stressors just - like `Stressors` except that it's an experimental feature and - more powerful. You can define stressors in `stress-ng` (see also - `man stress-ng`) dialect, however not all of the supported stressors - are well tested. It maybe retired in later releases. You should - always use `Stressors` to define the stressors and use this only - when you want more stressors unsupported by `Stressors`. When - both `StressngStressors` and `Stressors` are defined, `StressngStressors` - wins. - type: string - stressors: - description: Stressors defines plenty of stressors supported to - stress system components out. You can use one or more of them - to make up various kinds of stresses. At least one of the stressors - should be specified. - properties: - cpu: - description: CPUStressor stresses CPU out - properties: - load: - description: Load specifies P percent loading per CPU worker. - 0 is effectively a sleep (no load) and 100 is full loading. - type: integer - options: - description: extend stress-ng options - items: - type: string - type: array - workers: - description: Workers specifies N workers to apply the stressor. - type: integer - required: - - workers - type: object - memory: - description: MemoryStressor stresses virtual memory out - properties: - options: - description: extend stress-ng options + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: items: type: string type: array - size: - description: Size specifies N bytes consumed per vm worker, - default is the total available memory. One can specify - the size as % of total available memory or in units of - B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. - type: string - workers: - description: Workers specifies N workers to apply the stressor. - type: integer - required: - - workers - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the % of pods to do chaos action - type: string - required: - - mode - - selector - type: object - tasks: - items: + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected program. + It's a possibly signed sequence of decimal numbers, such as + "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: type: string - type: array - template_name: - type: string - time_chaos: - description: TimeChaosSpec defines the desired state of TimeChaos - properties: - clockIds: - description: ClockIds defines all affected clock id All available - options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", - "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", - "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] - items: - type: string - type: array - containerNames: - description: ContainerName indicates the name of affected container. - If not set, all containers will be injected - items: - type: string - type: array - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. + workflowName: + type: string + required: + - startTime + - templateName + - type + - workflowName + type: object + status: + description: Most recently observed status of the workflow node + properties: + activeChildren: + description: ActiveChildren means the created children node + items: + description: LocalObjectReference contains enough information to + let you locate the referenced object inside the same namespace. properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object type: object - timeOffset: - description: TimeOffset defines the delta time of injected program. - It's a possibly signed sequence of decimal numbers, such as "300ms", - "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), - "ms", "s", "m", "h". - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - mode - - selector - - timeOffset - type: object - type: - type: string - workflow_name: - type: string - required: - - start_time - - template_name - - type - - workflow_name - type: object - status: - description: Most recently observed status of the workflow node - properties: - active_children: - description: ActiveChildren means the created children node - items: - description: LocalObjectReference contains enough information to let - you locate the referenced object inside the same namespace. - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - type: object - type: array - chaos_resource: - description: ChaosResource refs to the real chaos CR object. - properties: - apiGroup: - description: APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the - core API group. For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - required: - - kind - - name - type: object - conditions: - description: Represents the latest available observations of a worklfow - node's current state. - items: + x-kubernetes-map-type: atomic + type: array + chaosResource: + description: ChaosResource refs to the real chaos CR object. properties: - reason: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. type: string - status: + kind: + description: Kind is the type of resource being referenced type: string - type: + name: + description: Name is the name of resource being referenced type: string required: - - reason - - status - - type + - kind + - name type: object - type: array - expected_children_num: - description: ExpectedChildrenNum means the expected children to execute - type: integer - finished_children: - description: Children is necessary for representing the order when replicated - child template references by parent template. - items: - description: LocalObjectReference contains enough information to let - you locate the referenced object inside the same namespace. + x-kubernetes-map-type: atomic + conditionalBranchesStatus: + description: ConditionalBranchesStatus records the evaluation result + of each ConditionalBranch properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string + branches: + items: + properties: + evaluationResult: + type: string + target: + type: string + required: + - evaluationResult + - target + type: object + type: array + context: + items: + type: string + type: array type: object - type: array - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + conditions: + description: Represents the latest available observations of a workflow + node's current state. + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - reason + - status + - type + type: object + type: array + finishedChildren: + description: Children is necessary for representing the order when + replicated child template references by parent template. + items: + description: LocalObjectReference contains enough information to + let you locate the referenced object inside the same namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: + status: {} diff --git a/config/crd/bases/chaos-mesh.org_workflows.yaml b/config/crd/bases/chaos-mesh.org_workflows.yaml index 48bae7d646..067ddbfa67 100644 --- a/config/crd/bases/chaos-mesh.org_workflows.yaml +++ b/config/crd/bases/chaos-mesh.org_workflows.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: workflows.chaos-mesh.org spec: group: chaos-mesh.org @@ -16,2079 +14,10137 @@ spec: shortNames: - wf singular: workflow - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a workflow - properties: - entry: - type: string - templates: - items: - properties: - aws_chaos: - description: AwsChaosSpec is the content of the specification - for an AwsChaos - properties: - action: - description: 'Action defines the specific aws chaos action. - Supported action: ec2-stop / ec2-restart / detach-volume - Default action: ec2-stop' - enum: - - ec2-stop - - ec2-restart - - detach-volume - type: string - awsRegion: - description: AwsRegion defines the region of aws. - type: string - deviceName: - description: DeviceName indicates the name of the device. - Needed in detach-volume. - type: string - duration: - description: Duration represents the duration of the chaos - action. - type: string - ec2Instance: - description: Ec2Instance indicates the ID of the ec2 instance. - type: string - endpoint: - description: Endpoint indicates the endpoint of the aws server. - Just used it in test now. - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. - type: string - volumeID: - description: EbsVolume indicates the ID of the EBS volume. - Needed in detach-volume. - type: string - required: - - action - - awsRegion - - ec2Instance - type: object - dns_chaos: - description: DNSChaosSpec defines the desired state of DNSChaos - properties: - action: - description: 'Action defines the specific DNS chaos action. - Supported action: error, random Default action: error' - enum: - - error - - random - type: string - duration: - description: Duration represents the duration of the chaos - action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - patterns: - description: "Choose which domain names to take effect, support - the placeholder ? and wildcard *, or the Specified domain - name. Note: 1. The wildcard * must be at the end of - the string. For example, chaos-*.org is invalid. 2. - if the patterns is empty, will take effect on all the domain - names. For example: \t\tThe value is [\"google.com\", \"github.*\", - \"chaos-mes?.org\"], \t\twill take effect on \"google.com\", - \"github.com\" and \"chaos-mesh.org\"" - items: - type: string - type: array - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, - provide a number from 0-100 to specify the max percent of - pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - duration: - type: string - gcp_chaos: - description: GcpChaosSpec is the content of the specification - for a GcpChaos - properties: - action: - description: 'Action defines the specific gcp chaos action. - Supported action: node-stop / node-reset / disk-loss Default - action: node-stop' - enum: - - node-stop - - node-reset - - disk-loss - type: string - deviceName: - description: The device name of the disk to detach. Needed - in disk-loss. - type: string - duration: - description: Duration represents the duration of the chaos - action. - type: string - instance: - description: Instance defines the name of the instance - type: string - project: - description: Project defines the name of gcp project. - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a workflow + properties: + entry: + type: string + templates: + items: + properties: + abortWithStatusCheck: + description: AbortWithStatusCheck describe whether to abort + the workflow when the failure threshold of StatusCheck is + exceeded. Only used when Type is TypeStatusCheck. + type: boolean + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. + Supported action: ec2-stop / ec2-restart / detach-volume + Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. + Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws + server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. + Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. + Supported action: vm-stop / vm-restart / disk-detach Default + action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. Needed + in disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the + data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. + Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. - It is used for GCP credentials. - type: string - zone: - description: Zone defines the zone of gcp project. - type: string - required: - - action - - instance - - project - - zone - type: object - http_chaos: - properties: - action: - description: 'Action defines the specific pod chaos action. - Supported action: delay | abort | mixed Default action: - delay' - enum: - - delay - - abort - - mixed - type: string - duration: - description: Duration represents the duration of the chaos - action. It is required when the action is `PodFailureAction`. - 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". - type: string - headers: - description: Specifies how the header match will be performed - to route the request. - items: + type: array + delay: + description: Delay defines the delay distribution. properties: - exact_match: - type: string - invert_match: - type: string - name: - type: string - prefix_match: - type: string - present_match: - type: string - range_match: + correlation: type: string - regex_match: + jitter: type: string - safe_regex_match: + latency: + description: Latency defines the latency of every io + request. type: string - suffix_match: - type: string - required: - - name type: object - type: array - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - percent: - description: 'Percent defines the percentage of injection - errors and provides a number from 0-100. default: 100.' - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: + duration: + description: Duration represents the duration of the chaos + action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - action - - mode - - selector - type: object - io_chaos: - description: IoChaosSpec defines the desired state of IoChaos - properties: - action: - description: 'Action defines the specific pod chaos action. - Supported action: latency / fault / attrOverride / mistake' - enum: - - latency - - fault - - attrOverride - - mistake - type: string - attr: - description: Attr defines the overrided attribution - properties: - atime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - blocks: - format: int64 - type: integer - ctime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - gid: - format: int32 - type: integer - ino: - format: int64 - type: integer - kind: - description: FileType represents type of a file - type: string - mtime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - nlink: - format: int32 - type: integer - perm: - type: integer - rdev: - format: int32 - type: integer - size: - format: int64 - type: integer - uid: - format: int32 - type: integer - type: object - containerName: - description: ContainerName indicates the target container - to inject iochaos in - type: string - delay: - description: Delay defines the value of I/O chaos action delay. - A delay string is a possibly signed sequence of decimal - numbers, each with optional fraction and a unit suffix, - such as "300ms". Valid time units are "ns", "us" (or "µs"), - "ms", "s", "m", "h". - type: string - duration: - description: Duration represents the duration of the chaos - action. It is required when the action is `PodFailureAction`. - 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". - type: string - errno: - description: 'Errno defines the error code that returned by - I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' - format: int32 - type: integer - methods: - description: 'Methods defines the I/O methods for injecting - I/O chaos action. default: all I/O methods.' - items: - type: string - type: array - mistake: - description: Mistake defines what types of incorrectness are - injected to IO operations - properties: - filling: - description: Filling determines what is filled in the - miskate data. - enum: - - zero - - random - type: string - maxLength: - description: Max length of each wrong data segment in - bytes - format: int64 - minimum: 1 - type: integer - maxOccurrences: - description: There will be [1, MaxOccurrences] segments - of wrong data. - format: int64 - minimum: 1 - type: integer - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - path: - description: Path defines the path of files for injecting - I/O chaos action. - type: string - percent: - description: 'Percent defines the percentage of injection - errors and provides a number from 0-100. default: 100.' - type: integer - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - volumePath: - description: VolumePath represents the mount path of injected - volume - type: string - required: - - action - - mode - - selector - - volumePath - type: object - jvm_chaos: - description: JVMChaosSpec defines the desired state of JVMChaos - properties: - action: - description: 'Action defines the specific jvm chaos action. - Supported action: delay;return;script;cfl;oom;ccf;tce;cpf;tde;tpf' - enum: - - delay - - return - - script - - cfl - - oom - - ccf - - tce - - cpf - - tde - - tpf - type: string - duration: - description: Duration represents the duration of the chaos - action - type: string - flags: - additionalProperties: + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action type: string - description: Flags represents the flags of action - type: object - matchers: - additionalProperties: + volumeName: type: string - description: Matchers represents the matching rules for the - target - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' + required: + - action + - mode + - selector + - volumeName + type: object + children: + description: Children describes the children steps of serial + or parallel node. Only used when Type is TypeSerial or TypeParallel. + items: type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. + type: array + conditionalBranches: + description: ConditionalBranches describes the conditional branches + of custom tasks. Only used when Type is TypeTask. + items: properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" + expression: + description: Expression is the expression for this conditional + branch, expected type of result is boolean. If expression + is empty, this branch will always be selected/the template + will be spawned. + type: string + target: + description: Target is the name of other template, if + expression is evaluated as true, this template will + be spawned. type: string required: - - cron + - target type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: + type: array + deadline: + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos action. + Supported action: error, random Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, + support the placeholder ? and wildcard *, or the Specified + domain name. Note: 1. The wildcard * must be at the end + of the string. For example, chaos-*.org is invalid. 2. + if the patterns is empty, will take effect on all the + domain names. For example: The value is ["google.com", + "github.*", "chaos-mes?.org"], will take effect on "google.com", + "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - target: - description: 'Target defines the specific jvm chaos target. - Supported target: servlet;psql;jvm;jedis;http;dubbo;rocketmq;tars;mysql;druid;redisson;rabbitmq;mongodb' - enum: - - servlet - - psql - - jvm - - jedis - - http - - dubbo - - rocketmq - - tars - - mysql - - druid - - redisson - - rabbitmq - - mongodb - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the % of pods to do chaos - action - type: string - required: - - action - - mode - - selector - - target - type: object - kernel_chaos: - description: KernelChaosSpec defines the desired state of KernelChaos - properties: - duration: - description: Duration represents the duration of the chaos - action - type: string - failKernRequest: - description: FailKernRequest defines the request of kernel - injection - properties: - callchain: - description: 'Callchain indicate a special call chain, - such as: ext4_mount -> mount_subtree -> - ... -> should_failslab With an optional - set of predicates and an optional set of parameters, - which used with predicates. You can read call chan and - predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples - to learn more. If no special call chain, just keep Callchain - empty, which means it will fail at any call chain with - slab alloc (eg: kmalloc).' - items: - description: Frame defines the function signature and - predicate in function's body - properties: - funcname: - description: Funcname can be find from kernel source - or `/proc/kallsyms`, such as `ext4_mount` - type: string - parameters: - description: Parameters is used with predicate, - for example, if you want to inject slab error - in `d_alloc_parallel(struct dentry *parent, const - struct qstr *name)` with a special name `bananas`, - you need to set it to `struct dentry *parent, - const struct qstr *name` otherwise omit it. - type: string - predicate: - description: Predicate will access the arguments - of this Frame, example with Parameters's, you - can set it to `STRNCMP(name->name, "bananas", - 8)` to make inject only with it, or omit it to - inject for all d_alloc_parallel call chain. - type: string - type: object - type: array - failtype: - description: 'FailType indicates what to fail, can be - set to ''0'' / ''1'' / ''2'' If `0`, indicates slab - to fail (should_failslab) If `1`, indicates alloc_page - to fail (should_fail_alloc_page) If `2`, indicates bio - to fail (should_fail_bio) You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html 2. - http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt - to learn more' - format: int32 - maximum: 2 - minimum: 0 - type: integer - headers: - description: 'Headers indicates the appropriate kernel - headers you need. Eg: "linux/mmzone.h", "linux/blkdev.h" - and so on' - items: - type: string - type: array - probability: - description: Probability indicates the fails with probability. - If you want 1%, please set this field with 1. - format: int32 - maximum: 100 - minimum: 0 - type: integer - times: - description: Times indicates the max times of fails. - format: int32 - minimum: 0 - type: integer - required: - - failtype - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - failKernRequest - - mode - - selector - type: object - name: - type: string - network_chaos: - description: NetworkChaosSpec defines the desired state of NetworkChaos - properties: - action: - description: 'Action defines the specific network chaos action. - Supported action: partition, netem, delay, loss, duplicate, - corrupt Default action: delay' - enum: - - netem - - delay - - loss - - duplicate - - corrupt - - partition - - bandwidth - type: string - bandwidth: - description: Bandwidth represents the detail about bandwidth - control action - properties: - buffer: - description: Buffer is the maximum amount of bytes that - tokens can be available for instantaneously. - format: int32 - minimum: 1 - type: integer - limit: - description: Limit is the number of bytes that can be - queued waiting for tokens to become available. - format: int32 - minimum: 1 - type: integer - minburst: - description: Minburst specifies the size of the peakrate - bucket. For perfect accuracy, should be set to the MTU - of the interface. If a peakrate is needed, but some - burstiness is acceptable, this size can be raised. A - 3000 byte minburst allows around 3mbit/s of peakrate, - given 1000 byte packets. - format: int32 - minimum: 0 - type: integer - peakrate: - description: Peakrate is the maximum depletion rate of - the bucket. The peakrate does not need to be set, it - is only necessary if perfect millisecond timescale shaping - is required. - format: int64 - minimum: 0 - type: integer - rate: - description: Rate is the speed knob. Allows bps, kbps, - mbps, gbps, tbps unit. bps means bytes per second. - type: string - required: - - buffer - - limit - - rate - type: object - corrupt: - description: Corrupt represents the detail about corrupt action - properties: - correlation: - type: string - corrupt: - type: string - required: - - correlation - - corrupt - type: object - delay: - description: Delay represents the detail about delay action - properties: - correlation: - type: string - jitter: - type: string - latency: - type: string - reorder: - description: ReorderSpec defines details of packet reorder. - properties: - correlation: - type: string - gap: - type: integer - reorder: - type: string - required: - - correlation - - gap - - reorder - type: object - required: - - latency - type: object - direction: - description: Direction represents the direction, this applies - on netem and network partition action - enum: - - to - - from - - both - - "" - type: string - duplicate: - description: DuplicateSpec represents the detail about loss - action - properties: - correlation: - type: string - duplicate: - type: string - required: - - correlation - - duplicate - type: object - duration: - description: Duration represents the duration of the chaos - action - type: string - externalTargets: - description: ExternalTargets represents network targets outside - k8s - items: - type: string - type: array - loss: - description: Loss represents the detail about loss action - properties: - correlation: - type: string - loss: - type: string - required: - - correlation - - loss - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - target: - description: Target represents network target, this applies - on netem and network partition action - properties: - mode: - description: TargetMode defines the target selector mode - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - - "" - type: string - selector: - description: TargetSelector defines the target selector - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can - be used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions - that can be used to select objects. A list of selectors - based on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can - be used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can - be used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. + pods: + additionalProperties: items: type: string type: array - nodeSelectors: - additionalProperties: + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. + Supported action: node-stop / node-reset / disk-loss Default + action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed + in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status + code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, + such as "300ms", "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + method: + description: Method is a rule to select target by http method + in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of + target. + properties: + type: + description: Type represents the patch type, only + support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. type: string - description: Map of string keys and values that can - be used to select nodes. Selector which must match - a node's labels, and objects must belong to these - selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects - must belong to these nodes. + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], + ["Set-Cookie", ""]]`.' + items: items: type: string type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", "bar"], + ["foo", "unknown"]]`.' + items: items: type: string type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set - values that used to select pods. The key defines - the namespace which pods belong, and the each values - is a set of pod names. - type: object - type: object - value: - description: TargetValue is required when the mode is - set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - If `FixedPodMode`, provide an integer of pods to do - chaos action. If `FixedPercentPodMod`, provide a number - from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods - to do chaos action - type: string - required: - - mode - - selector - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - action - - mode - - selector - type: object - pod_chaos: - description: PodChaosSpec defines the attributes that a user creates - on a chaos experiment about pods. - properties: - action: - description: 'Action defines the specific pod chaos action. - Supported action: pod-kill / pod-failure / container-kill - Default action: pod-kill' - enum: - - pod-kill - - pod-failure - - container-kill - type: string - containerName: - description: ContainerName indicates the name of the container. - Needed in container-kill. - type: string - duration: - description: Duration represents the duration of the chaos - action. It is required when the action is `PodFailureAction`. - 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". - type: string - gracePeriod: - description: GracePeriod is used in pod-kill action. It represents - the duration in seconds before the pod should be deleted. - Value must be non-negative integer. The default value is - zero that indicates delete immediately. - format: int64 - minimum: 0 - type: integer - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: + type: array + type: object + path: + description: Path is a rule to select target by uri path + in http request. + type: string + port: + description: Port represents the target port to be proxy + of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http message + body in target. + format: byte type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator + code: + description: Code is a rule to replace http status code + in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header name + and header value pairs. type: object - type: array - fieldSelectors: - additionalProperties: + method: + description: Method is a rule to replace http method + in request. type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: + path: + description: Path is rule to to replace uri path in + http request. type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: + queries: + additionalProperties: type: string - type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - action - - mode - - selector - type: object - stress_chaos: - description: StressChaosSpec defines the desired state of StressChaos - properties: - containerName: - description: ContainerName indicates the target container - to inject stress in - type: string - duration: - description: Duration represents the duration of the chaos - action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": + "unknown" }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: + description: RequestHeaders is a rule to select target by + http headers in request. The key-value pairs represent + header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target + by http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - stressngStressors: - description: StressngStressors defines plenty of stressors - just like `Stressors` except that it's an experimental feature - and more powerful. You can define stressors in `stress-ng` - (see also `man stress-ng`) dialect, however not all of the - supported stressors are well tested. It maybe retired in - later releases. You should always use `Stressors` to define - the stressors and use this only when you want more stressors - unsupported by `Stressors`. When both `StressngStressors` - and `Stressors` are defined, `StressngStressors` wins. - type: string - stressors: - description: Stressors defines plenty of stressors supported - to stress system components out. You can use one or more - of them to make up various kinds of stresses. At least one - of the stressors should be specified. - properties: - cpu: - description: CPUStressor stresses CPU out - properties: - load: - description: Load specifies P percent loading per - CPU worker. 0 is effectively a sleep (no load) and - 100 is full loading. - type: integer - options: - description: extend stress-ng options - items: - type: string - type: array - workers: - description: Workers specifies N workers to apply - the stressor. - type: integer - required: - - workers - type: object - memory: - description: MemoryStressor stresses virtual memory out - properties: - options: - description: extend stress-ng options + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: items: type: string type: array - size: - description: Size specifies N bytes consumed per vm - worker, default is the total available memory. One - can specify the size as % of total available memory - or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. - type: string - workers: - description: Workers specifies N workers to apply - the stressor. - type: integer - required: - - workers - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the % of pods to do chaos - action - type: string - required: - - mode - - selector - type: object - tasks: - items: - type: string - type: array - template_type: - type: string - time_chaos: - description: TimeChaosSpec defines the desired state of TimeChaos - properties: - clockIds: - description: ClockIds defines all affected clock id All available - options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", - "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", - "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] - items: - type: string - type: array - containerNames: - description: ContainerName indicates the name of affected - container. If not set, all containers will be injected - items: - type: string - type: array - duration: - description: Duration represents the duration of the chaos - action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file + in secret, `ca.crt` for example type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. + certName: + description: CertName represents the data name of cert + file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of key + file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required + secret resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace + of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. + Supported action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: - type: string - type: array + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer required: - - key - - operator + - nsec + - sec type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action + delay. A delay string is a possibly signed sequence of + decimal numbers, each with optional fraction and a unit + suffix, such as "300ms". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos + action. It is required when the action is `PodFailureAction`. + 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". + type: string + errno: + description: 'Errno defines the error code that returned + by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting + I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled in the + mistake data. + enum: + - zero + - random type: string - type: array - pods: - additionalProperties: - items: + maxLength: + description: Max length of each wrong data segment in + bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting + I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection + errors and provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected + volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. + Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only set + it when action is stress + type: integer + database: + description: the match database default value is "", means + match all database + type: string + duration: + description: Duration represents the duration of the chaos + action + type: string + exception: + description: the exception which needs to throw for action + `exception` or the exception message needs to throw in + action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it + when action is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will + generate one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel + injection + properties: + callchain: + description: 'Callchain indicate a special call chain, + such as: ext4_mount -> mount_subtree -> ... -> should_failslab + With an optional set of predicates and an optional + set of parameters, which used with predicates. You + can read call chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep + Callchain empty, which means it will fail at any call + chain with slab alloc (eg: kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from kernel + source or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab error + in `d_alloc_parallel(struct dentry *parent, + const struct qstr *name)` with a special name + `bananas`, you need to set it to `struct dentry + *parent, const struct qstr *name` otherwise + omit it. + type: string + predicate: + description: Predicate will access the arguments + of this Frame, example with Parameters's, you + can set it to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, or omit it + to inject for all d_alloc_parallel call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be + set to ''0'' / ''1'' / ''2'' If `0`, indicates slab + to fail (should_failslab) If `1`, indicates alloc_page + to fail (should_fail_alloc_page) If `2`, indicates + bio to fail (should_fail_bio) You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel + headers you need. Eg: "linux/mmzone.h", "linux/blkdev.h" + and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + name: + type: string + networkChaos: + description: NetworkChaosSpec defines the desired state of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos + action. Supported action: partition, netem, delay, loss, + duplicate, corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes that + tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be + queued waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate + bucket. For perfect accuracy, should be set to the + MTU of the interface. If a peakrate is needed, but + some burstiness is acceptable, this size can be raised. + A 3000 byte minburst allows around 3mbit/s of peakrate, + given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate + of the bucket. The peakrate does not need to be set, + it is only necessary if perfect millisecond timescale + shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, + mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt + action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be + affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies + on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss + action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos + action + type: string + externalTargets: + description: ExternalTargets represents network targets + outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control + action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, + mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + target: + description: Target represents network target, this applies + on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device + to be affected in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired state + of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one + of Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock + on which to act. More clock description in linux kernel + can be found in man page of clock_getres, clock_gettime, + clock_settime. Muti clock ids should be split with + "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. + if path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. + if path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on + writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. + if path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on + writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos + action + type: string + file-append: + properties: + count: + description: Count is the number of times to append + the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the + file. + type: string + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to + be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http + status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside + proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by http + status code in response + type: string + delay: + description: Delay represents the delay of the target + request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside + proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for + action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', + unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", + means match all database + type: string + exception: + description: The exception which needs to throw for + action `exception` or the exception message needs + to throw in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' + or the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only + support 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", + means match all SQL type. The value can be 'select', + 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, + will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set + it when action is stress + type: integer + mem-type: + description: the memory type need to locate, only set + it when action is stress, the value can be 'stack' + or 'heap' + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is + 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag + can be accepted, others will be dropped. only set + when the IPProtocol is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or + µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf + test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads + to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP + address + type: string + rate: + description: The speed of network traffic, allows bps, + kbps, mbps, gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag + can be accepted, others will be dropped. only set + when the IPProtocol is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values + can be 'from', 'to'. 'from' means packets coming from + the 'IPAddress' or 'Hostname' and going to your server, + 'to' means packets originating from your server and + going to the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP + addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of + the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to + flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to + flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string keys + and a set values that used to select physical machines. + The key defines the namespace which physical machine + belong, and each value is a set of physical machine + names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. + 0 is effectively a sleep (no load) and 100 is full + loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, + default is the total available memory. One can specify + the size as % of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to + specify the percent of physical machines the server can + do chaos action. IF `RandomMaxPercentMode`, provide a + number from 0-100 to specify the max percent of pods to + do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a user + creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos action. + Supported action: pod-kill / pod-failure / container-kill + Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action. It is required when the action is `PodFailureAction`. + 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It + represents the duration in seconds before the pod should + be deleted. Value must be non-negative integer. The default + value is zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + description: Schedule describe the Schedule(describing scheduled + chaos) to be injected with chaos nodes. Only used when Type + is TypeSchedule. + properties: + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos + action. Supported action: ec2-stop / ec2-restart / + detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. + Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 + instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the + aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. + Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos + action. Supported action: vm-stop / vm-restart / disk-detach + Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. + Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of + the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure + subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos + action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every + io request. + type: string + type: object + duration: + description: Duration represents the duration of the + chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos + action. Supported action: error, random Default action: + error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, + support the placeholder ? and wildcard *, or the Specified + domain name. Note: 1. The wildcard * must be at the + end of the string. For example, chaos-*.org is invalid. + 2. if the patterns is empty, will take effect on all + the domain names. For example: The value is ["google.com", + "github.*", "chaos-mes?.org"], will take effect on + "google.com", "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos + action. Supported action: node-stop / node-reset / + disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed + in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http + status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target + request/response. A duration string is a possibly + unsigned sequence of decimal numbers, each with optional + fraction and a unit suffix, such as "300ms", "2h45m". + Valid time units are "ns", "us" (or "µs"), "ms", "s", + "m", "h". + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + method: + description: Method is a rule to select target by http + method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. + properties: + body: + description: Body is a rule to patch message body + of target. + properties: + type: + description: Type represents the patch type, + only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", + "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri + path in http request. + type: string + port: + description: Port represents the target port to be proxy + of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http message + body in target. + format: byte + type: string + code: + description: Code is a rule to replace http status + code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header + name and header value pairs. + type: object + method: + description: Method is a rule to replace http method + in request. + type: string + path: + description: Path is rule to to replace uri path + in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": + "unknown" }`, the `/?foo=bar` will be altered + to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target + by http headers in request. The key-value pairs represent + header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target + by http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and + injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of + ca file in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name of + cert file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of + key file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required + secret resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace + of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: latency / fault / attrOverride + / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action + delay. A delay string is a possibly signed sequence + of decimal numbers, each with optional fraction and + a unit suffix, such as "300ms". Valid time units are + "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the + chaos action. It is required when the action is `PodFailureAction`. + 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". + type: string + errno: + description: 'Errno defines the error code that returned + by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting + I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled in + the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment + in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting + I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection + errors and provides a number from 0-100. default: + 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path of + injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos + action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only + set it when action is stress + type: integer + database: + description: the match database default value is "", + means match all database + type: string + duration: + description: Duration represents the duration of the + chaos action + type: string + exception: + description: the exception which needs to throw for + action `exception` or the exception message needs + to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set + it when action is stress, the value can be 'stack' + or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only + support 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and + will generate one if not set + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", + means match all SQL type. The value can be 'select', + 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of + KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of + kernel injection + properties: + callchain: + description: 'Callchain indicate a special call + chain, such as: ext4_mount -> mount_subtree -> + ... -> should_failslab With an optional set of + predicates and an optional set of parameters, + which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just + keep Callchain empty, which means it will fail + at any call chain with slab alloc (eg: kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from kernel + source or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab + error in `d_alloc_parallel(struct dentry + *parent, const struct qstr *name)` with + a special name `bananas`, you need to set + it to `struct dentry *parent, const struct + qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments + of this Frame, example with Parameters's, + you can set it to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, or omit + it to inject for all d_alloc_parallel call + chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can + be set to ''0'' / ''1'' / ''2'' If `0`, indicates + slab to fail (should_failslab) If `1`, indicates + alloc_page to fail (should_fail_alloc_page) If + `2`, indicates bio to fail (should_fail_bio) You + can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with + probability. If you want 1%, please set this field + with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state + of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos + action. Supported action: partition, netem, delay, + loss, duplicate, corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes + that tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can + be queued waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the + peakrate bucket. For perfect accuracy, should + be set to the MTU of the interface. If a peakrate + is needed, but some burstiness is acceptable, + this size can be raised. A 3000 byte minburst + allows around 3mbit/s of peakrate, given 1000 + byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate + of the bucket. The peakrate does not need to be + set, it is only necessary if perfect millisecond + timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, + kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, + tbps unit. bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt + action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay + action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet + reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to + be affected. + type: string + direction: + default: to + description: Direction represents the direction, this + applies on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about + loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the + chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets + outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control + action + properties: + rate: + description: Rate is the speed knob. Allows bit, + kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, + tbps unit. bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this + applies on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device + to be affected in target scope. + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired + state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only + one of Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock + on which to act. More clock description in linux + kernel can be found in man page of clock_getres, + clock_gettime, clock_settime. Muti clock ids should + be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + payload-process-num: + description: specifies the number of process work + on writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + payload-process-num: + description: specifies the number of process work + on writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the + chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to append + the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to + be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of + the file. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file + to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the + file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by + http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP + connection, we will only attack HTTP connection + with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by + http status code in response + type: string + delay: + description: Delay represents the delay of the target + request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP + connection, we will only attack HTTP connection + with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support + GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw + for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', + unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is + "", means match all database + type: string + exception: + description: The exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' + or the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set to + "8") now + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is + "", means match all SQL type. The value can be + 'select', 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", + means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's + data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only + set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, only + set it when action is stress, the value can be + 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp + flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used for + partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or + µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf + test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client + threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the + IP address + type: string + rate: + description: The speed of network traffic, allows + bps, kbps, mbps, gbps, tbps unit. bps means bytes + per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is + 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp + flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used for + partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means packets + coming from the 'IPAddress' or 'Hostname' and + going to your server, 'to' means packets originating + from your server and going to the 'IPAddress' + or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these + IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering + experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string + keys and a set values that used to select physical + machines. The key defines the namespace which + physical machine belong, and each value is a set + of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU + worker. 0 is effectively a sleep (no load) and + 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, + default is the total available memory. One can + specify the size as % of total available memory + or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of physical machines + to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of physical + machines the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a + user creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: pod-kill / pod-failure / + container-kill Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action. It is required when the action is `PodFailureAction`. + 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. + It represents the duration in seconds before the pod + should be deleted. Value must be non-negative integer. + The default value is zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired state of + StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors + just like `Stressors` except that it's an experimental + feature and more powerful. You can define stressors + in `stress-ng` (see also `man stress-ng`) dialect, + however not all of the supported stressors are well + tested. It maybe retired in later releases. You should + always use `Stressors` to define the stressors and + use this only when you want more stressors unsupported + by `Stressors`. When both `StressngStressors` and + `Stressors` are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported + to stress system components out. You can use one or + more of them to make up various kinds of stresses. + At least one of the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading + per CPU worker. 0 is effectively a sleep (no + load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to + apply the stressor. Maximum 8192 workers can + run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory + out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` to + know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % of total + available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to + apply the stressor. Maximum 8192 workers can + run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state of + TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id + All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected + program. It's a possibly signed sequence of decimal + numbers, such as "300ms", "-1.5h" or "2h45m". Valid + time units are "ns", "us" (or "µs"), "ms", "s", "m", + "h". + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + required: + - schedule + - type + type: object + statusCheck: + description: StatusCheck describe the behavior of StatusCheck. + Only used when Type is TypeStatusCheck. + properties: + duration: + description: Duration defines the duration of the whole + status check if the number of failed execution does not + exceed the failure threshold. Duration is available to + both `Synchronous` and `Continuous` mode. 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum consecutive + failure for the status check to be considered failed. + minimum: 1 + type: integer + http: + properties: + body: + type: string + criteria: + description: Criteria defines how to determine the result + of the status check. + properties: + statusCode: + description: StatusCode defines the expected http + status code for the request. A statusCode string + could be a single code (e.g. 200), or an inclusive + range (e.g. 200-400, both `200` and `400` are + included). + type: string + required: + - statusCode + type: object + headers: + additionalProperties: + items: + type: string + type: array + description: "A Header represents the key-value pairs + in an HTTP header. \n The keys should be in canonical + form, as returned by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in seconds) + to perform an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of the status + check. Support type: Synchronous / Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number of record + to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum consecutive + successes for the status check to be considered successful. + SuccessThreshold only works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of seconds + after which an execution of status check times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check type. + Support type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + stressChaos: + description: StressChaosSpec defines the desired state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors + just like `Stressors` except that it's an experimental + feature and more powerful. You can define stressors in + `stress-ng` (see also `man stress-ng`) dialect, however + not all of the supported stressors are well tested. It + maybe retired in later releases. You should always use + `Stressors` to define the stressors and use this only + when you want more stressors unsupported by `Stressors`. + When both `StressngStressors` and `Stressors` are defined, + `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported + to stress system components out. You can use one or more + of them to make up various kinds of stresses. At least + one of the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading per + CPU worker. 0 is effectively a sleep (no load) + and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to apply + the stressor. Maximum 8192 workers can run by + stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory + out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` to know + more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per + vm worker, default is the total available memory. + One can specify the size as % of total available + memory or in units of B, KB/KiB, MB/MiB, GB/GiB, + TB/TiB. + type: string + workers: + description: Workers specifies N workers to apply + the stressor. Maximum 8192 workers can run by + stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - mode + - selector + type: object + task: + description: Task describes the behavior of the custom task. + Only used when Type is TypeTask. + properties: + container: + description: Container is the main container image to run + in the pod + properties: + args: + description: 'Arguments to the entrypoint. The container + image''s CMD is used if this is not provided. Variable + references $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, the + reference in the input string will be unchanged. Double + $$ are reduced to a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Cannot be updated. More info: + https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The container image''s ENTRYPOINT is used + if this is not provided. Variable references $(VAR_NAME) + are expanded using the container''s environment. If + a variable cannot be resolved, the reference in the + input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable exists + or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set in + the container. Cannot be updated. + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined environment + variables in the container and any service environment + variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults + to "".' + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: + supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, + requests.cpu, requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in + the pod's namespace + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined within + a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container is + starting. When a key exists in multiple sources, the + value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will + take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source of + a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config + management to default or override container images + in workload controllers like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, + IfNotPresent. Defaults to Always if :latest tag is + specified, or IfNotPresent otherwise. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system should + take in response to container lifecycle events. Cannot + be updated. + properties: + postStart: + description: 'PostStart is called immediately after + a container is created. If the handler fails, + the container is terminated and restarted according + to its restart policy. Other management of the + container blocks until the hook completes. More + info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of + this field and lifecycle hooks will fail in + runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately before + a container is terminated due to an API request + or management event such as liveness/startup probe + failure, preemption, resource contention, etc. + The handler is not called if the container crashes + or exits. The Pod''s termination grace period + countdown begins before the PreStop hook is executed. + Regardless of the outcome of the handler, the + container will eventually terminate within the + Pod''s termination grace period (unless delayed + by finalizers). Other management of the container + blocks until the hook completes or until the termination + grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of + this field and lifecycle hooks will fail in + runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. Cannot + be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. + Not specifying a port here DOES NOT prevent that port + from being exposed. Any port which is listening on + the default "0.0.0.0" address inside a container will + be accessible from the network. Modifying this array + with strategic merge patch may corrupt the data. For + more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port + in a single container. + properties: + containerPort: + description: Number of port to expose on the pod's + IP address. This must be a valid port number, + 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on the host. + If specified, this must be a valid port number, + 0 < x < 65536. If HostNetwork is specified, + this must match ContainerPort. Most containers + do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an IANA_SVC_NAME + and unique within the pod. Each named port in + a pod must have a unique name. Name for the + port that can be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, TCP, + or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service readiness. + Container will be removed from service endpoints if + the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource + resize policy for the container. + properties: + resourceName: + description: 'Name of the resource to which this + resource resize policy applies. Supported values: + cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when specified + resource is resized. If not specified, it defaults + to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this container. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, + defined in spec.resourceClaims, that are used + by this container. \n This is an alpha field and + requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can + only be set for containers." + items: + description: ResourceClaim references one entry + in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one + entry in pod.spec.resourceClaims of the + Pod where this field is used. It makes that + resource available inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount + of compute resources required. If Requests is + omitted for a container, it defaults to Limits + if that is explicitly specified, otherwise to + an implementation-defined value. Requests cannot + exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + restartPolicy: + description: 'RestartPolicy defines the restart behavior + of individual containers in a pod. This field may + only be set for init containers, and the only allowed + value is "Always". For non-init containers or when + this field is not specified, the restart behavior + is defined by the Pod''s restart policy and the container + type. Setting the RestartPolicy as "Always" for the + init container will have the following effect: this + init container will be continually restarted on exit + until all regular containers have terminated. Once + all regular containers have completed, all init containers + with restartPolicy "Always" will be shut down. This + lifecycle differs from normal init containers and + is often referred to as a "sidecar" container. Although + this init container still starts in the init container + sequence, it does not wait for the container to complete + before proceeding to the next init container. Instead, + the next init container starts immediately after this + init container is started, or after any startupProbe + has successfully completed.' + type: string + securityContext: + description: 'SecurityContext defines the security options + the container should be run with. If set, the fields + of SecurityContext override the equivalent fields + of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges than + its parent process. This bool directly controls + if the no_new_privs flag will be set on the container + process. AllowPrivilegeEscalation is true always + when the container is: 1) run as Privileged 2) + has CAP_SYS_ADMIN Note that this field cannot + be set when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running + containers. Defaults to the default set of capabilities + granted by the container runtime. Note that this + field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes + in privileged containers are essentially equivalent + to root on the host. Defaults to false. Note that + this field cannot be set when spec.os.name is + windows. + type: boolean + procMount: + description: procMount denotes the type of proc + mount to use for the containers. The default is + DefaultProcMount which uses the container runtime + defaults for readonly paths and masked paths. + This requires the ProcMountType feature flag to + be enabled. Note that this field cannot be set + when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only + root filesystem. Default is false. Note that this + field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the + container process. Uses runtime default if unset. + May also be set in PodSecurityContext. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run + as a non-root user. If true, the Kubelet will + validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start + the container if it does. If unset or false, no + such validation will be performed. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in + SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the + container process. Defaults to user specified + in image metadata if unspecified. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in + SecurityContext takes precedence. Note that this + field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to + the container. If unspecified, the container runtime + will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + properties: + level: + description: Level is SELinux level label that + applies to the container. + type: string + role: + description: Role is a SELinux role label that + applies to the container. + type: string + type: + description: Type is a SELinux type label that + applies to the container. + type: string + user: + description: User is a SELinux user label that + applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this + container. If seccomp options are provided at + both the pod & container level, the container + options override the pod options. Note that this + field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. + The profile must be preconfigured on the node + to work. Must be a descending path, relative + to the kubelet's configured seccomp profile + location. Must be set if type is "Localhost". + Must NOT be set for any other type. + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: + \n Localhost - a profile defined in a file + on the node should be used. RuntimeDefault + - the container runtime default profile should + be used. Unconfined - no profile should be + applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options + from the PodSecurityContext will be used. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the + GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name + of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. + All of a Pod's containers must have the same + effective HostProcess value (it is not allowed + to have a mix of HostProcess containers and + non-HostProcess containers). In addition, + if HostProcess is true then HostNetwork must + also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run + the entrypoint of the container process. Defaults + to the user specified in image metadata if + unspecified. May also be set in PodSecurityContext. + If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the Pod has + successfully initialized. If specified, no other probes + are executed until this completes successfully. If + this probe fails, the Pod will be restarted, just + as if the livenessProbe failed. This can be used to + provide different probe parameters at the beginning + of a Pod''s lifecycle, when it might take a long time + to load data or warm a cache, than during steady-state + operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will + always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close + the stdin channel after it has been opened by a single + attach. When stdin is true the stdin stream will remain + open across multiple attach sessions. If stdinOnce + is set to true, stdin is opened on container start, + is empty until the first client attaches to stdin, + and then remains open and accepts data until the client + disconnects, at which time stdin is closed and remains + closed until the container is restarted. If this flag + is false, a container processes that reads from stdin + will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to which + the container''s termination message will be written + is mounted into the container''s filesystem. Message + written is intended to be brief final status, such + as an assertion failure message. Will be truncated + by the node if greater than 4096 bytes. The total + message length across all containers will be limited + to 12kb. Defaults to /dev/termination-log. Cannot + be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message should + be populated. File will use the contents of terminationMessagePath + to populate the container status message on both success + and failure. FallbackToLogsOnError will use the last + chunk of container log output if the termination message + file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, + whichever is smaller. Defaults to File. Cannot be + updated. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices + to be used by the container. + items: + description: volumeDevice describes a mapping of a + raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside of + the container that the device will be mapped + to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting of a + Volume within a container. + properties: + mountPath: + description: Path within the container at which + the volume should be mounted. Must not contain + ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts + are propagated from the host to container and + the other way around. When not set, MountPropagationNone + is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write + otherwise (false or unspecified). Defaults to + false. + type: boolean + subPath: + description: Path within the volume from which + the container's volume should be mounted. Defaults + to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from + which the container's volume should be mounted. + Behaves similarly to SubPath but environment + variable references $(VAR_NAME) are expanded + using the container's environment. Defaults + to "" (volume's root). SubPathExpr and SubPath + are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not specified, + the container runtime's default will be used, which + might be configured in the container image. Cannot + be updated. + type: string + required: + - name + type: object + volumes: + description: Volumes is a list of volumes that can be mounted + by containers in a template. + items: + description: Volume represents a named volume in a pod + that may be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents an AWS + Disk resource that is attached to a kubelet''s host + machine and then exposed to the pod. More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in the + volume that you want to mount. If omitted, the + default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for + /dev/sda is "0" (or you can leave the property + empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force the + readOnly setting in VolumeMounts. More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the persistent + disk resource in AWS (Amazon EBS volume). More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data Disk + mount on the host and bind mount to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching + mode: None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data + disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in + the blob storage + type: string + fsType: + description: fsType is Filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: + multiple blob disks per storage account Dedicated: + single blob disk per storage account Managed: + azure managed data disk (only in managed availability + set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File Service + mount on the host and bind mount to the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret + that contains Azure Storage Account Name and + Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount on + the host that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors is + a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the mounted + root, rather than the full Ceph tree, default + is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile + is the path to key ring for User, default is + /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef + is reference to the authentication secret for + User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the rados + user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume attached + and mounted on kubelets host machine. More info: + https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Examples: "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points to + a secret object containing parameters used to + connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the volume + in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that + should populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced ConfigMap + will be projected into the volume as a file + whose name is the key and content is the value. + If specified, the listed keys will be projected + into the specified paths, and unlisted keys + will not be present. If a key is specified which + is not present in the ConfigMap, the volume + setup will error unless it is marked optional. + Paths must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 and + 0777 or a decimal value between 0 and + 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. If not specified, the volume + defaultMode will be used. This might be + in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path of + the file to map the key to. May not be + an absolute path. May not contain the + path element '..'. May not start with + the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents + ephemeral storage that is handled by certain external + CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI driver + that handles this volume. Consult with your + admin for the correct name as registered in + the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", "xfs", + "ntfs". If not provided, the empty value is + passed to the associated CSI driver which will + determine the default filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference + to the secret object containing sensitive information + to pass to the CSI driver to complete the CSI + NodePublishVolume and NodeUnpublishVolume calls. + This field is optional, and may be empty if + no secret is required. If the secret object + contains more than one secret, all secret references + are passed. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only configuration + for the volume. Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. + Consult your driver's documentation for supported + values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API about + the pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on created + files by default. Must be a Optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: Items is a list of downward API volume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, + defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used to + set permissions on this file, must be + an octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML + accepts both octal and decimal values, + JSON requires decimal values for mode + bits. If not specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must + not be absolute or contain the ''..'' + path. Must be utf-8 encoded. The first + item of the relative path must not start + with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the + container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu + and requests.memory) are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults + to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary directory + that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type of storage + medium should back this directory. The default + is "" which means to use the node''s default + medium. Must be an empty string (default) or + Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount of + local storage required for this EmptyDir volume. + The size limit is also applicable for memory + medium. The maximum usage on memory medium EmptyDir + would be the minimum value between the SizeLimit + specified here and the sum of memory limits + of all containers in a pod. The default is nil + which means that the limit is undefined. More + info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume that is + handled by a cluster storage driver. The volume's + lifecycle is tied to the pod that defines it - it + will be created before the pod starts, and deleted + when the pod is removed. \n Use this if: a) the + volume is only needed while the pod runs, b) features + of normal volumes like restoring from snapshot or + capacity tracking are needed, c) the storage driver + is specified through a storage class, and d) the + storage driver supports dynamic volume provisioning + through a PersistentVolumeClaim (see EphemeralVolumeSource + for more information on the connection between this + volume type and PersistentVolumeClaim). \n Use PersistentVolumeClaim + or one of the vendor-specific APIs for volumes that + persist for longer than the lifecycle of an individual + pod. \n Use CSI for light-weight local ephemeral + volumes if the CSI driver is meant to be used that + way - see the documentation of the driver for more + information. \n A pod can use both types of ephemeral + volumes and persistent volumes at the same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone + PVC to provision the volume. The pod in which + this EphemeralVolumeSource is embedded will + be the owner of the PVC, i.e. the PVC will be + deleted together with the pod. The name of + the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` + array entry. Pod validation will reject the + pod if the concatenated name is not valid for + a PVC (for example, too long). \n An existing + PVC with that name that is not owned by the + pod will *not* be used for the pod to avoid + using an unrelated volume by mistake. Starting + the pod is then blocked until the unrelated + PVC is removed. If such a pre-created PVC is + meant to be used by the pod, the PVC has to + updated with an owner reference to the pod once + the pod exists. Normally this should not be + necessary, but it may be useful when manually + reconstructing a broken cluster. \n This field + is read-only and no changes will be made by + Kubernetes to the PVC after it has been created. + \n Required, must not be nil." + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when creating + it. No other fields are allowed and will + be rejected during validation. + type: object + spec: + description: The specification for the PersistentVolumeClaim. + The entire content is copied unchanged into + the PVC that gets created from this template. + The same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: 'accessModes contains the + desired access modes the volume should + have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can be + used to specify either: * An existing + VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller + can support the specified data source, + it will create a new volume based on + the contents of the specified data source. + When the AnyVolumeDataSource feature + gate is enabled, dataSource contents + will be copied to dataSourceRef, and + dataSourceRef contents will be copied + to dataSource when dataSourceRef.namespace + is not specified. If the namespace is + specified, then dataSourceRef will not + be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, the + specified Kind must be in the core + API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies + the object from which to populate the + volume with data, if a non-empty volume + is desired. This may be any object from + a non-empty API group (non core object) + or a PersistentVolumeClaim object. When + this field is specified, volume binding + will only succeed if the type of the + specified object matches some installed + volume populator or dynamic provisioner. + This field will replace the functionality + of the dataSource field and as such + if both fields are non-empty, they must + have the same value. For backwards compatibility, + when namespace isn''t specified in dataSourceRef, + both fields (dataSource and dataSourceRef) + will be set to the same value automatically + if one of them is empty and the other + is non-empty. When namespace is specified + in dataSourceRef, dataSource isn''t + set to the same value and must be empty. + There are three important differences + between dataSource and dataSourceRef: + * While dataSource only allows two specific + types of objects, dataSourceRef allows + any non-core object, as well as PersistentVolumeClaim + objects. * While dataSource ignores + disallowed values (dropping them), dataSourceRef + preserves all values, and generates + an error if a disallowed value is specified. + * While dataSource only allows local + objects, dataSourceRef allows objects + in any namespaces. (Beta) Using this + field requires the AnyVolumeDataSource + feature gate to be enabled. (Alpha) + Using the namespace field of dataSourceRef + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, the + specified Kind must be in the core + API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: Namespace is the namespace + of resource being referenced Note + that when a namespace is specified, + a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent + namespace to allow that namespace's + owner to accept the reference. See + the ReferenceGrant documentation + for details. (Alpha) This field + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents the + minimum resources the volume should + have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed + to specify resource requirements that + are lower than previous value but must + still be higher than capacity recorded + in the status field of the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the names + of resources, defined in spec.resourceClaims, + that are used by this container. + \n This is an alpha field and requires + enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. + It can only be set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match + the name of one entry in pod.spec.resourceClaims + of the Pod where this field + is used. It makes that resource + available inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the + maximum amount of compute resources + allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the + minimum amount of compute resources + required. If Requests is omitted + for a container, it defaults to + Limits if that is explicitly specified, + otherwise to an implementation-defined + value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query + over volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a + list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a + set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values + array must be non-empty. If + the operator is Exists or + DoesNotExist, the values array + must be empty. This array + is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName is the + name of the StorageClass required by + the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type + of volume is required by the claim. + Value of Filesystem is implied when + not included in claim spec. + type: string + volumeName: + description: volumeName is the binding + reference to the PersistentVolume backing + this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource + that is attached to a kubelet's host machine and + then exposed to the pod. + properties: + fsType: + description: 'fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. TODO: how do we prevent errors + in the filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target + worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume world + wide identifiers (wwids) Either wwids or combination + of targetWWNs and lun must be set, but not both + simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume + resource that is provisioned/attached using an exec + based plugin. + properties: + driver: + description: driver is the name of the driver + to use for this volume. + type: string + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". The default filesystem depends on FlexVolume + script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field + holds extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef + is reference to the secret object containing + sensitive information to pass to the plugin + scripts. This may be empty if no secret object + is specified. If the secret object contains + more than one secret, all secrets are passed + to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume attached + to a kubelet's host machine. This depends on the + Flocker control service being running + properties: + datasetName: + description: datasetName is Name of the dataset + stored as metadata -> name on the dataset for + Flocker should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. + This is unique identifier of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE Disk + resource that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of the + volume that you want to mount. Tip: Ensure that + the filesystem type is supported by the host + operating system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in the + volume that you want to mount. If omitted, the + default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for + /dev/sda is "0" (or you can leave the property + empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the PD + resource in GCE. Used to identify the disk in + GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository + at a particular revision. DEPRECATED: GitRepo is + deprecated. To provision a container with a git + repo, mount an EmptyDir into an InitContainer that + clones the repo using git, then mount the EmptyDir + into the Pod''s container.' + properties: + directory: + description: directory is the target directory + name. Must not contain or start with '..'. If + '.' is supplied, the volume directory will be + the git repository. Otherwise, if specified, + the volume will contain the git repository in + the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the + specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs mount + on the host that shares a pod''s lifetime. More + info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name that + details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume path. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the Glusterfs + volume to be mounted with read-only permissions. + Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing file + or directory on the host machine that is directly + exposed to the container. This is generally used + for system agents or other privileged things that + are allowed to see the host machine. Most containers + will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can use + host directory mounts and who can/can not mount + host directories as read/write.' + properties: + path: + description: 'path of the directory on the host. + If the path is a symlink, it will follow the + link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults + to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource + that is attached to a kubelet''s host machine and + then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether + support iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support + iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI + Initiator Name. If initiatorName is specified + with iscsiInterface simultaneously, new iSCSI + interface : will + be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified + Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface Name + that uses an iSCSI transport. Defaults to 'default' + (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal + List. The portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for + iSCSI target and initiator authentication + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target Portal. + The Portal is either an IP or ip_addr:port if + the port is other than default (typically TCP + ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL + and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the host + that shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the NFS + server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the NFS + export to be mounted with read-only permissions. + Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP address + of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource represents + a reference to a PersistentVolumeClaim in the same + namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this + volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets + host machine + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon + Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx + volume attached and mounted on kubelets host machine + properties: + fsType: + description: fSType represents the filesystem + type to mount Must be a filesystem type supported + by the host operating system. Ex. "ext4", "xfs". + Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx + volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources + secrets, configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits used + to set permissions on created files by default. + Must be an octal value between 0000 and 0777 + or a decimal value between 0 and 511. YAML accepts + both octal and decimal values, JSON requires + decimal values for mode bits. Directories within + the path are not affected by this setting. This + might be in conflict with other options that + affect the file mode, like fsGroup, and the + result can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume projections + items: + description: Projection that may be projected + along with other supported volume types + properties: + configMap: + description: configMap information about + the configMap data to project + properties: + items: + description: items if unspecified, each + key-value pair in the Data field of + the referenced ConfigMap will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will + be projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not + present in the ConfigMap, the volume + setup will error unless it is marked + optional. Paths must be relative and + may not contain the '..' path or start + with '..'. + items: + description: Maps a string key to + a path within a volume. + properties: + key: + description: key is the key to + project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 + or a decimal value between 0 + and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume + defaultMode will be used. This + might be in conflict with other + options that affect the file + mode, like fsGroup, and the + result can be other mode bits + set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the + key to. May not be an absolute + path. May not contain the path + element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about + the downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile + represents information to create + the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only annotations, + labels, name and namespace are + supported.' + properties: + apiVersion: + description: Version of the + schema the FieldPath is + written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field + to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits + used to set permissions on this + file, must be an octal value + between 0000 and 0777 or a decimal + value between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If not + specified, the volume defaultMode + will be used. This might be + in conflict with other options + that affect the file mode, like + fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file + to be created. Must not be absolute + or contain the ''..'' path. + Must be utf-8 encoded. The first + item of the relative path must + not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource + of the container: only resources + limits and requests (limits.cpu, + limits.memory, requests.cpu + and requests.memory) are currently + supported.' + properties: + containerName: + description: 'Container name: + required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the + output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about the + secret data to project + properties: + items: + description: items if unspecified, each + key-value pair in the Data field of + the referenced Secret will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will + be projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not + present in the Secret, the volume + setup will error unless it is marked + optional. Paths must be relative and + may not contain the '..' path or start + with '..'. + items: + description: Maps a string key to + a path within a volume. + properties: + key: + description: key is the key to + project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 + or a decimal value between 0 + and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume + defaultMode will be used. This + might be in conflict with other + options that affect the file + mode, like fsGroup, and the + result can be other mode bits + set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the + key to. May not be an absolute + path. May not contain the path + element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional field specify + whether the Secret or its key must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to + project + properties: + audience: + description: audience is the intended + audience of the token. A recipient + of a token must identify itself with + an identifier specified in the audience + of the token, and otherwise should + reject the token. The audience defaults + to the identifier of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is the + requested duration of validity of + the service account token. As the + token approaches expiration, the kubelet + volume plugin will proactively rotate + the service account token. The kubelet + will start trying to rotate the token + if the token is older than 80 percent + of its time to live or if the token + is older than 24 hours.Defaults to + 1 hour and must be at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative + to the mount point of the file to + project the token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount on + the host that shares a pod's lifetime + properties: + group: + description: group to map volume access to Default + is no group + type: string + readOnly: + description: readOnly here will force the Quobyte + volume to be mounted with read-only permissions. + Defaults to false. + type: boolean + registry: + description: registry represents a single or multiple + Quobyte Registry services specified as a string + as host:port pair (multiple entries are separated + with commas) which acts as the central registry + for volumes + type: string + tenant: + description: tenant owning the given Quobyte volume + in the Backend Used with dynamically provisioned + Quobyte volumes, value is set by the plugin + type: string + user: + description: user to map volume access to Defaults + to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + image: + description: 'image is the rados image name. More + info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring + for RBDUser. Default is /etc/ceph/keyring. More + info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of Ceph + monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. Default + is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides keyring. + Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. Default + is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of the + ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the + ScaleIO Protection Domain for the configured + storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret + for ScaleIO user and other sensitive information. + If this is not provided, Login operation will + fail. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL + communication with Gateway, default false + type: boolean + storageMode: + description: storageMode indicates whether the + storage for a volume should be ThickProvisioned + or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage + Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage + system as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume + already created in the ScaleIO system that is + associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that should + populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: items If unspecified, each key-value + pair in the Data field of the referenced Secret + will be projected into the volume as a file + whose name is the key and content is the value. + If specified, the listed keys will be projected + into the specified paths, and unlisted keys + will not be present. If a key is specified which + is not present in the Secret, the volume setup + will error unless it is marked optional. Paths + must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 and + 0777 or a decimal value between 0 and + 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. If not specified, the volume + defaultMode will be used. This might be + in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path of + the file to map the key to. May not be + an absolute path. May not contain the + path element '..'. May not start with + the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether the + Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the secret + in the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS volume + attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret to + use for obtaining the StorageOS API credentials. If + not specified, default values will be attempted. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable + name of the StorageOS volume. Volume names + are only unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the scope + of the volume within StorageOS. If no namespace + is specified then the Pod's namespace will be + used. This allows the Kubernetes name scoping + to be mirrored within StorageOS for tighter + integration. Set VolumeName to any name to override + the default behaviour. Set to "default" if you + are not using namespaces within StorageOS. Namespaces + that do not pre-exist within StorageOS will + be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere volume + attached and mounted on kubelets host machine + properties: + fsType: + description: fsType is filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy + Based Management (SPBM) profile ID associated + with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage + Policy Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name type: object - type: object - timeOffset: - description: TimeOffset defines the delta time of injected - program. It's a possibly signed sequence of decimal numbers, - such as "300ms", "-1.5h" or "2h45m". Valid time units are - "ns", "us" (or "µs"), "ms", "s", "m", "h". - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - mode - - selector - - timeOffset - type: object - required: - - name - - template_type - type: object - type: array - required: - - entry - - templates - type: object - status: - description: Most recently observed status of the workflow - properties: - entry_node: - type: string - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: array + type: object + templateType: + type: string + timeChaos: + description: TimeChaosSpec defines the desired state of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id All + available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected + program. It's a possibly signed sequence of decimal numbers, + such as "300ms", "-1.5h" or "2h45m". Valid time units + are "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + required: + - name + - templateType + type: object + type: array + required: + - entry + - templates + type: object + status: + description: Most recently observed status of the workflow + properties: + conditions: + description: Represents the latest available observations of a workflow's + current state. + items: + properties: + reason: + type: string + startTime: + format: date-time + type: string + status: + type: string + type: + type: string + required: + - reason + - status + - type + type: object + type: array + endTime: + format: date-time + type: string + entryNode: + type: string + startTime: + format: date-time + type: string + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 038eed776a..48961738b4 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -1,3 +1,4 @@ + # This kustomization.yaml is not intended to be run by itself, # since it depends on service name and namespace that are out of this kustomize package. # It should be run by config/default @@ -9,14 +10,22 @@ resources: - bases/chaos-mesh.org_kernelchaos.yaml - bases/chaos-mesh.org_stresschaos.yaml - bases/chaos-mesh.org_podiochaos.yaml +- bases/chaos-mesh.org_podhttpchaos.yaml - bases/chaos-mesh.org_podnetworkchaos.yaml - bases/chaos-mesh.org_httpchaos.yaml - bases/chaos-mesh.org_dnschaos.yaml - bases/chaos-mesh.org_awschaos.yaml +- bases/chaos-mesh.org_azurechaos.yaml - bases/chaos-mesh.org_jvmchaos.yaml - bases/chaos-mesh.org_gcpchaos.yaml - bases/chaos-mesh.org_workflows.yaml - bases/chaos-mesh.org_workflownodes.yaml +- bases/chaos-mesh.org_schedules.yaml +- bases/chaos-mesh.org_physicalmachinechaos.yaml +- bases/chaos-mesh.org_physicalmachines.yaml +- bases/chaos-mesh.org_blockchaos.yaml +- bases/chaos-mesh.org_statuschecks.yaml +- bases/chaos-mesh.org_remoteclusters.yaml # +kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: diff --git a/config/crd/kustomizeconfig.yaml b/config/crd/kustomizeconfig.yaml index 6f83d9a94b..d120f270ea 100644 --- a/config/crd/kustomizeconfig.yaml +++ b/config/crd/kustomizeconfig.yaml @@ -1,3 +1,4 @@ + # This file is for teaching kustomize how to substitute name and namespace reference in CRD nameReference: - kind: Service diff --git a/config/crd/patches/cainjection_in_iochaos.yaml b/config/crd/patches/cainjection_in_iochaos.yaml index f0c11b787c..5564faabc8 100644 --- a/config/crd/patches/cainjection_in_iochaos.yaml +++ b/config/crd/patches/cainjection_in_iochaos.yaml @@ -1,3 +1,4 @@ + # The following patch adds a directive for certmanager to inject CA into the CRD # CRD conversion requires k8s 1.13 or later. apiVersion: apiextensions.k8s.io/v1beta1 diff --git a/config/crd/patches/cainjection_in_networkchaos.yaml b/config/crd/patches/cainjection_in_networkchaos.yaml index 79749e8a66..7d79280e25 100644 --- a/config/crd/patches/cainjection_in_networkchaos.yaml +++ b/config/crd/patches/cainjection_in_networkchaos.yaml @@ -1,3 +1,4 @@ + # The following patch adds a directive for certmanager to inject CA into the CRD # CRD conversion requires k8s 1.13 or later. apiVersion: apiextensions.k8s.io/v1beta1 diff --git a/config/crd/patches/cainjection_in_podchaos.yaml b/config/crd/patches/cainjection_in_podchaos.yaml index 5cba2d0ff6..c6d94efb53 100644 --- a/config/crd/patches/cainjection_in_podchaos.yaml +++ b/config/crd/patches/cainjection_in_podchaos.yaml @@ -1,3 +1,4 @@ + # The following patch adds a directive for certmanager to inject CA into the CRD # CRD conversion requires k8s 1.13 or later. apiVersion: apiextensions.k8s.io/v1beta1 diff --git a/config/crd/patches/webhook_in_iochaos.yaml b/config/crd/patches/webhook_in_iochaos.yaml index 36c10e4f34..e133f1d7ba 100644 --- a/config/crd/patches/webhook_in_iochaos.yaml +++ b/config/crd/patches/webhook_in_iochaos.yaml @@ -1,3 +1,4 @@ + # The following patch enables conversion webhook for CRD # CRD conversion requires k8s 1.13 or later. apiVersion: apiextensions.k8s.io/v1beta1 diff --git a/config/crd/patches/webhook_in_networkchaos.yaml b/config/crd/patches/webhook_in_networkchaos.yaml index 323e81424a..c8dbf97304 100644 --- a/config/crd/patches/webhook_in_networkchaos.yaml +++ b/config/crd/patches/webhook_in_networkchaos.yaml @@ -1,3 +1,4 @@ + # The following patch enables conversion webhook for CRD # CRD conversion requires k8s 1.13 or later. apiVersion: apiextensions.k8s.io/v1beta1 diff --git a/config/crd/patches/webhook_in_podchaos.yaml b/config/crd/patches/webhook_in_podchaos.yaml index d8b2e6035b..1f78576443 100644 --- a/config/crd/patches/webhook_in_podchaos.yaml +++ b/config/crd/patches/webhook_in_podchaos.yaml @@ -1,3 +1,4 @@ + # The following patch enables conversion webhook for CRD # CRD conversion requires k8s 1.13 or later. apiVersion: apiextensions.k8s.io/v1beta1 diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index 8ee798e7f6..a72f1a12ad 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -1,3 +1,4 @@ + namePrefix: chaos-mesh- bases: diff --git a/config/default/manager_webhook_patch.yaml b/config/default/manager_webhook_patch.yaml index 738de350b7..855e495c4d 100644 --- a/config/default/manager_webhook_patch.yaml +++ b/config/default/manager_webhook_patch.yaml @@ -1,3 +1,4 @@ + apiVersion: apps/v1 kind: Deployment metadata: diff --git a/config/samples/chaosoperator_v1alpha1_iochaos.yaml b/config/samples/chaosoperator_v1alpha1_iochaos.yaml index 30bf1368ec..814d3e4227 100644 --- a/config/samples/chaosoperator_v1alpha1_iochaos.yaml +++ b/config/samples/chaosoperator_v1alpha1_iochaos.yaml @@ -1,5 +1,6 @@ + apiVersion: chaosmesh.chaos-mesh.org/v1alpha1 -kind: IoChaos +kind: IOChaos metadata: name: iochaos-sample spec: diff --git a/config/samples/chaosoperator_v1alpha1_networkchaos.yaml b/config/samples/chaosoperator_v1alpha1_networkchaos.yaml index 59fe285702..3d79934986 100644 --- a/config/samples/chaosoperator_v1alpha1_networkchaos.yaml +++ b/config/samples/chaosoperator_v1alpha1_networkchaos.yaml @@ -1,3 +1,4 @@ + apiVersion: chaos-mesh.org/v1alpha1 kind: NetworkChaos metadata: diff --git a/config/samples/chaosoperator_v1alpha1_podchaos.yaml b/config/samples/chaosoperator_v1alpha1_podchaos.yaml index 09fde94d91..9e01a12e8d 100644 --- a/config/samples/chaosoperator_v1alpha1_podchaos.yaml +++ b/config/samples/chaosoperator_v1alpha1_podchaos.yaml @@ -1,3 +1,4 @@ + apiVersion: chaos-mesh.org/v1alpha1 kind: PodChaos metadata: diff --git a/config/webhook/kustomization.yaml b/config/webhook/kustomization.yaml index 8ddc9c004d..fe66d9488e 100644 --- a/config/webhook/kustomization.yaml +++ b/config/webhook/kustomization.yaml @@ -1,5 +1,5 @@ -resources: -- manifests.yaml + +resources: [] configurations: - kustomizeconfig.yaml diff --git a/config/webhook/kustomizeconfig.yaml b/config/webhook/kustomizeconfig.yaml index 25e21e3c96..8bd005ff6b 100644 --- a/config/webhook/kustomizeconfig.yaml +++ b/config/webhook/kustomizeconfig.yaml @@ -1,3 +1,4 @@ + # the following config is for teaching kustomize where to look at when substituting vars. # It requires kustomize v2.1.0 or newer to work properly. nameReference: diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml deleted file mode 100644 index a1bdbd22d8..0000000000 --- a/config/webhook/manifests.yaml +++ /dev/null @@ -1,27 +0,0 @@ - ---- -apiVersion: admissionregistration.k8s.io/v1beta1 -kind: ValidatingWebhookConfiguration -metadata: - creationTimestamp: null - name: validating-webhook-configuration -webhooks: -- clientConfig: - caBundle: Cg== - service: - name: webhook-service - namespace: system - path: /inject-v1-pod - failurePolicy: Fail - name: vpod.kb.io - timeoutSeconds: 5 - rules: - - apiGroups: - - "" - apiVersions: - - v1 - operations: - - CREATE - - UPDATE - resources: - - pods diff --git a/container-image.generated.mk b/container-image.generated.mk new file mode 100644 index 0000000000..8019e8f86a --- /dev/null +++ b/container-image.generated.mk @@ -0,0 +1,91 @@ +# Generated by ./cmd/generate-makefile. DO NOT EDIT. + +##@ Generated targets in container-image.generated.mk + +.PHONY: image +image-all: image-chaos-daemon image-chaos-mesh image-chaos-dashboard image-build-env image-dev-env image-e2e-helper image-chaos-mesh-e2e image-chaos-kernel image-chaos-dlv ## Build all container images + +.PHONY: image-chaos-daemon +image-chaos-daemon: images/chaos-daemon/.dockerbuilt ## Build container image for chaos-daemon, ghcr.io/chaos-mesh/chaos-daemon:latest + +images/chaos-daemon/.dockerbuilt: SHELL=bash +images/chaos-daemon/.dockerbuilt: images/chaos-daemon/bin/chaos-daemon images/chaos-daemon/bin/pause images/chaos-daemon/bin/cdh images/chaos-daemon/Dockerfile + $(ROOT)/build/build_image.py chaos-daemon images/chaos-daemon + touch images/chaos-daemon/.dockerbuilt + +.PHONY: image-chaos-mesh +image-chaos-mesh: images/chaos-mesh/.dockerbuilt ## Build container image for chaos-mesh, ghcr.io/chaos-mesh/chaos-mesh:latest + +images/chaos-mesh/.dockerbuilt: SHELL=bash +images/chaos-mesh/.dockerbuilt: images/chaos-mesh/bin/chaos-controller-manager images/chaos-mesh/Dockerfile + $(ROOT)/build/build_image.py chaos-mesh images/chaos-mesh + touch images/chaos-mesh/.dockerbuilt + +.PHONY: image-chaos-dashboard +image-chaos-dashboard: images/chaos-dashboard/.dockerbuilt ## Build container image for chaos-dashboard, ghcr.io/chaos-mesh/chaos-dashboard:latest + +images/chaos-dashboard/.dockerbuilt: SHELL=bash +images/chaos-dashboard/.dockerbuilt: images/chaos-dashboard/bin/chaos-dashboard images/chaos-dashboard/Dockerfile + $(ROOT)/build/build_image.py chaos-dashboard images/chaos-dashboard + touch images/chaos-dashboard/.dockerbuilt + +.PHONY: image-build-env +image-build-env: images/build-env/.dockerbuilt ## Build container image for build-env, ghcr.io/chaos-mesh/build-env:latest + +images/build-env/.dockerbuilt: SHELL=bash +images/build-env/.dockerbuilt: images/build-env/Dockerfile + $(ROOT)/build/build_image.py build-env images/build-env + touch images/build-env/.dockerbuilt + +.PHONY: image-dev-env +image-dev-env: images/dev-env/.dockerbuilt ## Build container image for dev-env, ghcr.io/chaos-mesh/dev-env:latest + +images/dev-env/.dockerbuilt: SHELL=bash +images/dev-env/.dockerbuilt: images/dev-env/Dockerfile + $(ROOT)/build/build_image.py dev-env images/dev-env + touch images/dev-env/.dockerbuilt + +.PHONY: image-e2e-helper +image-e2e-helper: e2e-test/cmd/e2e_helper/.dockerbuilt ## Build container image for e2e-helper + +e2e-test/cmd/e2e_helper/.dockerbuilt: SHELL=bash +e2e-test/cmd/e2e_helper/.dockerbuilt: e2e-test/cmd/e2e_helper/Dockerfile + $(ROOT)/build/build_image.py e2e-helper e2e-test/cmd/e2e_helper + touch e2e-test/cmd/e2e_helper/.dockerbuilt + +.PHONY: image-chaos-mesh-e2e +image-chaos-mesh-e2e: e2e-test/image/e2e/.dockerbuilt ## Build container image for running e2e tests + +e2e-test/image/e2e/.dockerbuilt: SHELL=bash +e2e-test/image/e2e/.dockerbuilt: e2e-test/image/e2e/manifests e2e-test/image/e2e/chaos-mesh e2e-build e2e-test/image/e2e/Dockerfile + $(ROOT)/build/build_image.py chaos-mesh-e2e e2e-test/image/e2e + touch e2e-test/image/e2e/.dockerbuilt + +.PHONY: image-chaos-kernel +image-chaos-kernel: images/chaos-kernel/.dockerbuilt ## Build container image for chaos-kernel, ghcr.io/chaos-mesh/chaos-kernel:latest + +images/chaos-kernel/.dockerbuilt: SHELL=bash +images/chaos-kernel/.dockerbuilt: images/chaos-kernel/Dockerfile + $(ROOT)/build/build_image.py chaos-kernel images/chaos-kernel + touch images/chaos-kernel/.dockerbuilt + +.PHONY: image-chaos-dlv +image-chaos-dlv: images/chaos-dlv/.dockerbuilt ## Build container image for chaos-dlv + +images/chaos-dlv/.dockerbuilt: SHELL=bash +images/chaos-dlv/.dockerbuilt: images/chaos-dlv/Dockerfile + $(ROOT)/build/build_image.py chaos-dlv images/chaos-dlv + touch images/chaos-dlv/.dockerbuilt + +.PHONY: clean-image-built +clean-image-built: + rm -f images/chaos-daemon/.dockerbuilt + rm -f images/chaos-mesh/.dockerbuilt + rm -f images/chaos-dashboard/.dockerbuilt + rm -f images/build-env/.dockerbuilt + rm -f images/dev-env/.dockerbuilt + rm -f e2e-test/cmd/e2e_helper/.dockerbuilt + rm -f e2e-test/image/e2e/.dockerbuilt + rm -f images/chaos-kernel/.dockerbuilt + rm -f images/chaos-dlv/.dockerbuilt + diff --git a/controllers/README.md b/controllers/README.md new file mode 100644 index 0000000000..649a96ed43 --- /dev/null +++ b/controllers/README.md @@ -0,0 +1,108 @@ +# Controller Design of Chaos Mesh + +This document describes the common controller specification in Chaos Mesh. +Although no "standard" should be considered as absolute requirements (and the +real world is full of trade-off and corner case), they should be carefully +considered when you are trying to add a new controller. + +## One controller per field + +One field should only be "controlled" by at most one controller. In this +chapter, multiple reasons will be listed for this design: + +### Avoid the hidden bugs + +Multiple controllers modifying a single object could lead to a conflict +situation (which is more like a global optimistic lock). The common way to solve +conflict is to adapt the modification and retry. However, if multiple +controllers want to modify a single field, how could they merge the conflict? +What's more, it always leads to a hidden bug under the logic. Here is an +example: + +If you want to split "pause" and "duration" (the former common chaos) into two +standalone controllers, let's try to describe the logic of them: + +For the "pause" controller, when the annotation is added, the chaos should enter +"not injected" mode, and when the annotation is removed, the chaos should enter +"injected" mode. + +For the "duration" controller, when the time exceeds the duration, the chaos +should enter "not injected" mode. + +Though these logics seem to be intuitive, there is a bug under the conflict +"mode" (or the `desiredPhase` in the current code). What will happen if the user +removes the annotation after the duration exceed? The chaos will enter +"injected" and then turn into "not injected" mode (with the help of "duration" +controller), which is dirty and confusing. + +If we obey the "One field per controller" rule, then they should be combined +into one controller and can never be split. + +### Handle the conflict in an easier way + +After retrying the conflict error, we don't need to rerun the whole controller +logic (as there may be some side effects in the controller). Instead, we could +save the single field, and set the corresponding field after getting the new +object. Which will give us more confidence in the retry attempting. + +## Controller should work standalone + +The behavior of every controller should be defined carefully, and they should be +able to work without other controllers. The behavior of the controller should +also be simple and easy to understand. Try to conclude the action/logic of the +controller in one hundred words, if you failed, please reconsider whether it +should be "one" controller, but not two or more (or even split a new +CustomResource). + +## Controller should be well documented + +Every controller should be described with a "little"/"short" document. + +## Error Handling + +According to the source code of `controller-runtime`: + +```go +// RunInformersAndControllers the syncHandler, passing it the namespace/Name string of the +// resource to be synced. +if result, err := c.Do.Reconcile(req); err != nil { + c.Queue.AddRateLimited(req) + log.Error(err, "Reconciler error", "controller", c.Name, "request", req) + ctrlmetrics.ReconcileErrors.WithLabelValues(c.Name).Inc() + ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, "error").Inc() + return false +} else if result.RequeueAfter > 0 { + // The result.RequeueAfter request will be lost, if it is returned + // along with a non-nil error. But this is intended as + // We need to drive to stable reconcile loops before queuing due + // to result.RequestAfter + c.Queue.Forget(obj) + c.Queue.AddAfter(req, result.RequeueAfter) + ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, "requeue_after").Inc() + return true +} else if result.Requeue { + c.Queue.AddRateLimited(req) + ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, "requeue").Inc() + return true +} +``` + +If the `Reconcile` return a `Requeue` without `RequeueAfter`, this request will +be added to the `RateLimitQueue`. The default `RateLimitQueue` is constructured +in this way: + +```go +// DefaultControllerRateLimiter is a no-arg constructor for a default rate limiter for a workqueue. It has +// both overall and per-item rate limiting. The overall is a token bucket and the per-item is exponential +func DefaultControllerRateLimiter() RateLimiter { + return NewMaxOfRateLimiter( + NewItemExponentialFailureRateLimiter(5*time.Millisecond, 1000*time.Second), + // 10 qps, 100 bucket size. This is only for retry speed and its only the overall factor (not per item) + &BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)}, + ) +} +``` + +So it's a good enough error back off without stopping the worker. When a +controller meets a retriable error, the simplest way to handle it is returning a +`ctrl.Result{Requeue: true}, nil` \ No newline at end of file diff --git a/controllers/action/multiplexer.go b/controllers/action/multiplexer.go new file mode 100644 index 0000000000..40656bfb2c --- /dev/null +++ b/controllers/action/multiplexer.go @@ -0,0 +1,132 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package action introduces a multiplexer for actions. +package action + +import ( + "context" + "fmt" + "reflect" + "strings" + + "k8s.io/apimachinery/pkg/runtime" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +// TODO: refactor this as a map[name]impltypes.ChaosImpl style, remove reflect usage. + +var _ impltypes.ChaosImpl = (*Multiplexer)(nil) + +// Multiplexer could combine ChaosImpl implementations into one, and route them by Action in the ChaosSpec. +// Field impl should be a struct which contains several fields with struct tag "action", each field should be an implementation of ChaosImpl. +// For example: +// +// type tempStruct struct { +// Impl1 impltypes.ChaosImpl `action:"action1"` +// Impl2 impltypes.ChaosImpl `action:"action2"` +// } +// +// is valid to be the field in Multiplexer. +// +// Because we use reflect fo iterate fields in tempStruct, so fields in tempStruct should be public/exported. +// +// When some Chaos like: +// +// type SomeChaos struct { +// *** +// Spec SomeChaosSpec `json:"spec"` +// *** +// } +// type SomeChaosSpec struct { +// *** +// // available actions: action1, action2 +// Action string `json:"action"` +// *** +// } +// +// is created, the corresponding ChaosImpl(s) for each action will be invoked by struct tag. +type Multiplexer struct { + impl interface{} +} + +func (i *Multiplexer) callAccordingToAction(action, methodName string, defaultPhase v1alpha1.Phase, args ...interface{}) (v1alpha1.Phase, error) { + implType := reflect.TypeOf(i.impl).Elem() + implVal := reflect.ValueOf(i.impl) + + reflectArgs := []reflect.Value{} + for _, arg := range args { + reflectArgs = append(reflectArgs, reflect.ValueOf(arg)) + } + for i := 0; i < implType.NumField(); i++ { + field := implType.Field(i) + + actions := strings.Split(field.Tag.Get("action"), ",") + for i := range actions { + if actions[i] == action { + rets := implVal.Elem().FieldByIndex(field.Index).MethodByName(methodName).Call(reflectArgs) + + // nil.(error) will panic :( + err := rets[1].Interface() + if err == nil { + return rets[0].Interface().(v1alpha1.Phase), nil + } + + return rets[0].Interface().(v1alpha1.Phase), err.(error) + } + } + } + var gvk = "" + if obj, ok := args[len(args)-1].(runtime.Object); ok { + gvk = obj.GetObjectKind().GroupVersionKind().String() + } + return defaultPhase, NewErrorUnknownAction(gvk, action) +} + +type ErrorUnknownAction struct { + GroupVersionKind string + Action string +} + +func NewErrorUnknownAction(GVK string, action string) ErrorUnknownAction { + return ErrorUnknownAction{GroupVersionKind: GVK, Action: action} +} + +func (it ErrorUnknownAction) Error() string { + return fmt.Sprintf("unknown action: Action: %s, GroupVersionKind: %s", it.Action, it.GroupVersionKind) +} + +// TODO: refactor this by introduce a new interface called ContainsAction +func (i *Multiplexer) getAction(obj v1alpha1.InnerObject) string { + return reflect.ValueOf(obj).Elem().FieldByName("Spec").FieldByName("Action").String() +} + +func (i *Multiplexer) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + return i.callAccordingToAction(i.getAction(obj), "Apply", v1alpha1.NotInjected, ctx, index, records, obj) +} + +func (i *Multiplexer) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + return i.callAccordingToAction(i.getAction(obj), "Recover", v1alpha1.Injected, ctx, index, records, obj) +} + +// NewMultiplexer is a constructor of Multiplexer. +// For the detail of the parameter "impl", see the comment of type Multiplexer. +func NewMultiplexer(impl interface{}) Multiplexer { + return Multiplexer{ + impl, + } +} diff --git a/controllers/action/multiplexer_examples_test.go b/controllers/action/multiplexer_examples_test.go new file mode 100644 index 0000000000..c94b48fc97 --- /dev/null +++ b/controllers/action/multiplexer_examples_test.go @@ -0,0 +1,90 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package action + +import ( + "context" + "fmt" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type chaosImplForAction1 struct { +} + +func (it *chaosImplForAction1) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + fmt.Println("action1-apply") + return v1alpha1.Injected, nil +} + +func (it *chaosImplForAction1) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + fmt.Println("action1-recover") + return v1alpha1.NotInjected, nil +} + +type chaosImplForAction2 struct { +} + +func (it *chaosImplForAction2) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + fmt.Println("action2-apply") + return v1alpha1.Injected, nil +} + +func (it *chaosImplForAction2) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + fmt.Println("action2-recover") + return v1alpha1.NotInjected, nil +} + +func ExampleMultiplexer() { + type adHoc struct { + AnyName1 *chaosImplForAction1 `action:"struct-tag"` + WhateverTheName *chaosImplForAction2 `action:"is-important"` + } + multiplexer := NewMultiplexer(&adHoc{ + AnyName1: &chaosImplForAction1{}, + WhateverTheName: &chaosImplForAction2{}, + }) + + // Just use PodChaos as example, you could use any struct that contains Spec.Action for it. + chaosA := v1alpha1.PodChaos{ + Spec: v1alpha1.PodChaosSpec{ + Action: "struct-tag", + }, + } + chaosB := v1alpha1.PodChaos{ + Spec: v1alpha1.PodChaosSpec{ + Action: "is-important", + }, + } + + if _, err := multiplexer.Apply(context.Background(), 0, nil, &chaosA); err != nil { + panic(err) + } + if _, err := multiplexer.Recover(context.Background(), 0, nil, &chaosA); err != nil { + panic(err) + } + if _, err := multiplexer.Apply(context.Background(), 0, nil, &chaosB); err != nil { + panic(err) + } + if _, err := multiplexer.Recover(context.Background(), 0, nil, &chaosB); err != nil { + panic(err) + } + + // Output: action1-apply + // action1-recover + // action2-apply + // action2-recover +} diff --git a/controllers/action/multiplexer_test.go b/controllers/action/multiplexer_test.go new file mode 100644 index 0000000000..fd2ab1cafa --- /dev/null +++ b/controllers/action/multiplexer_test.go @@ -0,0 +1,98 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package action + +import ( + "context" + "testing" + + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type mockApplyError struct { +} + +func (it *mockApplyError) Error() string { + return "mock apply error" +} + +type mockRecoverError struct { +} + +func (it mockRecoverError) Error() string { + return "mock recover error" +} + +type chaosImplMustFailed struct { +} + +func (it *chaosImplMustFailed) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + return v1alpha1.NotInjected, &mockApplyError{} + +} + +func (it *chaosImplMustFailed) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + return v1alpha1.Injected, mockRecoverError{} +} + +func TestMultiplexer_passthroughsError(t *testing.T) { + type adHoc struct { + Backend *chaosImplMustFailed `action:"must-failed"` + } + multiplexer := NewMultiplexer(&adHoc{ + Backend: &chaosImplMustFailed{}, + }) + + // Just use PodChaos as example, you could use any struct that contains Spec.Action for it. + chaos := v1alpha1.PodChaos{ + Spec: v1alpha1.PodChaosSpec{ + Action: "must-failed", + }, + } + _, err := multiplexer.Apply(context.Background(), 0, []*v1alpha1.Record{}, &chaos) + applyError := &mockApplyError{} + if !errors.As(err, &applyError) { + t.Fatal("returned error is not mockApplyError") + } + + _, err = multiplexer.Recover(context.Background(), 0, []*v1alpha1.Record{}, &chaos) + recoverError := mockRecoverError{} + if !errors.As(err, &recoverError) { + t.Fatal("returned error is not recoverError") + } +} + +func TestMultiplexer_unhandledAction(t *testing.T) { + type adHoc struct { + Backend *chaosImplMustFailed `action:"must-failed"` + } + multiplexer := NewMultiplexer(&adHoc{ + // No fields here + }) + chaos := v1alpha1.PodChaos{ + Spec: v1alpha1.PodChaosSpec{ + Action: "not-exist", + }, + } + _, err := multiplexer.Apply(context.Background(), 0, []*v1alpha1.Record{}, &chaos) + unknownAction := ErrorUnknownAction{} + if !errors.As(err, &unknownAction) { + t.Fatal("should not return error") + } + +} diff --git a/controllers/awschaos/detachvolume/types.go b/controllers/awschaos/detachvolume/types.go deleted file mode 100644 index d037a70c17..0000000000 --- a/controllers/awschaos/detachvolume/types.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package detachvolume - -import ( - "context" - "errors" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - - awscfg "github.com/aws/aws-sdk-go-v2/config" - "github.com/aws/aws-sdk-go-v2/credentials" - "github.com/aws/aws-sdk-go-v2/service/ec2" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" -) - -const ( - AwsFinalizer = "aws-finalizer" -) - -type endpoint struct { - ctx.Context -} - -func (e *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - awschaos, ok := chaos.(*v1alpha1.AwsChaos) - if !ok { - err := errors.New("chaos is not awschaos") - e.Log.Error(err, "chaos is not AwsChaos", "chaos", chaos) - return err - } - - opts := []func(*awscfg.LoadOptions) error{ - awscfg.WithRegion(awschaos.Spec.AwsRegion), - } - if awschaos.Spec.SecretName != nil { - secret := &v1.Secret{} - err := e.Client.Get(ctx, types.NamespacedName{ - Name: *awschaos.Spec.SecretName, - Namespace: awschaos.Namespace, - }, secret) - if err != nil { - e.Log.Error(err, "fail to get cloud secret") - return err - } - opts = append(opts, awscfg.WithCredentialsProvider(credentials.NewStaticCredentialsProvider( - string(secret.Data["aws_access_key_id"]), - string(secret.Data["aws_secret_access_key"]), - "", - ))) - } - cfg, err := awscfg.LoadDefaultConfig(ctx, opts...) - if err != nil { - e.Log.Error(err, "unable to load aws SDK config") - return err - } - ec2client := ec2.NewFromConfig(cfg) - - awschaos.Finalizers = []string{AwsFinalizer} - _, err = ec2client.DetachVolume(context.TODO(), &ec2.DetachVolumeInput{ - VolumeId: awschaos.Spec.EbsVolume, - Device: awschaos.Spec.DeviceName, - Force: true, - InstanceId: &awschaos.Spec.Ec2Instance, - }) - - if err != nil { - awschaos.Finalizers = make([]string, 0) - e.Log.Error(err, "fail to detach the volume") - return err - } - - return nil -} - -func (e *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - awschaos, ok := chaos.(*v1alpha1.AwsChaos) - if !ok { - err := errors.New("chaos is not awschaos") - e.Log.Error(err, "chaos is not AwsChaos", "chaos", chaos) - return err - } - - awschaos.Finalizers = make([]string, 0) - opts := []func(*awscfg.LoadOptions) error{ - awscfg.WithRegion(awschaos.Spec.AwsRegion), - } - if awschaos.Spec.SecretName != nil { - secret := &v1.Secret{} - err := e.Client.Get(ctx, types.NamespacedName{ - Name: *awschaos.Spec.SecretName, - Namespace: awschaos.Namespace, - }, secret) - if err != nil { - e.Log.Error(err, "fail to get cloud secret") - return err - } - opts = append(opts, awscfg.WithCredentialsProvider(credentials.NewStaticCredentialsProvider( - string(secret.Data["aws_access_key_id"]), - string(secret.Data["aws_secret_access_key"]), - "", - ))) - } - cfg, err := awscfg.LoadDefaultConfig(ctx, opts...) - if err != nil { - e.Log.Error(err, "unable to load aws SDK config") - return err - } - ec2client := ec2.NewFromConfig(cfg) - - _, err = ec2client.AttachVolume(context.TODO(), &ec2.AttachVolumeInput{ - Device: awschaos.Spec.DeviceName, - InstanceId: &awschaos.Spec.Ec2Instance, - VolumeId: awschaos.Spec.EbsVolume, - }) - - if err != nil { - e.Log.Error(err, "fail to attach the volume") - return err - } - - return nil -} - -func (e *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.AwsChaos{} -} - -func init() { - router.Register("awschaos", &v1alpha1.AwsChaos{}, func(obj runtime.Object) bool { - chaos, ok := obj.(*v1alpha1.AwsChaos) - if !ok { - return false - } - - return chaos.Spec.Action == v1alpha1.DetachVolume - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/awschaos/ec2restart/types.go b/controllers/awschaos/ec2restart/types.go deleted file mode 100644 index f8d1222875..0000000000 --- a/controllers/awschaos/ec2restart/types.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package ec2stop - -import ( - "context" - "errors" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - - awscfg "github.com/aws/aws-sdk-go-v2/config" - "github.com/aws/aws-sdk-go-v2/credentials" - "github.com/aws/aws-sdk-go-v2/service/ec2" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" -) - -type endpoint struct { - ctx.Context -} - -func (e *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - awschaos, ok := chaos.(*v1alpha1.AwsChaos) - if !ok { - err := errors.New("chaos is not awschaos") - e.Log.Error(err, "chaos is not AwsChaos", "chaos", chaos) - return err - } - - opts := []func(*awscfg.LoadOptions) error{ - awscfg.WithRegion(awschaos.Spec.AwsRegion), - } - if awschaos.Spec.SecretName != nil { - secret := &v1.Secret{} - err := e.Client.Get(ctx, types.NamespacedName{ - Name: *awschaos.Spec.SecretName, - Namespace: awschaos.Namespace, - }, secret) - if err != nil { - e.Log.Error(err, "fail to get cloud secret") - return err - } - opts = append(opts, awscfg.WithCredentialsProvider(credentials.NewStaticCredentialsProvider( - string(secret.Data["aws_access_key_id"]), - string(secret.Data["aws_secret_access_key"]), - "", - ))) - } - cfg, err := awscfg.LoadDefaultConfig(ctx, opts...) - if err != nil { - e.Log.Error(err, "unable to load aws SDK config") - return err - } - ec2client := ec2.NewFromConfig(cfg) - - _, err = ec2client.RebootInstances(context.TODO(), &ec2.RebootInstancesInput{ - InstanceIds: []string{awschaos.Spec.Ec2Instance}, - }) - - if err != nil { - e.Log.Error(err, "fail to restart the instance") - return err - } - - return nil -} - -func (e *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - return nil -} - -func (e *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.AwsChaos{} -} - -func init() { - router.Register("awschaos", &v1alpha1.AwsChaos{}, func(obj runtime.Object) bool { - chaos, ok := obj.(*v1alpha1.AwsChaos) - if !ok { - return false - } - - return chaos.Spec.Action == v1alpha1.Ec2Restart - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/awschaos/ec2stop/types.go b/controllers/awschaos/ec2stop/types.go deleted file mode 100644 index de58edfaf1..0000000000 --- a/controllers/awschaos/ec2stop/types.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package ec2stop - -import ( - "context" - "errors" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/aws/aws-sdk-go-v2/aws" - awscfg "github.com/aws/aws-sdk-go-v2/config" - "github.com/aws/aws-sdk-go-v2/credentials" - "github.com/aws/aws-sdk-go-v2/service/ec2" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" -) - -const ( - AwsFinalizer = "aws-finalizer" -) - -type endpoint struct { - ctx.Context -} - -func (e *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - awschaos, ok := chaos.(*v1alpha1.AwsChaos) - if !ok { - err := errors.New("chaos is not awschaos") - e.Log.Error(err, "chaos is not AwsChaos", "chaos", chaos) - return err - } - - opts := []func(*awscfg.LoadOptions) error{ - awscfg.WithRegion(awschaos.Spec.AwsRegion), - } - - if awschaos.Spec.Endpoint != nil { - opts = append(opts, awscfg.WithEndpointResolver(aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) { - return aws.Endpoint{URL: *awschaos.Spec.Endpoint, SigningRegion: region}, nil - }))) - } - - if awschaos.Spec.SecretName != nil { - secret := &v1.Secret{} - err := e.Client.Get(ctx, types.NamespacedName{ - Name: *awschaos.Spec.SecretName, - Namespace: awschaos.Namespace, - }, secret) - if err != nil { - e.Log.Error(err, "fail to get cloud secret") - return err - } - opts = append(opts, awscfg.WithCredentialsProvider(credentials.NewStaticCredentialsProvider( - string(secret.Data["aws_access_key_id"]), - string(secret.Data["aws_secret_access_key"]), - "", - ))) - } - cfg, err := awscfg.LoadDefaultConfig(ctx, opts...) - if err != nil { - e.Log.Error(err, "unable to load aws SDK config") - return err - } - ec2client := ec2.NewFromConfig(cfg) - - awschaos.Finalizers = []string{AwsFinalizer} - _, err = ec2client.StopInstances(context.TODO(), &ec2.StopInstancesInput{ - InstanceIds: []string{awschaos.Spec.Ec2Instance}, - }) - - if err != nil { - awschaos.Finalizers = make([]string, 0) - e.Log.Error(err, "fail to stop the instance") - return err - } - - return nil -} - -func (e *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - awschaos, ok := chaos.(*v1alpha1.AwsChaos) - if !ok { - err := errors.New("chaos is not awschaos") - e.Log.Error(err, "chaos is not AwsChaos", "chaos", chaos) - return err - } - - awschaos.Finalizers = make([]string, 0) - opts := []func(*awscfg.LoadOptions) error{ - awscfg.WithRegion(awschaos.Spec.AwsRegion), - } - if awschaos.Spec.SecretName != nil { - secret := &v1.Secret{} - err := e.Client.Get(ctx, types.NamespacedName{ - Name: *awschaos.Spec.SecretName, - Namespace: awschaos.Namespace, - }, secret) - if err != nil { - e.Log.Error(err, "fail to get cloud secret") - return err - } - opts = append(opts, awscfg.WithCredentialsProvider(credentials.NewStaticCredentialsProvider( - string(secret.Data["aws_access_key_id"]), - string(secret.Data["aws_secret_access_key"]), - "", - ))) - } - cfg, err := awscfg.LoadDefaultConfig(ctx, opts...) - if err != nil { - e.Log.Error(err, "unable to load aws SDK config") - return err - } - ec2client := ec2.NewFromConfig(cfg) - - _, err = ec2client.StartInstances(context.TODO(), &ec2.StartInstancesInput{ - InstanceIds: []string{awschaos.Spec.Ec2Instance}, - }) - - if err != nil { - e.Log.Error(err, "fail to start the instance") - return err - } - - return nil -} - -func (e *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.AwsChaos{} -} - -func init() { - router.Register("awschaos", &v1alpha1.AwsChaos{}, func(obj runtime.Object) bool { - chaos, ok := obj.(*v1alpha1.AwsChaos) - if !ok { - return false - } - - return chaos.Spec.Action == v1alpha1.Ec2Stop - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/chaosimpl/awschaos/detachvolume/impl.go b/controllers/chaosimpl/awschaos/detachvolume/impl.go new file mode 100644 index 0000000000..eb654d19d0 --- /dev/null +++ b/controllers/chaosimpl/awschaos/detachvolume/impl.go @@ -0,0 +1,148 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package detachvolume + +import ( + "context" + "encoding/json" + + awscfg "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/go-logr/logr" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + + Log logr.Logger +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + awschaos := obj.(*v1alpha1.AWSChaos) + + opts := []func(*awscfg.LoadOptions) error{ + awscfg.WithRegion(awschaos.Spec.AWSRegion), + } + if awschaos.Spec.SecretName != nil { + secret := &v1.Secret{} + err := impl.Client.Get(ctx, types.NamespacedName{ + Name: *awschaos.Spec.SecretName, + Namespace: awschaos.Namespace, + }, secret) + if err != nil { + impl.Log.Error(err, "fail to get cloud secret") + return v1alpha1.NotInjected, err + } + opts = append(opts, awscfg.WithCredentialsProvider(credentials.NewStaticCredentialsProvider( + string(secret.Data["aws_access_key_id"]), + string(secret.Data["aws_secret_access_key"]), + string(secret.Data["aws_session_token"]), + ))) + } + cfg, err := awscfg.LoadDefaultConfig(ctx, opts...) + if err != nil { + impl.Log.Error(err, "unable to load aws SDK config") + return v1alpha1.NotInjected, err + } + ec2client := ec2.NewFromConfig(cfg) + + var selected v1alpha1.AWSSelector + err = json.Unmarshal([]byte(records[index].Id), &selected) + if err != nil { + impl.Log.Error(err, "fail to unmarshal the selector") + return v1alpha1.NotInjected, err + } + + _, err = ec2client.DetachVolume(context.TODO(), &ec2.DetachVolumeInput{ + VolumeId: selected.EbsVolume, + Device: selected.DeviceName, + Force: true, + InstanceId: &selected.Ec2Instance, + }) + + if err != nil { + impl.Log.Error(err, "fail to detach the volume") + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + awschaos := obj.(*v1alpha1.AWSChaos) + + opts := []func(*awscfg.LoadOptions) error{ + awscfg.WithRegion(awschaos.Spec.AWSRegion), + } + if awschaos.Spec.SecretName != nil { + secret := &v1.Secret{} + err := impl.Client.Get(ctx, types.NamespacedName{ + Name: *awschaos.Spec.SecretName, + Namespace: awschaos.Namespace, + }, secret) + if err != nil { + impl.Log.Error(err, "fail to get cloud secret") + return v1alpha1.Injected, err + } + opts = append(opts, awscfg.WithCredentialsProvider(credentials.NewStaticCredentialsProvider( + string(secret.Data["aws_access_key_id"]), + string(secret.Data["aws_secret_access_key"]), + string(secret.Data["aws_session_token"]), + ))) + } + cfg, err := awscfg.LoadDefaultConfig(ctx, opts...) + if err != nil { + impl.Log.Error(err, "unable to load aws SDK config") + return v1alpha1.Injected, err + } + ec2client := ec2.NewFromConfig(cfg) + + var selected v1alpha1.AWSSelector + err = json.Unmarshal([]byte(records[index].Id), &selected) + if err != nil { + impl.Log.Error(err, "fail to unmarshal the selector") + return v1alpha1.NotInjected, err + } + + _, err = ec2client.AttachVolume(context.TODO(), &ec2.AttachVolumeInput{ + Device: selected.DeviceName, + InstanceId: &selected.Ec2Instance, + VolumeId: selected.EbsVolume, + }) + + if err != nil { + impl.Log.Error(err, "fail to attach the volume") + return v1alpha1.Injected, err + } + + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client, log logr.Logger) *Impl { + return &Impl{ + Client: c, + Log: log.WithName("detachvolume"), + } +} diff --git a/controllers/chaosimpl/awschaos/ec2restart/impl.go b/controllers/chaosimpl/awschaos/ec2restart/impl.go new file mode 100644 index 0000000000..99fdbecaeb --- /dev/null +++ b/controllers/chaosimpl/awschaos/ec2restart/impl.go @@ -0,0 +1,100 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package ec2restart + +import ( + "context" + "encoding/json" + + awscfg "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/go-logr/logr" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + + Log logr.Logger +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + awschaos := obj.(*v1alpha1.AWSChaos) + + var selected v1alpha1.AWSSelector + err := json.Unmarshal([]byte(records[index].Id), &selected) + if err != nil { + impl.Log.Error(err, "fail to unmarshal the selector") + return v1alpha1.NotInjected, err + } + + opts := []func(*awscfg.LoadOptions) error{ + awscfg.WithRegion(selected.AWSRegion), + } + + if awschaos.Spec.SecretName != nil { + secret := &v1.Secret{} + err := impl.Client.Get(ctx, types.NamespacedName{ + Name: *awschaos.Spec.SecretName, + Namespace: awschaos.Namespace, + }, secret) + if err != nil { + impl.Log.Error(err, "fail to get cloud secret") + return v1alpha1.NotInjected, err + } + opts = append(opts, awscfg.WithCredentialsProvider(credentials.NewStaticCredentialsProvider( + string(secret.Data["aws_access_key_id"]), + string(secret.Data["aws_secret_access_key"]), + string(secret.Data["aws_session_token"]), + ))) + } + cfg, err := awscfg.LoadDefaultConfig(ctx, opts...) + if err != nil { + impl.Log.Error(err, "unable to load aws SDK config") + return v1alpha1.NotInjected, err + } + ec2client := ec2.NewFromConfig(cfg) + + _, err = ec2client.RebootInstances(context.TODO(), &ec2.RebootInstancesInput{ + InstanceIds: []string{selected.Ec2Instance}, + }) + + if err != nil { + impl.Log.Error(err, "fail to restart the instance") + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} + +func (impl *Impl) Recover(_ context.Context, _ int, _ []*v1alpha1.Record, _ v1alpha1.InnerObject) (v1alpha1.Phase, error) { + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client, log logr.Logger) *Impl { + return &Impl{ + Client: c, + Log: log.WithName("ec2restart"), + } +} diff --git a/controllers/chaosimpl/awschaos/ec2stop/impl.go b/controllers/chaosimpl/awschaos/ec2stop/impl.go new file mode 100644 index 0000000000..8c68d43649 --- /dev/null +++ b/controllers/chaosimpl/awschaos/ec2stop/impl.go @@ -0,0 +1,156 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package ec2stop + +import ( + "context" + "encoding/json" + + "github.com/aws/aws-sdk-go-v2/aws" + awscfg "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/go-logr/logr" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + + Log logr.Logger +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + awschaos := obj.(*v1alpha1.AWSChaos) + + var selected v1alpha1.AWSSelector + err := json.Unmarshal([]byte(records[index].Id), &selected) + if err != nil { + impl.Log.Error(err, "fail to unmarshal the selector") + return v1alpha1.NotInjected, err + } + + opts := []func(*awscfg.LoadOptions) error{ + awscfg.WithRegion(selected.AWSRegion), + } + + if selected.Endpoint != nil { + opts = append(opts, awscfg.WithEndpointResolver(aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) { + return aws.Endpoint{URL: *selected.Endpoint, SigningRegion: region}, nil + }))) + } + + if awschaos.Spec.SecretName != nil { + secret := &v1.Secret{} + err := impl.Client.Get(ctx, types.NamespacedName{ + Name: *awschaos.Spec.SecretName, + Namespace: awschaos.Namespace, + }, secret) + if err != nil { + impl.Log.Error(err, "fail to get cloud secret") + return v1alpha1.NotInjected, err + } + opts = append(opts, awscfg.WithCredentialsProvider(credentials.NewStaticCredentialsProvider( + string(secret.Data["aws_access_key_id"]), + string(secret.Data["aws_secret_access_key"]), + string(secret.Data["aws_session_token"]), + ))) + } + cfg, err := awscfg.LoadDefaultConfig(ctx, opts...) + if err != nil { + impl.Log.Error(err, "unable to load aws SDK config") + return v1alpha1.NotInjected, err + } + ec2client := ec2.NewFromConfig(cfg) + + _, err = ec2client.StopInstances(context.TODO(), &ec2.StopInstancesInput{ + InstanceIds: []string{selected.Ec2Instance}, + }) + + if err != nil { + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + awschaos := obj.(*v1alpha1.AWSChaos) + + var selected v1alpha1.AWSSelector + err := json.Unmarshal([]byte(records[index].Id), &selected) + if err != nil { + impl.Log.Error(err, "fail to unmarshal the selector") + return v1alpha1.NotInjected, err + } + + opts := []func(*awscfg.LoadOptions) error{ + awscfg.WithRegion(selected.AWSRegion), + } + + if selected.Endpoint != nil { + opts = append(opts, awscfg.WithEndpointResolver(aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) { + return aws.Endpoint{URL: *selected.Endpoint, SigningRegion: region}, nil + }))) + } + if awschaos.Spec.SecretName != nil { + secret := &v1.Secret{} + err := impl.Client.Get(ctx, types.NamespacedName{ + Name: *awschaos.Spec.SecretName, + Namespace: awschaos.Namespace, + }, secret) + if err != nil { + impl.Log.Error(err, "fail to get cloud secret") + return v1alpha1.Injected, err + } + opts = append(opts, awscfg.WithCredentialsProvider(credentials.NewStaticCredentialsProvider( + string(secret.Data["aws_access_key_id"]), + string(secret.Data["aws_secret_access_key"]), + string(secret.Data["aws_session_token"]), + ))) + } + cfg, err := awscfg.LoadDefaultConfig(ctx, opts...) + if err != nil { + impl.Log.Error(err, "unable to load aws SDK config") + return v1alpha1.Injected, err + } + ec2client := ec2.NewFromConfig(cfg) + + _, err = ec2client.StartInstances(context.TODO(), &ec2.StartInstancesInput{ + InstanceIds: []string{selected.Ec2Instance}, + }) + + if err != nil { + impl.Log.Error(err, "fail to start the instance") + return v1alpha1.Injected, err + } + + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client, log logr.Logger) *Impl { + return &Impl{ + Client: c, + Log: log.WithName("ec2stop"), + } +} diff --git a/controllers/chaosimpl/awschaos/impl.go b/controllers/chaosimpl/awschaos/impl.go new file mode 100644 index 0000000000..0d524c952e --- /dev/null +++ b/controllers/chaosimpl/awschaos/impl.go @@ -0,0 +1,53 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package awschaos + +import ( + "go.uber.org/fx" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/action" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/awschaos/detachvolume" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/awschaos/ec2restart" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/awschaos/ec2stop" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +type Impl struct { + fx.In + + DetachVolume *detachvolume.Impl `action:"detach-volume"` + Ec2Restart *ec2restart.Impl `action:"ec2-restart"` + Ec2Stop *ec2stop.Impl `action:"ec2-stop"` +} + +func NewImpl(impl Impl) *types.ChaosImplPair { + delegate := action.NewMultiplexer(&impl) + return &types.ChaosImplPair{ + Name: "awschaos", + Object: &v1alpha1.AWSChaos{}, + Impl: &delegate, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, + detachvolume.NewImpl, + ec2restart.NewImpl, + ec2stop.NewImpl) diff --git a/controllers/chaosimpl/azurechaos/diskdetach/impl.go b/controllers/chaosimpl/azurechaos/diskdetach/impl.go new file mode 100644 index 0000000000..de5cda150d --- /dev/null +++ b/controllers/chaosimpl/azurechaos/diskdetach/impl.go @@ -0,0 +1,150 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package diskdetach + +import ( + "context" + "encoding/json" + "errors" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + "github.com/Azure/go-autorest/autorest/to" + "github.com/go-logr/logr" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/azurechaos/utils" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + + Log logr.Logger +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, chaos v1alpha1.InnerObject) (v1alpha1.Phase, error) { + azurechaos, ok := chaos.(*v1alpha1.AzureChaos) + if !ok { + err := errors.New("chaos is not azurechaos") + impl.Log.Error(err, "chaos is not azureChaos", "chaos", chaos) + return v1alpha1.NotInjected, err + } + vmClient, err := utils.GetVMClient(ctx, impl.Client, azurechaos) + if err != nil { + impl.Log.Error(err, "fail to get the vm client") + return v1alpha1.NotInjected, err + } + + var selected v1alpha1.AzureSelector + err = json.Unmarshal([]byte(records[index].Id), &selected) + if err != nil { + impl.Log.Error(err, "fail to unmarshal the selector") + return v1alpha1.NotInjected, err + } + + vm, err := vmClient.Get(ctx, azurechaos.Spec.ResourceGroupName, azurechaos.Spec.VMName, compute.InstanceView) + if err != nil { + impl.Log.Error(err, "fail to get the specified vm") + return v1alpha1.NotInjected, err + } + + diskIndex := -1 + for index, disk := range *vm.StorageProfile.DataDisks { + if *disk.Lun == int32(*azurechaos.Spec.LUN) && *disk.Name == *azurechaos.Spec.DiskName { + diskIndex = index + break + } + } + if diskIndex == -1 { + impl.Log.Error(err, "fail to get the disk, please check the LUN and diskName") + return v1alpha1.NotInjected, err + } + + newDiskList := append((*vm.StorageProfile.DataDisks)[:diskIndex], (*vm.StorageProfile.DataDisks)[diskIndex+1:]...) + vm.StorageProfile.DataDisks = &newDiskList + + _, err = vmClient.CreateOrUpdate(ctx, azurechaos.Spec.ResourceGroupName, azurechaos.Spec.VMName, vm) + if err != nil { + impl.Log.Error(err, "fail to detach the disk from the vm") + return v1alpha1.NotInjected, err + } + return v1alpha1.Injected, nil +} +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, chaos v1alpha1.InnerObject) (v1alpha1.Phase, error) { + azurechaos, ok := chaos.(*v1alpha1.AzureChaos) + if !ok { + err := errors.New("chaos is not azurechaos") + impl.Log.Error(err, "chaos is not AzureChaos", "chaos", chaos) + return v1alpha1.Injected, err + } + + vmClient, err := utils.GetVMClient(ctx, impl.Client, azurechaos) + if err != nil { + impl.Log.Error(err, "fail to get the vm client") + return v1alpha1.Injected, err + } + disksClient, err := utils.GetDiskClient(ctx, impl.Client, azurechaos) + if err != nil { + impl.Log.Error(err, "fail to get the disk client") + return v1alpha1.Injected, err + } + + disk, err := disksClient.Get(ctx, azurechaos.Spec.ResourceGroupName, *azurechaos.Spec.DiskName) + if err != nil { + impl.Log.Error(err, "fail to get the disk detail") + return v1alpha1.Injected, err + } + vm, err := vmClient.Get(ctx, azurechaos.Spec.ResourceGroupName, azurechaos.Spec.VMName, compute.InstanceView) + if err != nil { + impl.Log.Error(err, "fail to get the specified vm") + return v1alpha1.Injected, err + } + + newDiskList := *vm.StorageProfile.DataDisks + newDiskList = append(newDiskList, compute.DataDisk{ + Lun: to.Int32Ptr(int32(*azurechaos.Spec.LUN)), + Name: azurechaos.Spec.DiskName, + CreateOption: compute.DiskCreateOptionTypesAttach, + ManagedDisk: &compute.ManagedDiskParameters{ + ID: disk.ID, + }, + }) + vm.StorageProfile.DataDisks = &newDiskList + + var selected v1alpha1.AzureSelector + err = json.Unmarshal([]byte(records[index].Id), &selected) + if err != nil { + impl.Log.Error(err, "fail to unmarshal the selector") + return v1alpha1.NotInjected, err + } + + _, err = vmClient.CreateOrUpdate(ctx, azurechaos.Spec.ResourceGroupName, azurechaos.Spec.VMName, vm) + if err != nil { + impl.Log.Error(err, "fail to attach the disk") + return v1alpha1.Injected, err + } + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client, log logr.Logger) *Impl { + return &Impl{ + Client: c, + Log: log.WithName("diskdetach"), + } +} diff --git a/controllers/chaosimpl/azurechaos/impl.go b/controllers/chaosimpl/azurechaos/impl.go new file mode 100644 index 0000000000..c3f111b0f2 --- /dev/null +++ b/controllers/chaosimpl/azurechaos/impl.go @@ -0,0 +1,53 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package azurechaos + +import ( + "go.uber.org/fx" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/action" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/azurechaos/diskdetach" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/azurechaos/vmrestart" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/azurechaos/vmstop" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +type Impl struct { + fx.In + + VmRestart *vmrestart.Impl `action:"vm-restart"` + VmStop *vmstop.Impl `action:"vm-stop"` + DiskDetach *diskdetach.Impl `action:"disk-detach"` +} + +func NewImpl(impl Impl) *types.ChaosImplPair { + delegate := action.NewMultiplexer(&impl) + return &types.ChaosImplPair{ + Name: "azurechaos", + Object: &v1alpha1.AzureChaos{}, + Impl: &delegate, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, + vmstop.NewImpl, + vmrestart.NewImpl, + diskdetach.NewImpl) diff --git a/controllers/chaosimpl/azurechaos/utils/utils.go b/controllers/chaosimpl/azurechaos/utils/utils.go new file mode 100644 index 0000000000..5757f59644 --- /dev/null +++ b/controllers/chaosimpl/azurechaos/utils/utils.go @@ -0,0 +1,78 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package utils + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure/auth" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +// GetVMClient is used to get the azure VM Client +func GetVMClient(ctx context.Context, cli client.Client, azurechaos *v1alpha1.AzureChaos) (*compute.VirtualMachinesClient, error) { + authorizer, err := GetAuthorizer(ctx, cli, azurechaos) + if err != nil { + return nil, err + } + + vmClient := compute.NewVirtualMachinesClient(azurechaos.Spec.SubscriptionID) + vmClient.Authorizer = authorizer + + return &vmClient, nil +} + +// GetDiskClient is used to get the azure disk Client +func GetDiskClient(ctx context.Context, cli client.Client, azurechaos *v1alpha1.AzureChaos) (*compute.DisksClient, error) { + authorizer, err := GetAuthorizer(ctx, cli, azurechaos) + if err != nil { + return nil, err + } + disksClient := compute.NewDisksClient(azurechaos.Spec.SubscriptionID) + disksClient.Authorizer = authorizer + + return &disksClient, nil +} + +// GetAuthorizer is used to get the azure authorizer +func GetAuthorizer(ctx context.Context, cli client.Client, azurechaos *v1alpha1.AzureChaos) (autorest.Authorizer, error) { + secret := &v1.Secret{} + err := cli.Get(ctx, types.NamespacedName{ + Name: *azurechaos.Spec.SecretName, + Namespace: azurechaos.Namespace, + }, secret) + if err != nil { + return nil, err + } + + clientCredentialConfig := auth.NewClientCredentialsConfig( + string(secret.Data["client_id"]), + string(secret.Data["client_secret"]), + string(secret.Data["tenant_id"])) + + authorizer, err := clientCredentialConfig.Authorizer() + if err != nil { + return nil, err + } + + return authorizer, nil +} diff --git a/controllers/chaosimpl/azurechaos/vmrestart/impl.go b/controllers/chaosimpl/azurechaos/vmrestart/impl.go new file mode 100644 index 0000000000..041a0002d5 --- /dev/null +++ b/controllers/chaosimpl/azurechaos/vmrestart/impl.go @@ -0,0 +1,77 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package vmrestart + +import ( + "context" + "encoding/json" + "errors" + + "github.com/go-logr/logr" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/azurechaos/utils" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + + Log logr.Logger +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, chaos v1alpha1.InnerObject) (v1alpha1.Phase, error) { + azurechaos, ok := chaos.(*v1alpha1.AzureChaos) + if !ok { + err := errors.New("chaos is not azurechaos") + impl.Log.Error(err, "chaos is not azureChaos", "chaos", chaos) + return v1alpha1.NotInjected, err + } + + vmClient, err := utils.GetVMClient(ctx, impl.Client, azurechaos) + if err != nil { + impl.Log.Error(err, "fail to get the vm client") + return v1alpha1.NotInjected, err + } + + var selected v1alpha1.AzureSelector + err = json.Unmarshal([]byte(records[index].Id), &selected) + if err != nil { + impl.Log.Error(err, "fail to unmarshal the selector") + return v1alpha1.NotInjected, err + } + + _, err = vmClient.Restart(ctx, selected.ResourceGroupName, selected.VMName) + if err != nil { + impl.Log.Error(err, "fail to power off the vm") + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, chaos v1alpha1.InnerObject) (v1alpha1.Phase, error) { + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client, log logr.Logger) *Impl { + return &Impl{ + Client: c, + Log: log.WithName("vmrestart"), + } +} diff --git a/controllers/chaosimpl/azurechaos/vmstop/impl.go b/controllers/chaosimpl/azurechaos/vmstop/impl.go new file mode 100644 index 0000000000..1f31bcd1c3 --- /dev/null +++ b/controllers/chaosimpl/azurechaos/vmstop/impl.go @@ -0,0 +1,101 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package vmstop + +import ( + "context" + "encoding/json" + "errors" + + "github.com/go-logr/logr" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/azurechaos/utils" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + + Log logr.Logger +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, chaos v1alpha1.InnerObject) (v1alpha1.Phase, error) { + azurechaos, ok := chaos.(*v1alpha1.AzureChaos) + if !ok { + err := errors.New("chaos is not azurechaos") + impl.Log.Error(err, "chaos is not azureChaos", "chaos", chaos) + return v1alpha1.NotInjected, err + } + + vmClient, err := utils.GetVMClient(ctx, impl.Client, azurechaos) + if err != nil { + impl.Log.Error(err, "fail to get the vm client") + return v1alpha1.NotInjected, err + } + + var selected v1alpha1.AzureSelector + err = json.Unmarshal([]byte(records[index].Id), &selected) + if err != nil { + impl.Log.Error(err, "selector unmarshal error") + return v1alpha1.NotInjected, err + } + + _, err = vmClient.PowerOff(ctx, selected.ResourceGroupName, selected.VMName, nil) + if err != nil { + impl.Log.Error(err, "fail to power off the vm") + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, chaos v1alpha1.InnerObject) (v1alpha1.Phase, error) { + azurechaos, ok := chaos.(*v1alpha1.AzureChaos) + if !ok { + err := errors.New("chaos is not azurechaos") + impl.Log.Error(err, "chaos is not AzureChaos", "chaos", chaos) + return v1alpha1.Injected, err + } + vmClient, err := utils.GetVMClient(ctx, impl.Client, azurechaos) + if err != nil { + impl.Log.Error(err, "fail to get the vm client") + return v1alpha1.Injected, err + } + + var selected v1alpha1.AzureSelector + err = json.Unmarshal([]byte(records[index].Id), &selected) + if err != nil { + impl.Log.Error(err, "fail to unmarshal the selector") + return v1alpha1.NotInjected, err + } + + _, err = vmClient.Start(ctx, selected.ResourceGroupName, selected.VMName) + if err != nil { + impl.Log.Error(err, "fail to start the vm") + return v1alpha1.Injected, err + } + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client, log logr.Logger) *Impl { + return &Impl{ + Client: c, + Log: log.WithName("vmstop"), + } +} diff --git a/controllers/chaosimpl/blockchaos/impl.go b/controllers/chaosimpl/blockchaos/impl.go new file mode 100644 index 0000000000..b6c385d807 --- /dev/null +++ b/controllers/chaosimpl/blockchaos/impl.go @@ -0,0 +1,166 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package blockchaos + +import ( + "context" + "strconv" + "time" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "go.uber.org/fx" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" + pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + Log logr.Logger + + decoder *utils.ContainerRecordDecoder +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + impl.Log.Info("blockchaos apply", "record", records[index]) + + _, _, volumePath, err := controller.ParseNamespacedNameContainerVolumePath(records[index].Id) + if err != nil { + return v1alpha1.NotInjected, errors.Wrapf(err, "parse container and volumePath %s", records[index].Id) + } + + decodedContainer, err := impl.decoder.DecodeContainerRecord(ctx, records[index], obj) + pbClient := decodedContainer.PbClient + containerId := decodedContainer.ContainerId + if pbClient != nil { + defer pbClient.Close() + } + if err != nil { + return v1alpha1.NotInjected, err + } + + blockchaos := obj.(*v1alpha1.BlockChaos) + if blockchaos.Status.InjectionIds == nil { + blockchaos.Status.InjectionIds = make(map[string]int) + } + _, ok := blockchaos.Status.InjectionIds[records[index].Id] + if ok { + impl.Log.Info("the blockchaos has already been injected") + return v1alpha1.Injected, nil + } + + var res *pb.ApplyBlockChaosResponse + if blockchaos.Spec.Action == v1alpha1.BlockDelay { + delay, err := time.ParseDuration(blockchaos.Spec.Delay.Latency) + if err != nil { + return v1alpha1.NotInjected, errors.Wrapf(err, "parse latency: %s", blockchaos.Spec.Delay.Latency) + } + + corr, err := strconv.ParseFloat(blockchaos.Spec.Delay.Correlation, 64) + if err != nil { + return v1alpha1.NotInjected, errors.Wrapf(err, "parse corr: %s", blockchaos.Spec.Delay.Correlation) + } + + jitter, err := time.ParseDuration(blockchaos.Spec.Delay.Jitter) + if err != nil { + return v1alpha1.NotInjected, errors.Wrapf(err, "parse jitter: %s", blockchaos.Spec.Delay.Jitter) + } + + res, err = pbClient.ApplyBlockChaos(ctx, &pb.ApplyBlockChaosRequest{ + ContainerId: containerId, + VolumePath: volumePath, + Action: pb.ApplyBlockChaosRequest_Delay, + Delay: &pb.BlockDelaySpec{ + Delay: delay.Nanoseconds(), + Correlation: corr, + Jitter: jitter.Nanoseconds(), + }, + EnterNS: true, + }) + + if err != nil { + return v1alpha1.NotInjected, err + } + } else { + return v1alpha1.NotInjected, utils.ErrUnknownAction + } + + blockchaos.Status.InjectionIds[records[index].Id] = int(res.InjectionId) + + return v1alpha1.Injected, nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + impl.Log.Info("blockchaos recover", "record", records[index]) + + decodedContainer, err := impl.decoder.DecodeContainerRecord(ctx, records[index], obj) + pbClient := decodedContainer.PbClient + if pbClient != nil { + defer pbClient.Close() + } + if err != nil { + if errors.Is(err, utils.ErrContainerNotFound) { + // pretend the disappeared container has been recovered + return v1alpha1.NotInjected, nil + } + return v1alpha1.Injected, err + } + + blockchaos := obj.(*v1alpha1.BlockChaos) + if blockchaos.Status.InjectionIds == nil { + blockchaos.Status.InjectionIds = make(map[string]int) + } + injection_id, ok := blockchaos.Status.InjectionIds[records[index].Id] + if !ok { + impl.Log.Info("the blockchaos has already been recovered") + return v1alpha1.NotInjected, nil + } + + if _, err = pbClient.RecoverBlockChaos(ctx, &pb.RecoverBlockChaosRequest{ + InjectionId: int32(injection_id), + }); err != nil { + // TODO: check whether the error still exists + return v1alpha1.Injected, err + } + delete(blockchaos.Status.InjectionIds, records[index].Id) + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client, log logr.Logger, decoder *utils.ContainerRecordDecoder) *impltypes.ChaosImplPair { + return &impltypes.ChaosImplPair{ + Name: "blockchaos", + Object: &v1alpha1.BlockChaos{}, + Impl: &Impl{ + Client: c, + Log: log.WithName("blockchaos"), + decoder: decoder, + }, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, +) diff --git a/controllers/chaosimpl/dnschaos/types.go b/controllers/chaosimpl/dnschaos/types.go new file mode 100644 index 0000000000..0ad4a03337 --- /dev/null +++ b/controllers/chaosimpl/dnschaos/types.go @@ -0,0 +1,254 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package dnschaos + +import ( + "context" + "fmt" + "net" + "time" + + dnspb "github.com/chaos-mesh/k8s_dns_chaos/pb" + "github.com/go-logr/logr" + "github.com/pkg/errors" + "go.uber.org/fx" + "google.golang.org/grpc" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + Log logr.Logger + + decoder *utils.ContainerRecordDecoder +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + decodedContainer, err := impl.decoder.DecodeContainerRecord(ctx, records[index], obj) + if decodedContainer.PbClient != nil { + defer decodedContainer.PbClient.Close() + } + if err != nil { + return v1alpha1.NotInjected, err + } + + service, err := impl.getService(ctx, config.ControllerCfg.Namespace, config.ControllerCfg.DNSServiceName) + if err != nil { + impl.Log.Error(err, "fail to get dns service") + return v1alpha1.NotInjected, err + } + + dnsPods, err := impl.getPodsFromSelector(ctx, config.ControllerCfg.Namespace, service.Spec.Selector) + if err != nil { + impl.Log.Error(err, "fail to get pods from selector") + return v1alpha1.NotInjected, err + } + + dnschaos := obj.(*v1alpha1.DNSChaos) + for _, pod := range dnsPods { + err = impl.setDNSServerRules(pod.Status.PodIP, config.ControllerCfg.DNSServicePort, dnschaos.Name, decodedContainer.Pod, dnschaos.Spec.Action, dnschaos.Spec.DomainNamePatterns) + if err != nil { + impl.Log.Error(err, "fail to set DNS server rules") + return v1alpha1.NotInjected, err + } + impl.Log.Info("Apply DNS chaos to DNS pod", "ip", service.Spec.ClusterIP) + } + + _, err = decodedContainer.PbClient.SetDNSServer(ctx, &pb.SetDNSServerRequest{ + ContainerId: decodedContainer.ContainerId, + DnsServer: service.Spec.ClusterIP, + Enable: true, + EnterNS: true, + }) + if err != nil { + impl.Log.Error(err, "set dns server") + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} + +func (impl *Impl) setDNSServerRules(dnsServerIP string, port int, name string, pod *v1.Pod, action v1alpha1.DNSChaosAction, patterns []string) error { + impl.Log.Info("setDNSServerRules", "name", name) + + pbPods := make([]*dnspb.Pod, 1) + pbPods[0] = &dnspb.Pod{ + Name: pod.Name, + Namespace: pod.Namespace, + } + + conn, err := grpc.Dial(net.JoinHostPort(dnsServerIP, fmt.Sprintf("%d", port)), grpc.WithInsecure()) + if err != nil { + return err + } + defer conn.Close() + + c := dnspb.NewDNSClient(conn) + request := &dnspb.SetDNSChaosRequest{ + Name: name, + Action: string(action), + Pods: pbPods, + Patterns: patterns, + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + response, err := c.SetDNSChaos(ctx, request) + if err != nil { + return err + } + + if !response.Result { + return errors.Errorf("set dns chaos to dns server error: %s", response.Msg) + } + + return nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + decodedContainer, err := impl.decoder.DecodeContainerRecord(ctx, records[index], obj) + if decodedContainer.PbClient != nil { + defer decodedContainer.PbClient.Close() + } + if err != nil { + if errors.Is(err, utils.ErrContainerNotFound) { + // pretend the disappeared container has been recovered + return v1alpha1.NotInjected, nil + } + return v1alpha1.Injected, err + } + + dnschaos := obj.(*v1alpha1.DNSChaos) + + // get dns server's ip used for chaos + service, err := impl.getService(ctx, config.ControllerCfg.Namespace, config.ControllerCfg.DNSServiceName) + if err != nil { + impl.Log.Error(err, "fail to get dns service") + return v1alpha1.Injected, err + } + + dnsPods, err := impl.getPodsFromSelector(ctx, config.ControllerCfg.Namespace, service.Spec.Selector) + if err != nil { + impl.Log.Error(err, "fail to get pods from selector") + return v1alpha1.NotInjected, err + } + + for _, pod := range dnsPods { + err = impl.cancelDNSServerRules(pod.Status.PodIP, config.ControllerCfg.DNSServicePort, dnschaos.Name) + if err != nil { + impl.Log.Error(err, "fail to cancelDNSServerRules") + return v1alpha1.Injected, err + } + impl.Log.Info("Cancel DNS chaos to DNS pod", "ip", service.Spec.ClusterIP) + } + + _, err = decodedContainer.PbClient.SetDNSServer(ctx, &pb.SetDNSServerRequest{ + ContainerId: decodedContainer.ContainerId, + Enable: false, + EnterNS: true, + }) + if err != nil { + impl.Log.Error(err, "recover pod for DNS chaos") + return v1alpha1.Injected, err + } + + return v1alpha1.NotInjected, err +} + +func (impl *Impl) cancelDNSServerRules(dnsServerIP string, port int, name string) error { + conn, err := grpc.Dial(net.JoinHostPort(dnsServerIP, fmt.Sprintf("%d", port)), grpc.WithInsecure()) + if err != nil { + return err + } + defer conn.Close() + + c := dnspb.NewDNSClient(conn) + request := &dnspb.CancelDNSChaosRequest{ + Name: name, + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + response, err := c.CancelDNSChaos(ctx, request) + if err != nil { + return err + } + + if !response.Result { + return errors.Errorf("set dns chaos to dns server error %s", response.Msg) + } + + return nil +} + +// getService get k8s service by service name +func (impl *Impl) getService(ctx context.Context, namespace string, serviceName string) (*v1.Service, error) { + service := &v1.Service{} + err := impl.Client.Get(ctx, client.ObjectKey{ + Namespace: namespace, + Name: serviceName, + }, service) + if err != nil { + return nil, err + } + + return service, nil +} + +// getPodsFromSelector returns the pods assiocated to a given service +func (impl *Impl) getPodsFromSelector(ctx context.Context, namespace string, labelSelector map[string]string) ([]v1.Pod, error) { + lSelector := labels.SelectorFromSet(labelSelector) + listOptions := &client.ListOptions{ + Namespace: namespace, + LabelSelector: lSelector, + } + podsList := &v1.PodList{} + err := impl.Client.List(ctx, podsList, listOptions) + if err != nil { + return nil, err + } + + return podsList.Items, nil +} + +func NewImpl(c client.Client, log logr.Logger, decoder *utils.ContainerRecordDecoder) *impltypes.ChaosImplPair { + return &impltypes.ChaosImplPair{ + Name: "dnschaos", + Object: &v1alpha1.DNSChaos{}, + Impl: &Impl{ + Client: c, + Log: log.WithName("dnschaos"), + decoder: decoder, + }, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, +) diff --git a/controllers/chaosimpl/fx.go b/controllers/chaosimpl/fx.go new file mode 100644 index 0000000000..1f0156cbb0 --- /dev/null +++ b/controllers/chaosimpl/fx.go @@ -0,0 +1,54 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package chaosimpl + +import ( + "go.uber.org/fx" + + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/awschaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/azurechaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/blockchaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/dnschaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/gcpchaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/httpchaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/iochaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/jvmchaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/kernelchaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/networkchaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/physicalmachinechaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/podchaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/stresschaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/timechaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" +) + +var AllImpl = fx.Options( + awschaos.Module, + azurechaos.Module, + dnschaos.Module, + httpchaos.Module, + iochaos.Module, + kernelchaos.Module, + networkchaos.Module, + podchaos.Module, + gcpchaos.Module, + stresschaos.Module, + jvmchaos.Module, + timechaos.Module, + physicalmachinechaos.Module, + blockchaos.Module, + + utils.Module) diff --git a/controllers/chaosimpl/gcpchaos/diskloss/impl.go b/controllers/chaosimpl/gcpchaos/diskloss/impl.go new file mode 100644 index 0000000000..375e5ca316 --- /dev/null +++ b/controllers/chaosimpl/gcpchaos/diskloss/impl.go @@ -0,0 +1,149 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package diskloss + +import ( + "context" + "encoding/json" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + compute "google.golang.org/api/compute/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/gcpchaos/utils" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + + Log logr.Logger +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, chaos v1alpha1.InnerObject) (v1alpha1.Phase, error) { + gcpchaos, ok := chaos.(*v1alpha1.GCPChaos) + if !ok { + err := errors.New("chaos is not gcpchaos") + impl.Log.Error(err, "chaos is not GCPChaos", "chaos", chaos) + return v1alpha1.NotInjected, err + } + computeService, err := utils.GetComputeService(ctx, impl.Client, gcpchaos) + if err != nil { + impl.Log.Error(err, "fail to get the compute service") + return v1alpha1.NotInjected, err + } + + var selected v1alpha1.GCPSelector + err = json.Unmarshal([]byte(records[index].Id), &selected) + if err != nil { + impl.Log.Error(err, "fail to unmarshal the selector") + return v1alpha1.NotInjected, err + } + + instance, err := computeService.Instances.Get(selected.Project, selected.Zone, selected.Instance).Do() + if err != nil { + impl.Log.Error(err, "fail to get the instance") + return v1alpha1.NotInjected, err + } + var ( + bytes []byte + notFound []string + marshalErr []string + ) + for _, specDeviceName := range selected.DeviceNames { + haveDisk := false + for _, disk := range instance.Disks { + if disk.DeviceName == specDeviceName { + haveDisk = true + bytes, err = json.Marshal(disk) + if err != nil { + marshalErr = append(marshalErr, err.Error()) + } + gcpchaos.Status.AttachedDisksStrings = append(gcpchaos.Status.AttachedDisksStrings, string(bytes)) + break + } + } + if !haveDisk { + notFound = append(notFound, specDeviceName) + } + } + if len(notFound) != 0 { + err = errors.Errorf("instance (%s) does not have the disk (%s)", selected.Instance, notFound) + impl.Log.Error(err, "the instance does not have the disk") + return v1alpha1.NotInjected, err + } + if len(marshalErr) != 0 { + err = errors.Errorf("instance (%s), marshal disk info error (%s)", selected.Instance, marshalErr) + impl.Log.Error(err, "marshal disk info error") + return v1alpha1.NotInjected, err + } + + for _, specDeviceName := range selected.DeviceNames { + _, err = computeService.Instances.DetachDisk(selected.Project, selected.Zone, selected.Instance, specDeviceName).Do() + if err != nil { + impl.Log.Error(err, "fail to detach the disk") + return v1alpha1.NotInjected, err + } + } + + return v1alpha1.Injected, nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, chaos v1alpha1.InnerObject) (v1alpha1.Phase, error) { + gcpchaos, ok := chaos.(*v1alpha1.GCPChaos) + if !ok { + err := errors.New("chaos is not gcpchaos") + impl.Log.Error(err, "chaos is not GCPChaos", "chaos", chaos) + return v1alpha1.Injected, err + } + computeService, err := utils.GetComputeService(ctx, impl.Client, gcpchaos) + if err != nil { + impl.Log.Error(err, "fail to get the compute service") + return v1alpha1.Injected, err + } + var disk compute.AttachedDisk + var selected v1alpha1.GCPSelector + err = json.Unmarshal([]byte(records[index].Id), &selected) + if err != nil { + impl.Log.Error(err, "fail to unmarshal the selector") + return v1alpha1.NotInjected, err + } + + for _, attachedDiskString := range gcpchaos.Status.AttachedDisksStrings { + err = json.Unmarshal([]byte(attachedDiskString), &disk) + if err != nil { + impl.Log.Error(err, "fail to unmarshal the disk info") + return v1alpha1.Injected, err + } + _, err = computeService.Instances.AttachDisk(selected.Project, selected.Zone, selected.Instance, &disk).Do() + if err != nil { + impl.Log.Error(err, "fail to attach the disk to the instance") + return v1alpha1.Injected, err + } + } + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client, log logr.Logger) *Impl { + return &Impl{ + Client: c, + Log: log.WithName("diskloss"), + } +} diff --git a/controllers/chaosimpl/gcpchaos/impl.go b/controllers/chaosimpl/gcpchaos/impl.go new file mode 100644 index 0000000000..d0e217d984 --- /dev/null +++ b/controllers/chaosimpl/gcpchaos/impl.go @@ -0,0 +1,53 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gcpchaos + +import ( + "go.uber.org/fx" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/action" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/gcpchaos/diskloss" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/gcpchaos/nodereset" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/gcpchaos/nodestop" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +type Impl struct { + fx.In + + DiskLoss *diskloss.Impl `action:"disk-loss"` + NodeReset *nodereset.Impl `action:"node-reset"` + NodeStop *nodestop.Impl `action:"node-stop"` +} + +func NewImpl(impl Impl) *impltypes.ChaosImplPair { + delegate := action.NewMultiplexer(&impl) + return &impltypes.ChaosImplPair{ + Name: "gcpchaos", + Object: &v1alpha1.GCPChaos{}, + Impl: &delegate, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, + diskloss.NewImpl, + nodereset.NewImpl, + nodestop.NewImpl) diff --git a/controllers/chaosimpl/gcpchaos/nodereset/impl.go b/controllers/chaosimpl/gcpchaos/nodereset/impl.go new file mode 100644 index 0000000000..1e43c4f3e6 --- /dev/null +++ b/controllers/chaosimpl/gcpchaos/nodereset/impl.go @@ -0,0 +1,77 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package nodereset + +import ( + "context" + "encoding/json" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/gcpchaos/utils" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + + Log logr.Logger +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, chaos v1alpha1.InnerObject) (v1alpha1.Phase, error) { + gcpchaos, ok := chaos.(*v1alpha1.GCPChaos) + if !ok { + err := errors.New("chaos is not gcpchaos") + impl.Log.Error(err, "chaos is not GCPChaos", "chaos", chaos) + return v1alpha1.NotInjected, err + } + computeService, err := utils.GetComputeService(ctx, impl.Client, gcpchaos) + if err != nil { + impl.Log.Error(err, "fail to get the compute service") + return v1alpha1.NotInjected, err + } + + var selected v1alpha1.GCPSelector + err = json.Unmarshal([]byte(records[index].Id), &selected) + if err != nil { + impl.Log.Error(err, "fail to unmarshal the selector") + return v1alpha1.NotInjected, err + } + + _, err = computeService.Instances.Reset(selected.Project, selected.Zone, selected.Instance).Do() + if err != nil { + impl.Log.Error(err, "fail to reset the instance") + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, chaos v1alpha1.InnerObject) (v1alpha1.Phase, error) { + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client, log logr.Logger) *Impl { + return &Impl{ + Client: c, + Log: log.WithName("nodereset"), + } +} diff --git a/controllers/chaosimpl/gcpchaos/nodestop/impl.go b/controllers/chaosimpl/gcpchaos/nodestop/impl.go new file mode 100644 index 0000000000..9a54678b3b --- /dev/null +++ b/controllers/chaosimpl/gcpchaos/nodestop/impl.go @@ -0,0 +1,95 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package nodestop + +import ( + "context" + "encoding/json" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/gcpchaos/utils" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + + Log logr.Logger +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, chaos v1alpha1.InnerObject) (v1alpha1.Phase, error) { + gcpchaos, ok := chaos.(*v1alpha1.GCPChaos) + if !ok { + err := errors.New("chaos is not gcpchaos") + impl.Log.Error(err, "chaos is not GCPChaos", "chaos", chaos) + return v1alpha1.NotInjected, err + } + computeService, err := utils.GetComputeService(ctx, impl.Client, gcpchaos) + if err != nil { + impl.Log.Error(err, "fail to get the compute service") + return v1alpha1.NotInjected, err + } + + var selected v1alpha1.GCPSelector + err = json.Unmarshal([]byte(records[index].Id), &selected) + if err != nil { + impl.Log.Error(err, "fail to unmarshal the selector") + return v1alpha1.NotInjected, err + } + + _, err = computeService.Instances.Stop(selected.Project, selected.Zone, selected.Instance).Do() + if err != nil { + impl.Log.Error(err, "fail to stop the instance") + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, chaos v1alpha1.InnerObject) (v1alpha1.Phase, error) { + gcpchaos, ok := chaos.(*v1alpha1.GCPChaos) + if !ok { + err := errors.New("chaos is not gcpchaos") + impl.Log.Error(err, "chaos is not GCPChaos", "chaos", chaos) + return v1alpha1.Injected, err + } + computeService, err := utils.GetComputeService(ctx, impl.Client, gcpchaos) + if err != nil { + impl.Log.Error(err, "fail to get the compute service") + return v1alpha1.Injected, err + } + var selected v1alpha1.GCPSelector + json.Unmarshal([]byte(records[index].Id), &selected) + _, err = computeService.Instances.Start(selected.Project, selected.Zone, selected.Instance).Do() + if err != nil { + impl.Log.Error(err, "fail to start the instance") + return v1alpha1.Injected, err + } + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client, log logr.Logger) *Impl { + return &Impl{ + Client: c, + Log: log.WithName("nodestop"), + } +} diff --git a/controllers/chaosimpl/gcpchaos/utils/utils.go b/controllers/chaosimpl/gcpchaos/utils/utils.go new file mode 100644 index 0000000000..5d036f837a --- /dev/null +++ b/controllers/chaosimpl/gcpchaos/utils/utils.go @@ -0,0 +1,59 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package utils + +import ( + "context" + "encoding/base64" + + compute "google.golang.org/api/compute/v1" + "google.golang.org/api/option" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +// GetComputeService is used to get the GCP compute Service. +func GetComputeService(ctx context.Context, cli client.Client, gcpchaos *v1alpha1.GCPChaos) (*compute.Service, error) { + if gcpchaos.Spec.SecretName != nil { + secret := &v1.Secret{} + err := cli.Get(ctx, types.NamespacedName{ + Name: *gcpchaos.Spec.SecretName, + Namespace: gcpchaos.Namespace, + }, secret) + if err != nil { + return nil, err + } + + decodeBytes, err := base64.StdEncoding.DecodeString(string(secret.Data["service_account"])) + if err != nil { + return nil, err + } + computeService, err := compute.NewService(ctx, option.WithCredentialsJSON(decodeBytes)) + if err != nil { + return nil, err + } + return computeService, nil + } + + computeService, err := compute.NewService(ctx) + if err != nil { + return nil, err + } + return computeService, nil +} diff --git a/controllers/chaosimpl/httpchaos/impl.go b/controllers/chaosimpl/httpchaos/impl.go new file mode 100644 index 0000000000..9f08b219a6 --- /dev/null +++ b/controllers/chaosimpl/httpchaos/impl.go @@ -0,0 +1,236 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package httpchaos + +import ( + "context" + "strings" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "go.uber.org/fx" + v1 "k8s.io/api/core/v1" + k8sError "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/httpchaos/podhttpchaosmanager" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/iochaos/podiochaosmanager" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +const ( + waitForApplySync v1alpha1.Phase = "Not Injected/Wait" + waitForRecoverSync v1alpha1.Phase = "Injected/Wait" +) + +type Impl struct { + client.Client + Log logr.Logger + + builder *podhttpchaosmanager.Builder +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + // The only possible phase to get in here is "Not Injected" or "Not Injected/Wait" + + impl.Log.Info("httpchaos Apply", "namespace", obj.GetNamespace(), "name", obj.GetName()) + httpchaos := obj.(*v1alpha1.HTTPChaos) + if httpchaos.Status.Instances == nil { + httpchaos.Status.Instances = make(map[string]int64) + } + + record := records[index] + phase := record.Phase + + if phase == waitForApplySync { + podhttpchaos := &v1alpha1.PodHttpChaos{} + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + return waitForApplySync, err + } + err = impl.Client.Get(ctx, namespacedName, podhttpchaos) + if err != nil { + return waitForApplySync, err + } + + if podhttpchaos.Status.FailedMessage != "" { + return waitForApplySync, errors.New(podhttpchaos.Status.FailedMessage) + } + + if podhttpchaos.Status.ObservedGeneration >= httpchaos.Status.Instances[record.Id] { + return v1alpha1.Injected, nil + } + + return waitForApplySync, nil + } + + podId, err := controller.ParseNamespacedName(records[index].Id) + if err != nil { + return v1alpha1.NotInjected, err + } + var pod v1.Pod + err = impl.Client.Get(ctx, podId, &pod) + if err != nil { + return v1alpha1.NotInjected, err + } + + source := httpchaos.Namespace + "/" + httpchaos.Name + m := impl.builder.WithInit(source, types.NamespacedName{ + Namespace: pod.Namespace, + Name: pod.Name, + }) + + m.T.Append(v1alpha1.PodHttpChaosRule{ + Source: m.Source, + Port: httpchaos.Spec.Port, + PodHttpChaosBaseRule: v1alpha1.PodHttpChaosBaseRule{ + Target: httpchaos.Spec.Target, + Selector: v1alpha1.PodHttpChaosSelector{ + Port: &httpchaos.Spec.Port, + Path: httpchaos.Spec.Path, + Method: httpchaos.Spec.Method, + Code: httpchaos.Spec.Code, + RequestHeaders: httpchaos.Spec.RequestHeaders, + ResponseHeaders: httpchaos.Spec.ResponseHeaders, + }, + Actions: httpchaos.Spec.PodHttpChaosActions, + }, + }) + + if httpchaos.Spec.TLS != nil { + m.T.Append(httpchaos.Spec.TLS) + } + + generationNumber, err := m.Commit(ctx) + if err != nil { + return v1alpha1.NotInjected, err + } + + // modify the custom status + httpchaos.Status.Instances[record.Id] = generationNumber + return waitForApplySync, nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + // The only possible phase to get in here is "Injected" or "Injected/Wait" + + httpchaos := obj.(*v1alpha1.HTTPChaos) + if httpchaos.Status.Instances == nil { + httpchaos.Status.Instances = make(map[string]int64) + } + + record := records[index] + phase := record.Phase + if phase == waitForRecoverSync { + podhttpchaos := &v1alpha1.PodHttpChaos{} + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + // This error is not expected to exist + return waitForRecoverSync, err + } + err = impl.Client.Get(ctx, namespacedName, podhttpchaos) + if err != nil { + // TODO: handle this error + if k8sError.IsNotFound(err) { + return v1alpha1.NotInjected, nil + } + + if k8sError.IsForbidden(err) { + if strings.Contains(err.Error(), "because it is being terminated") { + return v1alpha1.NotInjected, nil + } + } + + return waitForRecoverSync, err + } + + if podhttpchaos.Status.FailedMessage != "" { + return waitForRecoverSync, errors.New(podhttpchaos.Status.FailedMessage) + } + + if podhttpchaos.Status.ObservedGeneration >= httpchaos.Status.Instances[record.Id] { + return v1alpha1.NotInjected, nil + } + + return waitForRecoverSync, nil + } + + podId, err := controller.ParseNamespacedName(records[index].Id) + if err != nil { + // This error is not expected to exist + return v1alpha1.NotInjected, err + } + var pod v1.Pod + err = impl.Client.Get(ctx, podId, &pod) + if err != nil { + // TODO: handle this error + if k8sError.IsNotFound(err) { + return v1alpha1.NotInjected, nil + } + return v1alpha1.Injected, err + } + + source := httpchaos.Namespace + "/" + httpchaos.Name + m := impl.builder.WithInit(source, types.NamespacedName{ + Namespace: pod.Namespace, + Name: pod.Name, + }) + + generationNumber, err := m.Commit(ctx) + if err != nil { + if err == podiochaosmanager.ErrPodNotFound || err == podiochaosmanager.ErrPodNotRunning { + return v1alpha1.NotInjected, nil + } + + if k8sError.IsForbidden(err) { + if strings.Contains(err.Error(), "because it is being terminated") { + return v1alpha1.NotInjected, nil + } + } + return v1alpha1.Injected, err + } + + // Now modify the custom status and phase + httpchaos.Status.Instances[record.Id] = generationNumber + return waitForRecoverSync, nil +} + +func NewImpl(c client.Client, b *podhttpchaosmanager.Builder, log logr.Logger) *impltypes.ChaosImplPair { + return &impltypes.ChaosImplPair{ + Name: "httpchaos", + Object: &v1alpha1.HTTPChaos{}, + Impl: &Impl{ + Client: c, + Log: log.WithName("httpchaos"), + builder: b, + }, + ObjectList: &v1alpha1.HTTPChaosList{}, + Controlls: []client.Object{&v1alpha1.PodHttpChaos{}}, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, + podhttpchaosmanager.NewBuilder, +) diff --git a/controllers/chaosimpl/httpchaos/podhttpchaosmanager/builder.go b/controllers/chaosimpl/httpchaos/podhttpchaosmanager/builder.go new file mode 100644 index 0000000000..bb4f9bfffd --- /dev/null +++ b/controllers/chaosimpl/httpchaos/podhttpchaosmanager/builder.go @@ -0,0 +1,65 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podhttpchaosmanager + +import ( + "github.com/go-logr/logr" + "go.uber.org/fx" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type Builder struct { + Log logr.Logger + client.Client + client.Reader + scheme *runtime.Scheme +} + +type Params struct { + fx.In + + Logger logr.Logger + Client client.Client + Reader client.Reader `name:"no-cache"` + Scheme *runtime.Scheme +} + +func NewBuilder(params Params) *Builder { + return &Builder{ + Log: params.Logger, + Client: params.Client, + Reader: params.Reader, + scheme: params.Scheme, + } +} + +func (b *Builder) WithInit(source string, key types.NamespacedName) *PodHttpManager { + t := &PodHttpTransaction{} + t.Clear(source) + + return &PodHttpManager{ + Source: source, + Log: b.Log, + Client: b.Client, + Reader: b.Reader, + scheme: b.scheme, + + Key: key, + T: t, + } +} diff --git a/controllers/chaosimpl/httpchaos/podhttpchaosmanager/manager.go b/controllers/chaosimpl/httpchaos/podhttpchaosmanager/manager.go new file mode 100644 index 0000000000..9dd579ebf1 --- /dev/null +++ b/controllers/chaosimpl/httpchaos/podhttpchaosmanager/manager.go @@ -0,0 +1,146 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podhttpchaosmanager + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + k8sError "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +var ( + // ErrPodNotFound means operate pod may be deleted(almostly) + ErrPodNotFound = errors.New("pod not found") + + // ErrPodNotRunning means operate pod may be not working + // and it's non-sense to make changes on it. + ErrPodNotRunning = errors.New("pod not running") +) + +// PodHttpManager will save all the related podhttpchaos +type PodHttpManager struct { + Source string + + Log logr.Logger + client.Client + client.Reader + scheme *runtime.Scheme + + Key types.NamespacedName + T *PodHttpTransaction +} + +// CommitResponse is a tuple (Key, Err) +type CommitResponse struct { + Key types.NamespacedName + Err error +} + +// Commit will update all modifications to the cluster +func (m *PodHttpManager) Commit(ctx context.Context) (int64, error) { + m.Log.Info("running modification on pod", "key", m.Key, "modification", m.T) + updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { + chaos := &v1alpha1.PodHttpChaos{} + + err := m.Client.Get(ctx, m.Key, chaos) + if err != nil { + if !k8sError.IsNotFound(err) { + m.Log.Error(err, "error while getting podhttpchaos") + return err + } + + err := m.CreateNewPodHttpChaos(ctx) + if err != nil { + m.Log.Error(err, "error while creating new podhttpchaos") + return err + } + + return nil + } + + err = m.T.Apply(chaos) + if err != nil { + m.Log.Error(err, "error while applying transactions", "transaction", m.T) + return err + } + + return m.Client.Update(ctx, chaos) + }) + + if updateError != nil { + return 0, updateError + } + + chaos := &v1alpha1.PodHttpChaos{} + err := m.Reader.Get(ctx, m.Key, chaos) + if err != nil { + m.Log.Error(err, "error while getting the latest generation number") + return 0, err + } + return chaos.GetGeneration(), nil +} + +func (m *PodHttpManager) CreateNewPodHttpChaos(ctx context.Context) error { + var err error + chaos := &v1alpha1.PodHttpChaos{} + + pod := v1.Pod{} + err = m.Client.Get(ctx, m.Key, &pod) + if err != nil { + if !k8sError.IsNotFound(err) { + m.Log.Error(err, "error while finding pod") + return err + } + + m.Log.Info("pod not found", "key", m.Key, "error", err.Error()) + err = ErrPodNotFound + return err + } + + if pod.Status.Phase != v1.PodRunning { + m.Log.Info("pod is not running", "key", m.Key) + err = ErrPodNotRunning + return err + } + + chaos.Name = m.Key.Name + chaos.Namespace = m.Key.Namespace + chaos.OwnerReferences = []metav1.OwnerReference{ + { + APIVersion: pod.APIVersion, + Kind: pod.Kind, + Name: pod.Name, + UID: pod.UID, + }, + } + err = m.T.Apply(chaos) + if err != nil { + m.Log.Error(err, "error while applying transactions", "transaction", m.T) + return err + } + + return m.Client.Create(ctx, chaos) +} diff --git a/controllers/chaosimpl/httpchaos/podhttpchaosmanager/transaction.go b/controllers/chaosimpl/httpchaos/podhttpchaosmanager/transaction.go new file mode 100644 index 0000000000..30f9a7c1c6 --- /dev/null +++ b/controllers/chaosimpl/httpchaos/podhttpchaosmanager/transaction.go @@ -0,0 +1,106 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podhttpchaosmanager + +import ( + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" +) + +// PodHttpTransaction represents a modification on podhttpchaos +type PodHttpTransaction struct { + Steps []Step +} + +// Step represents a step of PodHttpTransaction +type Step interface { + // Apply will apply an action on podnetworkchaos + Apply(chaos *v1alpha1.PodHttpChaos) error +} + +// Clear removes all resources with the same source +type Clear struct { + Source string +} + +// Apply runs this action +func (s *Clear) Apply(chaos *v1alpha1.PodHttpChaos) error { + rules := []v1alpha1.PodHttpChaosRule{} + for _, rule := range chaos.Spec.Rules { + if rule.Source != s.Source { + rules = append(rules, rule) + } + } + chaos.Spec.Rules = rules + return nil +} + +// Append adds an item to corresponding list in podhttpchaos +type Append struct { + Item interface{} +} + +// Apply runs this action +func (a *Append) Apply(chaos *v1alpha1.PodHttpChaos) error { + switch item := a.Item.(type) { + case v1alpha1.PodHttpChaosRule: + chaos.Spec.Rules = append(chaos.Spec.Rules, item) + case *v1alpha1.PodHttpChaosTLS: + chaos.Spec.TLS = item + default: + return errors.Wrapf(utils.ErrUnknownType, "type: %T", item) + } + + return nil +} + +// Clear will clear all related items in podhttpchaos +func (t *PodHttpTransaction) Clear(source string) { + t.Steps = append(t.Steps, &Clear{ + Source: source, + }) +} + +// Append adds an item to corresponding list in podnetworkchaos +func (t *PodHttpTransaction) Append(item interface{}) error { + switch item.(type) { + case v1alpha1.PodHttpChaosRule: + t.Steps = append(t.Steps, &Append{ + Item: item, + }) + case *v1alpha1.PodHttpChaosTLS: + t.Steps = append(t.Steps, &Append{ + Item: item, + }) + default: + return errors.Wrapf(utils.ErrUnknownType, "type: %T", item) + } + return nil +} + +// Apply runs every step on the chaos +func (t *PodHttpTransaction) Apply(chaos *v1alpha1.PodHttpChaos) error { + for _, s := range t.Steps { + err := s.Apply(chaos) + if err != nil { + return err + } + } + + return nil +} diff --git a/controllers/chaosimpl/iochaos/impl.go b/controllers/chaosimpl/iochaos/impl.go new file mode 100644 index 0000000000..7a6f819ea1 --- /dev/null +++ b/controllers/chaosimpl/iochaos/impl.go @@ -0,0 +1,238 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package iochaos + +import ( + "context" + "strings" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "go.uber.org/fx" + v1 "k8s.io/api/core/v1" + k8sError "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/iochaos/podiochaosmanager" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +const ( + waitForApplySync v1alpha1.Phase = "Not Injected/Wait" + waitForRecoverSync v1alpha1.Phase = "Injected/Wait" +) + +type Impl struct { + client.Client + Log logr.Logger + + builder *podiochaosmanager.Builder +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + // The only possible phase to get in here is "Not Injected" or "Not Injected/Wait" + + impl.Log.Info("iochaos Apply", "namespace", obj.GetNamespace(), "name", obj.GetName()) + iochaos := obj.(*v1alpha1.IOChaos) + if iochaos.Status.Instances == nil { + iochaos.Status.Instances = make(map[string]int64) + } + + record := records[index] + phase := record.Phase + + if phase == waitForApplySync { + podiochaos := &v1alpha1.PodIOChaos{} + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + return waitForApplySync, err + } + err = impl.Client.Get(ctx, namespacedName, podiochaos) + if err != nil { + if k8sError.IsNotFound(err) { + return v1alpha1.NotInjected, nil + } + + if k8sError.IsForbidden(err) { + if strings.Contains(err.Error(), "because it is being terminated") { + return v1alpha1.NotInjected, nil + } + } + + return waitForApplySync, err + } + + if podiochaos.Status.FailedMessage != "" { + return waitForApplySync, errors.New(podiochaos.Status.FailedMessage) + } + + if podiochaos.Status.ObservedGeneration >= iochaos.Status.Instances[record.Id] { + return v1alpha1.Injected, nil + } + + return waitForApplySync, nil + } + + podId, containerName, err := controller.ParseNamespacedNameContainer(records[index].Id) + if err != nil { + return v1alpha1.NotInjected, err + } + var pod v1.Pod + err = impl.Client.Get(ctx, podId, &pod) + if err != nil { + return v1alpha1.NotInjected, err + } + + source := iochaos.Namespace + "/" + iochaos.Name + m := impl.builder.WithInit(source, types.NamespacedName{ + Namespace: pod.Namespace, + Name: pod.Name, + }) + + m.T.SetVolumePath(iochaos.Spec.VolumePath) + m.T.SetContainer(containerName) + + m.T.Append(v1alpha1.IOChaosAction{ + Type: iochaos.Spec.Action, + Filter: v1alpha1.Filter{ + Path: iochaos.Spec.Path, + Percent: iochaos.Spec.Percent, + Methods: iochaos.Spec.Methods, + }, + Faults: []v1alpha1.IoFault{ + { + Errno: iochaos.Spec.Errno, + Weight: 1, + }, + }, + Latency: iochaos.Spec.Delay, + AttrOverrideSpec: iochaos.Spec.Attr, + MistakeSpec: iochaos.Spec.Mistake, + Source: m.Source, + }) + generationNumber, err := m.Commit(ctx, iochaos) + if err != nil { + return v1alpha1.NotInjected, err + } + + // modify the custom status + iochaos.Status.Instances[record.Id] = generationNumber + return waitForApplySync, nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + // The only possible phase to get in here is "Injected" or "Injected/Wait" + + iochaos := obj.(*v1alpha1.IOChaos) + if iochaos.Status.Instances == nil { + iochaos.Status.Instances = make(map[string]int64) + } + + record := records[index] + phase := record.Phase + if phase == waitForRecoverSync { + podiochaos := &v1alpha1.PodIOChaos{} + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + // This error is not expected to exist + return waitForRecoverSync, nil + } + err = impl.Client.Get(ctx, namespacedName, podiochaos) + if err != nil { + // TODO: handle this error + if k8sError.IsNotFound(err) { + return v1alpha1.NotInjected, nil + } + return waitForRecoverSync, err + } + + if podiochaos.Status.FailedMessage != "" { + return waitForRecoverSync, errors.New(podiochaos.Status.FailedMessage) + } + + if podiochaos.Status.ObservedGeneration >= iochaos.Status.Instances[record.Id] { + return v1alpha1.NotInjected, nil + } + + return waitForRecoverSync, nil + } + + podId, _, err := controller.ParseNamespacedNameContainer(records[index].Id) + if err != nil { + // This error is not expected to exist + return v1alpha1.NotInjected, err + } + var pod v1.Pod + err = impl.Client.Get(ctx, podId, &pod) + if err != nil { + // TODO: handle this error + if k8sError.IsNotFound(err) { + return v1alpha1.NotInjected, nil + } + return v1alpha1.Injected, err + } + + source := iochaos.Namespace + "/" + iochaos.Name + m := impl.builder.WithInit(source, types.NamespacedName{ + Namespace: pod.Namespace, + Name: pod.Name, + }) + + generationNumber, err := m.Commit(ctx, iochaos) + if err != nil { + if err == podiochaosmanager.ErrPodNotFound || err == podiochaosmanager.ErrPodNotRunning { + return v1alpha1.NotInjected, nil + } + + if k8sError.IsForbidden(err) { + if strings.Contains(err.Error(), "because it is being terminated") { + return v1alpha1.NotInjected, nil + } + } + return v1alpha1.Injected, err + } + + // Now modify the custom status and phase + iochaos.Status.Instances[record.Id] = generationNumber + return waitForRecoverSync, nil +} + +func NewImpl(c client.Client, b *podiochaosmanager.Builder, log logr.Logger) *impltypes.ChaosImplPair { + return &impltypes.ChaosImplPair{ + Name: "iochaos", + Object: &v1alpha1.IOChaos{}, + Impl: &Impl{ + Client: c, + Log: log.WithName("iochaos"), + builder: b, + }, + ObjectList: &v1alpha1.IOChaosList{}, + Controlls: []client.Object{&v1alpha1.PodIOChaos{}}, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, + podiochaosmanager.NewBuilder, +) diff --git a/controllers/chaosimpl/iochaos/podiochaosmanager/builder.go b/controllers/chaosimpl/iochaos/podiochaosmanager/builder.go new file mode 100644 index 0000000000..6a9575fad4 --- /dev/null +++ b/controllers/chaosimpl/iochaos/podiochaosmanager/builder.go @@ -0,0 +1,65 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podiochaosmanager + +import ( + "github.com/go-logr/logr" + "go.uber.org/fx" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type Builder struct { + Log logr.Logger + client.Client + client.Reader + scheme *runtime.Scheme +} + +type Params struct { + fx.In + + Logger logr.Logger + Client client.Client + Reader client.Reader `name:"no-cache"` + Scheme *runtime.Scheme +} + +func NewBuilder(params Params) *Builder { + return &Builder{ + Log: params.Logger, + Client: params.Client, + Reader: params.Reader, + scheme: params.Scheme, + } +} + +func (b *Builder) WithInit(source string, key types.NamespacedName) *PodIOManager { + t := &PodIOTransaction{} + t.Clear(source) + + return &PodIOManager{ + Source: source, + Log: b.Log, + Client: b.Client, + Reader: b.Reader, + scheme: b.scheme, + + Key: key, + T: t, + } +} diff --git a/controllers/chaosimpl/iochaos/podiochaosmanager/podiochaosmanager.go b/controllers/chaosimpl/iochaos/podiochaosmanager/podiochaosmanager.go new file mode 100644 index 0000000000..78231bddda --- /dev/null +++ b/controllers/chaosimpl/iochaos/podiochaosmanager/podiochaosmanager.go @@ -0,0 +1,145 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podiochaosmanager + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + k8sError "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +var ( + // ErrPodNotFound means operate pod may be deleted(almostly) + ErrPodNotFound = errors.New("pod not found") + + // ErrPodNotRunning means operate pod may be not working + // and it's non-sense to make changes on it. + ErrPodNotRunning = errors.New("pod not running") +) + +// PodIOManager will save all the related podiochaos +type PodIOManager struct { + Source string + + Log logr.Logger + client.Client + client.Reader + scheme *runtime.Scheme + + Key types.NamespacedName + T *PodIOTransaction +} + +// CommitResponse is a tuple (Key, Err) +type CommitResponse struct { + Key types.NamespacedName + Err error +} + +// Commit will update all modifications to the cluster +func (m *PodIOManager) Commit(ctx context.Context, owner *v1alpha1.IOChaos) (int64, error) { + m.Log.Info("running modification on pod", "key", m.Key, "modification", m.T) + updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { + chaos := &v1alpha1.PodIOChaos{} + + err := m.Client.Get(ctx, m.Key, chaos) + if err != nil { + if !k8sError.IsNotFound(err) { + m.Log.Error(err, "error while getting podiochaos") + return err + } + + err := m.CreateNewPodIOChaos(ctx) + if err != nil { + m.Log.Error(err, "error while creating new podiochaos") + return err + } + + return nil + } + + err = m.T.Apply(chaos) + if err != nil { + m.Log.Error(err, "error while applying transactions", "transaction", m.T) + return err + } + + return m.Client.Update(ctx, chaos) + }) + if updateError != nil { + return 0, updateError + } + + chaos := &v1alpha1.PodIOChaos{} + err := m.Reader.Get(ctx, m.Key, chaos) + if err != nil { + m.Log.Error(err, "error while getting the latest generation number") + return 0, err + } + return chaos.GetGeneration(), nil +} + +func (m *PodIOManager) CreateNewPodIOChaos(ctx context.Context) error { + var err error + chaos := &v1alpha1.PodIOChaos{} + + pod := v1.Pod{} + err = m.Client.Get(ctx, m.Key, &pod) + if err != nil { + if !k8sError.IsNotFound(err) { + m.Log.Error(err, "error while finding pod") + return err + } + + m.Log.Info("pod not found", "key", m.Key, "error", err.Error()) + err = ErrPodNotFound + return err + } + + if pod.Status.Phase != v1.PodRunning { + m.Log.Info("pod is not running", "key", m.Key) + err = ErrPodNotRunning + return err + } + + chaos.Name = m.Key.Name + chaos.Namespace = m.Key.Namespace + chaos.OwnerReferences = []metav1.OwnerReference{ + { + APIVersion: pod.APIVersion, + Kind: pod.Kind, + Name: pod.Name, + UID: pod.UID, + }, + } + err = m.T.Apply(chaos) + if err != nil { + m.Log.Error(err, "error while applying transactions", "transaction", m.T) + return err + } + + return m.Client.Create(ctx, chaos) +} diff --git a/controllers/chaosimpl/iochaos/podiochaosmanager/transaction.go b/controllers/chaosimpl/iochaos/podiochaosmanager/transaction.go new file mode 100644 index 0000000000..f3ab0baca7 --- /dev/null +++ b/controllers/chaosimpl/iochaos/podiochaosmanager/transaction.go @@ -0,0 +1,142 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podiochaosmanager + +import ( + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" +) + +// PodIOTransaction represents a modification on podnetwork +type PodIOTransaction struct { + Steps []Step +} + +// Step represents a step of PodIOTransaction +type Step interface { + // Apply will apply an action on podnetworkchaos + Apply(chaos *v1alpha1.PodIOChaos) error +} + +// Clear removes all resources with the same source +type Clear struct { + Source string +} + +// Apply runs this action +func (s *Clear) Apply(chaos *v1alpha1.PodIOChaos) error { + actions := []v1alpha1.IOChaosAction{} + for _, action := range chaos.Spec.Actions { + if action.Source != s.Source { + actions = append(actions, action) + } + } + chaos.Spec.Actions = actions + + return nil +} + +// Append adds an item to corresponding list in podnetworkchaos +type Append struct { + Item interface{} +} + +// Apply runs this action +func (a *Append) Apply(chaos *v1alpha1.PodIOChaos) error { + switch item := a.Item.(type) { + case v1alpha1.IOChaosAction: + chaos.Spec.Actions = append(chaos.Spec.Actions, item) + default: + return errors.Wrapf(utils.ErrUnknownType, "type: %T", item) + } + + return nil +} + +// SetContainer sets the container field of podiochaos +type SetContainer struct { + Container string +} + +// Apply runs this action +func (s *SetContainer) Apply(chaos *v1alpha1.PodIOChaos) error { + chaos.Spec.Container = &s.Container + + return nil +} + +// SetVolumePath sets the volumePath field of podiochaos +type SetVolumePath struct { + Path string +} + +// Apply runs this action +func (s *SetVolumePath) Apply(chaos *v1alpha1.PodIOChaos) error { + chaos.Spec.VolumeMountPath = s.Path + + return nil +} + +// Clear will clear all related items in podnetworkchaos +func (t *PodIOTransaction) Clear(source string) { + t.Steps = append(t.Steps, &Clear{ + Source: source, + }) +} + +// Append adds an item to corresponding list in podnetworkchaos +func (t *PodIOTransaction) Append(item interface{}) error { + switch item.(type) { + case v1alpha1.IOChaosAction: + t.Steps = append(t.Steps, &Append{ + Item: item, + }) + return nil + default: + return errors.Wrapf(utils.ErrUnknownType, "type: %T", item) + } +} + +// SetVolumePath sets the volumePath field of podiochaos +func (t *PodIOTransaction) SetVolumePath(path string) error { + t.Steps = append(t.Steps, &SetVolumePath{ + Path: path, + }) + + return nil +} + +func (t *PodIOTransaction) SetContainer(container string) error { + t.Steps = append(t.Steps, &SetContainer{ + Container: container, + }) + + return nil +} + +// Apply runs every step on the chaos +func (t *PodIOTransaction) Apply(chaos *v1alpha1.PodIOChaos) error { + for _, s := range t.Steps { + err := s.Apply(chaos) + if err != nil { + return err + } + } + + return nil +} diff --git a/controllers/chaosimpl/jvmchaos/impl.go b/controllers/chaosimpl/jvmchaos/impl.go new file mode 100644 index 0000000000..36315c16eb --- /dev/null +++ b/controllers/chaosimpl/jvmchaos/impl.go @@ -0,0 +1,316 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package jvmchaos + +import ( + "bytes" + "context" + "fmt" + "strings" + "text/template" + + "github.com/go-logr/logr" + "github.com/pingcap/errors" + "go.uber.org/fx" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" +) + +var ( + errNilDecoder error = errors.New("impl decoder is nil") +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +const ( + // byteman rule template + SimpleRuleTemplate = ` +RULE {{.Name}} +CLASS {{.Class}} +METHOD {{.Method}} +AT ENTRY +IF true +DO + {{.Do}}; +ENDRULE +` + + CompleteRuleTemplate = ` +RULE {{.Name}} +CLASS {{.Class}} +METHOD {{.Method}} +HELPER {{.Helper}} +AT ENTRY +BIND {{.Bind}}; +IF {{.Condition}} +DO + {{.Do}}; +ENDRULE +` + + // for action 'mysql', 'gc' and 'stress' + SQLHelper = "org.chaos_mesh.byteman.helper.SQLHelper" + GCHelper = "org.chaos_mesh.byteman.helper.GCHelper" + StressHelper = "org.chaos_mesh.byteman.helper.StressHelper" + + // the trigger point for 'gc' and 'stress' + TriggerClass = "org.chaos_mesh.chaos_agent.TriggerThread" + TriggerMethod = "triggerFunc" + + MySQL5InjectClass = "com.mysql.jdbc.MysqlIO" + MySQL5InjectMethod = "sqlQueryDirect" + MySQL5Exception = "java.sql.SQLException(\"%s\")" + + MySQL8InjectClass = "com.mysql.cj.NativeSession" + MySQL8InjectMethod = "execSQL" + MySQL8Exception = "com.mysql.cj.exceptions.CJException(\"%s\")" +) + +// BytemanTemplateSpec is the template spec for byteman rule +type BytemanTemplateSpec struct { + Name string + Class string + Method string + Helper string + Bind string + Condition string + Do string + + // below is only used for stress template + StressType string + StressValueName string + StressValue string +} + +type Impl struct { + client.Client + Log logr.Logger + + decoder *utils.ContainerRecordDecoder +} + +// Apply applies jvm-chaos +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + impl.Log.Info("jvm chaos apply", "record", records[index]) + if impl.decoder == nil { + return v1alpha1.NotInjected, errors.WithStack(errNilDecoder) + } + decodedContainer, err := impl.decoder.DecodeContainerRecord(ctx, records[index], obj) + if decodedContainer.PbClient != nil { + defer func() { + err := decodedContainer.PbClient.Close() + if err != nil { + impl.Log.Error(err, "fail to close pb client") + } + }() + } + if err != nil { + return v1alpha1.NotInjected, err + } + + jvmChaos := obj.(*v1alpha1.JVMChaos) + err = generateRuleData(&jvmChaos.Spec) + if err != nil { + impl.Log.Error(err, "fail to generate rule data") + + return v1alpha1.Injected, err + } + + _, err = decodedContainer.PbClient.InstallJVMRules(ctx, &pb.InstallJVMRulesRequest{ + ContainerId: decodedContainer.ContainerId, + Rule: jvmChaos.Spec.RuleData, + Port: jvmChaos.Spec.Port, + EnterNS: true, + }) + if err != nil { + impl.Log.Error(err, "install jvm rules") + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} + +// Recover means the reconciler recovers the chaos action +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + if impl.decoder == nil { + return v1alpha1.Injected, errors.WithStack(errNilDecoder) + } + decodedContainer, err := impl.decoder.DecodeContainerRecord(ctx, records[index], obj) + if decodedContainer.PbClient != nil { + defer func() { + err := decodedContainer.PbClient.Close() + if err != nil { + impl.Log.Error(err, "fail to close pb client") + } + }() + } + if err != nil && strings.Contains(err.Error(), "container not found") { + // Unable to find the container, so we are unable to remove the experiment from the jvm as it has gone + impl.Log.Error(err, "finding container") + return v1alpha1.NotInjected, nil + } + if err != nil { + return v1alpha1.Injected, err + } + + jvmChaos := obj.(*v1alpha1.JVMChaos) + err = generateRuleData(&jvmChaos.Spec) + if err != nil { + impl.Log.Error(err, "fail to generate rule data") + + return v1alpha1.Injected, err + } + + _, err = decodedContainer.PbClient.UninstallJVMRules(ctx, &pb.UninstallJVMRulesRequest{ + ContainerId: decodedContainer.ContainerId, + Rule: jvmChaos.Spec.RuleData, + Port: jvmChaos.Spec.Port, + EnterNS: true, + }) + if err != nil && strings.Contains(err.Error(), "Connection refused") { + // Unable to connect to the jvm - meaning that there is no agent running on the jvm, most likely because the jvm process has been restarted + impl.Log.Error(err, "uninstall jvm rules (possible restart of jvm process)") + return v1alpha1.NotInjected, nil + } + if err != nil { + impl.Log.Error(err, "uninstall jvm rules") + return v1alpha1.Injected, err + } + + return v1alpha1.NotInjected, nil +} + +// JVMRuleParameter is only used to generate rule data +type JVMRuleParameter struct { + v1alpha1.JVMParameter + + StressType string + StressValue string + StressValueName string + Do string +} + +func generateRuleData(spec *v1alpha1.JVMChaosSpec) error { + if len(spec.RuleData) != 0 { + return nil + } + + bytemanTemplateSpec := BytemanTemplateSpec{ + Name: spec.Name, + Class: spec.Class, + Method: spec.Method, + } + + switch spec.Action { + case v1alpha1.JVMLatencyAction: + bytemanTemplateSpec.Do = fmt.Sprintf("Thread.sleep(%d)", spec.LatencyDuration) + case v1alpha1.JVMExceptionAction: + bytemanTemplateSpec.Do = fmt.Sprintf("throw new %s", spec.ThrowException) + case v1alpha1.JVMReturnAction: + bytemanTemplateSpec.Do = fmt.Sprintf("return %s", spec.ReturnValue) + case v1alpha1.JVMStressAction: + bytemanTemplateSpec.Helper = StressHelper + bytemanTemplateSpec.Class = TriggerClass + bytemanTemplateSpec.Method = TriggerMethod + // the bind and condition is useless, only used for fill the template + bytemanTemplateSpec.Bind = "flag:boolean=true" + bytemanTemplateSpec.Condition = "true" + if spec.CPUCount > 0 { + bytemanTemplateSpec.Do = fmt.Sprintf("injectCPUStress(\"%s\", %d)", spec.Name, spec.CPUCount) + } else { + bytemanTemplateSpec.Do = fmt.Sprintf("injectMemStress(\"%s\", \"%s\")", spec.Name, spec.MemoryType) + } + case v1alpha1.JVMGCAction: + bytemanTemplateSpec.Helper = GCHelper + bytemanTemplateSpec.Class = TriggerClass + bytemanTemplateSpec.Method = TriggerMethod + // the bind and condition is useless, only used for fill the template + bytemanTemplateSpec.Bind = "flag:boolean=true" + bytemanTemplateSpec.Condition = "true" + bytemanTemplateSpec.Do = "gc()" + case v1alpha1.JVMMySQLAction: + var mysqlException string + bytemanTemplateSpec.Helper = SQLHelper + // the first parameter of matchDBTable is the database which the SQL execute in, because the SQL may not contain database, for example: select * from t1; + // can't get the database information now, so use a "" instead + // TODO: get the database information and fill it in matchDBTable function + bytemanTemplateSpec.Bind = fmt.Sprintf("flag:boolean=matchDBTable(\"\", $2, \"%s\", \"%s\", \"%s\")", spec.Database, spec.Table, spec.SQLType) + bytemanTemplateSpec.Condition = "flag" + if spec.MySQLConnectorVersion == "5" { + bytemanTemplateSpec.Class = MySQL5InjectClass + bytemanTemplateSpec.Method = MySQL5InjectMethod + mysqlException = MySQL5Exception + } else if spec.MySQLConnectorVersion == "8" { + bytemanTemplateSpec.Class = MySQL8InjectClass + bytemanTemplateSpec.Method = MySQL8InjectMethod + mysqlException = MySQL8Exception + } else { + return errors.Errorf("mysql connector version %s is not supported", spec.MySQLConnectorVersion) + } + + if len(spec.ThrowException) > 0 { + exception := fmt.Sprintf(mysqlException, spec.ThrowException) + bytemanTemplateSpec.Do = fmt.Sprintf("throw new %s", exception) + } else if spec.LatencyDuration > 0 { + bytemanTemplateSpec.Do = fmt.Sprintf("Thread.sleep(%d)", spec.LatencyDuration) + } + } + + buf := new(bytes.Buffer) + var t *template.Template + switch spec.Action { + case v1alpha1.JVMStressAction, v1alpha1.JVMGCAction, v1alpha1.JVMMySQLAction: + t = template.Must(template.New("byteman rule").Parse(CompleteRuleTemplate)) + case v1alpha1.JVMExceptionAction, v1alpha1.JVMLatencyAction, v1alpha1.JVMReturnAction: + t = template.Must(template.New("byteman rule").Parse(SimpleRuleTemplate)) + default: + return errors.Errorf("jvm action %s not supported", spec.Action) + } + if t == nil { + return errors.Errorf("parse byeman rule template failed") + } + err := t.Execute(buf, bytemanTemplateSpec) + if err != nil { + return err + } + + spec.RuleData = buf.String() + return nil +} + +// Object would return the instance of chaos +func NewImpl(c client.Client, decoder *utils.ContainerRecordDecoder, log logr.Logger) *impltypes.ChaosImplPair { + return &impltypes.ChaosImplPair{ + Name: "jvmchaos", + Object: &v1alpha1.JVMChaos{}, + Impl: &Impl{ + Client: c, + Log: log.WithName("jvmchaos"), + decoder: decoder, + }, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, +) diff --git a/controllers/chaosimpl/jvmchaos/impl_test.go b/controllers/chaosimpl/jvmchaos/impl_test.go new file mode 100644 index 0000000000..fde39ee72c --- /dev/null +++ b/controllers/chaosimpl/jvmchaos/impl_test.go @@ -0,0 +1,171 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package jvmchaos + +import ( + "testing" + + . "github.com/onsi/gomega" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +func TestGenerateRuleData(t *testing.T) { + g := NewWithT(t) + + testCases := []struct { + spec *v1alpha1.JVMChaosSpec + ruleData string + }{ + { + &v1alpha1.JVMChaosSpec{ + Action: v1alpha1.JVMExceptionAction, + JVMParameter: v1alpha1.JVMParameter{ + Name: "test", + JVMCommonSpec: v1alpha1.JVMCommonSpec{ + Pid: 1234, + }, + JVMClassMethodSpec: v1alpha1.JVMClassMethodSpec{ + Class: "testClass", + Method: "testMethod", + }, + ThrowException: "java.io.IOException(\"BOOM\")", + }, + }, + "\nRULE test\nCLASS testClass\nMETHOD testMethod\nAT ENTRY\nIF true\nDO\n\tthrow new java.io.IOException(\"BOOM\");\nENDRULE\n", + }, + { + &v1alpha1.JVMChaosSpec{ + Action: v1alpha1.JVMReturnAction, + JVMParameter: v1alpha1.JVMParameter{ + Name: "test", + JVMCommonSpec: v1alpha1.JVMCommonSpec{ + Pid: 1234, + }, + JVMClassMethodSpec: v1alpha1.JVMClassMethodSpec{ + Class: "testClass", + Method: "testMethod", + }, + ReturnValue: "\"test\"", + }, + }, + "\nRULE test\nCLASS testClass\nMETHOD testMethod\nAT ENTRY\nIF true\nDO\n\treturn \"test\";\nENDRULE\n", + }, + { + &v1alpha1.JVMChaosSpec{ + Action: v1alpha1.JVMLatencyAction, + JVMParameter: v1alpha1.JVMParameter{ + Name: "test", + JVMCommonSpec: v1alpha1.JVMCommonSpec{ + Pid: 1234, + }, + JVMClassMethodSpec: v1alpha1.JVMClassMethodSpec{ + Class: "testClass", + Method: "testMethod", + }, + LatencyDuration: 5000, + }, + }, + "\nRULE test\nCLASS testClass\nMETHOD testMethod\nAT ENTRY\nIF true\nDO\n\tThread.sleep(5000);\nENDRULE\n", + }, + { + &v1alpha1.JVMChaosSpec{ + Action: v1alpha1.JVMStressAction, + JVMParameter: v1alpha1.JVMParameter{ + Name: "test", + JVMCommonSpec: v1alpha1.JVMCommonSpec{ + Pid: 1234, + }, + JVMStressCfgSpec: v1alpha1.JVMStressCfgSpec{ + CPUCount: 1, + }, + }, + }, + "\nRULE test\nCLASS org.chaos_mesh.chaos_agent.TriggerThread\nMETHOD triggerFunc\nHELPER org.chaos_mesh.byteman.helper.StressHelper\nAT ENTRY\nBIND flag:boolean=true;\nIF true\nDO\n\tinjectCPUStress(\"test\", 1);\nENDRULE\n", + }, + { + &v1alpha1.JVMChaosSpec{ + Action: v1alpha1.JVMStressAction, + JVMParameter: v1alpha1.JVMParameter{ + Name: "test", + JVMCommonSpec: v1alpha1.JVMCommonSpec{ + Pid: 1234, + }, + JVMStressCfgSpec: v1alpha1.JVMStressCfgSpec{ + MemoryType: "heap", + }, + }, + }, + "\nRULE test\nCLASS org.chaos_mesh.chaos_agent.TriggerThread\nMETHOD triggerFunc\nHELPER org.chaos_mesh.byteman.helper.StressHelper\nAT ENTRY\nBIND flag:boolean=true;\nIF true\nDO\n\tinjectMemStress(\"test\", \"heap\");\nENDRULE\n", + }, + { + &v1alpha1.JVMChaosSpec{ + Action: v1alpha1.JVMGCAction, + JVMParameter: v1alpha1.JVMParameter{ + Name: "test", + JVMCommonSpec: v1alpha1.JVMCommonSpec{ + Pid: 1234, + }, + }, + }, + "\nRULE test\nCLASS org.chaos_mesh.chaos_agent.TriggerThread\nMETHOD triggerFunc\nHELPER org.chaos_mesh.byteman.helper.GCHelper\nAT ENTRY\nBIND flag:boolean=true;\nIF true\nDO\n\tgc();\nENDRULE\n", + }, + { + &v1alpha1.JVMChaosSpec{ + Action: v1alpha1.JVMMySQLAction, + JVMParameter: v1alpha1.JVMParameter{ + Name: "test", + JVMCommonSpec: v1alpha1.JVMCommonSpec{ + Pid: 1234, + }, + JVMMySQLSpec: v1alpha1.JVMMySQLSpec{ + MySQLConnectorVersion: "8", + Database: "test", + Table: "t1", + SQLType: "select", + }, + ThrowException: "BOOM", + }, + }, + "\nRULE test\nCLASS com.mysql.cj.NativeSession\nMETHOD execSQL\nHELPER org.chaos_mesh.byteman.helper.SQLHelper\nAT ENTRY\nBIND flag:boolean=matchDBTable(\"\", $2, \"test\", \"t1\", \"select\");\nIF flag\nDO\n\tthrow new com.mysql.cj.exceptions.CJException(\"BOOM\");\nENDRULE\n", + }, + { + &v1alpha1.JVMChaosSpec{ + Action: v1alpha1.JVMMySQLAction, + JVMParameter: v1alpha1.JVMParameter{ + Name: "test", + JVMCommonSpec: v1alpha1.JVMCommonSpec{ + Pid: 1234, + }, + JVMMySQLSpec: v1alpha1.JVMMySQLSpec{ + MySQLConnectorVersion: "8", + Database: "test", + Table: "t1", + SQLType: "select", + }, + LatencyDuration: 5000, + }, + }, + "\nRULE test\nCLASS com.mysql.cj.NativeSession\nMETHOD execSQL\nHELPER org.chaos_mesh.byteman.helper.SQLHelper\nAT ENTRY\nBIND flag:boolean=matchDBTable(\"\", $2, \"test\", \"t1\", \"select\");\nIF flag\nDO\n\tThread.sleep(5000);\nENDRULE\n", + }, + } + + for _, testCase := range testCases { + err := generateRuleData(testCase.spec) + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(testCase.spec.RuleData).Should(Equal(testCase.ruleData)) + } +} diff --git a/controllers/chaosimpl/kernelchaos/types.go b/controllers/chaosimpl/kernelchaos/types.go new file mode 100644 index 0000000000..297b2279e4 --- /dev/null +++ b/controllers/chaosimpl/kernelchaos/types.go @@ -0,0 +1,257 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package kernelchaos + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "go.uber.org/fx" + "google.golang.org/grpc" + v1 "k8s.io/api/core/v1" + k8sError "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" + pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + pb_kernel "github.com/chaos-mesh/chaos-mesh/pkg/chaoskernel/pb" + grpcUtils "github.com/chaos-mesh/chaos-mesh/pkg/grpc" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + Log logr.Logger + + chaosDaemonClientBuilder *chaosdaemon.ChaosDaemonClientBuilder +} + +// Apply applies KernelChaos +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + kernelChaos := obj.(*v1alpha1.KernelChaos) + record := records[index] + + log := impl.Log.WithValues("chaos", kernelChaos, "record", record) + podId, containerID, err := controller.ParseNamespacedNameContainer(record.Id) + if err != nil { + return v1alpha1.NotInjected, err + } + var pod v1.Pod + err = impl.Client.Get(ctx, podId, &pod) + if err != nil { + log.Error(err, "fail to get pod by record") + // TODO: handle this error + if k8sError.IsNotFound(err) { + return v1alpha1.NotInjected, nil + } + return v1alpha1.NotInjected, err + } + + log = log.WithValues("pod", pod) + + if err = impl.applyPod(ctx, &pod, kernelChaos, containerID); err != nil { + log.Error(err, "failed to apply chaos on pod") + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} + +// Recover means the reconciler recovers the chaos action +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + kernelChaos := obj.(*v1alpha1.KernelChaos) + record := records[index] + + log := impl.Log.WithValues("chaos", kernelChaos, "record", record) + podId, containerID, err := controller.ParseNamespacedNameContainer(record.Id) + if err != nil { + errorInfo := fmt.Sprintf("kernelChaos recover error, record ID is %s", record.Id) + log.Error(err, errorInfo) + // This error is not expected to exist + return v1alpha1.Injected, err + } + var pod v1.Pod + err = impl.Client.Get(ctx, podId, &pod) + if err != nil { + log.Error(err, "fail to get pod by record") + // TODO: handle this error + if k8sError.IsNotFound(err) { + return v1alpha1.NotInjected, nil + } + return v1alpha1.Injected, err + } + + log = log.WithValues("pod", pod) + + if err = impl.recoverPod(ctx, &pod, kernelChaos, containerID); err != nil { + log.Error(err, "failed to recover chaos on pod") + return v1alpha1.Injected, err + } + + return v1alpha1.NotInjected, nil +} + +func (impl *Impl) recoverPod(ctx context.Context, pod *v1.Pod, chaos *v1alpha1.KernelChaos, containerID string) error { + impl.Log.Info("try to recover pod", "namespace", pod.Namespace, "name", pod.Name) + + pbClient, err := impl.chaosDaemonClientBuilder.Build(ctx, pod, &types.NamespacedName{ + Namespace: chaos.Namespace, + Name: chaos.Name, + }) + if err != nil { + return err + } + defer pbClient.Close() + + if len(pod.Status.ContainerStatuses) == 0 { + err = errors.Wrapf(utils.ErrContainerNotFound, "pod %s/%s has empty container status", pod.Namespace, pod.Name) + return err + } + + containerResponse, err := pbClient.ContainerGetPid(ctx, &pb.ContainerRequest{ + Action: &pb.ContainerAction{ + Action: pb.ContainerAction_GETPID, + }, + ContainerId: containerID, + }) + + if err != nil { + impl.Log.Error(err, "Get container pid error", "namespace", pod.Namespace, "name", pod.Name) + return err + } + + impl.Log.Info("Get container pid", "namespace", pod.Namespace, "name", pod.Name) + conn, err := impl.CreateBPFKIConnection(ctx, impl.Client, pod) + if err != nil { + return err + } + defer conn.Close() + + var callchain []*pb_kernel.FailKernRequestFrame + for _, frame := range chaos.Spec.FailKernRequest.Callchain { + callchain = append(callchain, &pb_kernel.FailKernRequestFrame{ + Funcname: frame.Funcname, + Parameters: frame.Parameters, + Predicate: frame.Predicate, + }) + } + + bpfClient := pb_kernel.NewBPFKIServiceClient(conn) + _, err = bpfClient.RecoverMMOrBIO(ctx, &pb_kernel.FailKernRequest{ + Pid: containerResponse.Pid, + Callchain: callchain, + }) + + return err +} + +func (impl *Impl) applyPod(ctx context.Context, pod *v1.Pod, chaos *v1alpha1.KernelChaos, containerID string) error { + impl.Log.Info("Try to inject kernel on pod", "namespace", pod.Namespace, "name", pod.Name) + + pbClient, err := impl.chaosDaemonClientBuilder.Build(ctx, pod, &types.NamespacedName{ + Namespace: chaos.Namespace, + Name: chaos.Name, + }) + if err != nil { + return err + } + defer pbClient.Close() + + if len(pod.Status.ContainerStatuses) == 0 { + err = errors.Wrapf(utils.ErrContainerNotFound, "pod %s/%s has empty container status", pod.Namespace, pod.Name) + return err + } + + containerResponse, err := pbClient.ContainerGetPid(ctx, &pb.ContainerRequest{ + Action: &pb.ContainerAction{ + Action: pb.ContainerAction_GETPID, + }, + ContainerId: containerID, + }) + if err != nil { + impl.Log.Error(err, "Get container pid error", "namespace", pod.Namespace, "name", pod.Name) + return err + } + + impl.Log.Info("Get container pid", "namespace", pod.Namespace, "name", pod.Name) + conn, err := impl.CreateBPFKIConnection(ctx, impl.Client, pod) + if err != nil { + return err + } + defer conn.Close() + + var callchain []*pb_kernel.FailKernRequestFrame + for _, frame := range chaos.Spec.FailKernRequest.Callchain { + callchain = append(callchain, &pb_kernel.FailKernRequestFrame{ + Funcname: frame.Funcname, + Parameters: frame.Parameters, + Predicate: frame.Predicate, + }) + } + + bpfClient := pb_kernel.NewBPFKIServiceClient(conn) + _, err = bpfClient.FailMMOrBIO(ctx, &pb_kernel.FailKernRequest{ + Pid: containerResponse.Pid, + Ftype: pb_kernel.FailKernRequest_FAILTYPE(chaos.Spec.FailKernRequest.FailType), + Headers: chaos.Spec.FailKernRequest.Headers, + Callchain: callchain, + Probability: float32(chaos.Spec.FailKernRequest.Probability) / 100, + Times: chaos.Spec.FailKernRequest.Times, + }) + + return err +} + +// CreateBPFKIConnection create a grpc connection with bpfki +func (impl *Impl) CreateBPFKIConnection(ctx context.Context, c client.Client, pod *v1.Pod) (*grpc.ClientConn, error) { + daemonIP, err := impl.chaosDaemonClientBuilder.FindDaemonIP(ctx, pod) + if err != nil { + return nil, err + } + builder := grpcUtils.Builder(daemonIP, config.ControllerCfg.BPFKIPort). + WithDefaultTimeout(). + Insecure() + return builder.Build() +} + +func NewImpl(c client.Client, log logr.Logger, builder *chaosdaemon.ChaosDaemonClientBuilder) *impltypes.ChaosImplPair { + return &impltypes.ChaosImplPair{ + Name: "kernelchaos", + Object: &v1alpha1.KernelChaos{}, + Impl: &Impl{ + Client: c, + Log: log.WithName("kernelchaos"), + chaosDaemonClientBuilder: builder, + }, + ObjectList: &v1alpha1.KernelChaosList{}, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, +) diff --git a/controllers/chaosimpl/networkchaos/impl.go b/controllers/chaosimpl/networkchaos/impl.go new file mode 100644 index 0000000000..b51ad0cc46 --- /dev/null +++ b/controllers/chaosimpl/networkchaos/impl.go @@ -0,0 +1,56 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package networkchaos + +import ( + "go.uber.org/fx" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/action" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/networkchaos/partition" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/networkchaos/podnetworkchaosmanager" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/networkchaos/trafficcontrol" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +type Impl struct { + fx.In + + TrafficControl *trafficcontrol.Impl `action:"bandwidth,netem,delay,loss,duplicate,corrupt"` + Partition *partition.Impl `action:"partition"` +} + +func NewImpl(impl Impl) *impltypes.ChaosImplPair { + delegate := action.NewMultiplexer(&impl) + return &impltypes.ChaosImplPair{ + Name: "networkchaos", + Object: &v1alpha1.NetworkChaos{}, + Impl: &delegate, + ObjectList: &v1alpha1.NetworkChaosList{}, + Controlls: []client.Object{&v1alpha1.PodNetworkChaos{}}, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, + trafficcontrol.NewImpl, + partition.NewImpl, + podnetworkchaosmanager.NewBuilder, +) diff --git a/controllers/chaosimpl/networkchaos/partition/impl.go b/controllers/chaosimpl/networkchaos/partition/impl.go new file mode 100644 index 0000000000..3ee1f6f1cb --- /dev/null +++ b/controllers/chaosimpl/networkchaos/partition/impl.go @@ -0,0 +1,391 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package partition + +import ( + "context" + "strings" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + k8sError "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/networkchaos/podnetworkchaosmanager" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/ipset" + "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/iptable" + "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/netutils" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" + pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +const ( + sourceIPSetPostFix = "src" + targetIPSetPostFix = "tgt" +) + +type Impl struct { + client.Client + + builder *podnetworkchaosmanager.Builder + + Log logr.Logger +} + +const ( + waitForApplySync v1alpha1.Phase = "Not Injected/Wait" + waitForRecoverSync v1alpha1.Phase = "Injected/Wait" +) + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + impl.Log.Info("partition Apply", "chaos", obj) + networkchaos, ok := obj.(*v1alpha1.NetworkChaos) + if !ok { + err := errors.New("chaos is not NetworkChaos") + impl.Log.Error(err, "chaos is not NetworkChaos", "chaos", obj) + return v1alpha1.NotInjected, err + } + if networkchaos.Status.Instances == nil { + networkchaos.Status.Instances = make(map[string]int64) + } + + record := records[index] + phase := record.Phase + + if phase == waitForApplySync { + podnetworkchaos := &v1alpha1.PodNetworkChaos{} + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + return waitForApplySync, err + } + err = impl.Client.Get(ctx, namespacedName, podnetworkchaos) + if err != nil { + if k8sError.IsNotFound(err) { + return v1alpha1.NotInjected, nil + } + + if k8sError.IsForbidden(err) { + if strings.Contains(err.Error(), "because it is being terminated") { + return v1alpha1.NotInjected, nil + } + } + + return waitForApplySync, err + } + + if podnetworkchaos.Status.FailedMessage != "" { + return waitForApplySync, errors.New(podnetworkchaos.Status.FailedMessage) + } + + if podnetworkchaos.Status.ObservedGeneration >= networkchaos.Status.Instances[record.Id] { + return v1alpha1.Injected, nil + } + + return waitForApplySync, nil + } + + var pod v1.Pod + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + return v1alpha1.NotInjected, err + } + err = impl.Client.Get(ctx, namespacedName, &pod) + if err != nil { + // TODO: handle this error + return v1alpha1.NotInjected, err + } + + source := networkchaos.Namespace + "/" + networkchaos.Name + m := func() *podnetworkchaosmanager.PodNetworkManager { + shouldInit := true + + if record.SelectorKey == ".Target" { + for _, r := range records { + if r.Id == record.Id { + // Only init in the "." selector key so it won't be cleared + // by another one with the same key in the ".Target" + shouldInit = false + } + } + } + + if shouldInit { + return impl.builder.WithInit(source, types.NamespacedName{ + Namespace: pod.Namespace, + Name: pod.Name, + }) + } + + return impl.builder.Build(source, types.NamespacedName{ + Namespace: pod.Namespace, + Name: pod.Name, + }) + }() + + if record.SelectorKey == "." { + shouldCommit := false + + if networkchaos.Spec.Direction == v1alpha1.To || networkchaos.Spec.Direction == v1alpha1.Both { + var targets []*v1alpha1.Record + for _, record := range records { + if record.SelectorKey == ".Target" { + targets = append(targets, record) + } + } + + err := impl.SetDrop(ctx, m, targets, networkchaos, targetIPSetPostFix, v1alpha1.Output, networkchaos.Spec.Device) + if err != nil { + return v1alpha1.NotInjected, err + } + + shouldCommit = true + } + + if networkchaos.Spec.Direction == v1alpha1.From || networkchaos.Spec.Direction == v1alpha1.Both { + var targets []*v1alpha1.Record + for _, record := range records { + if record.SelectorKey == ".Target" { + targets = append(targets, record) + } + } + + err := impl.SetDrop(ctx, m, targets, networkchaos, targetIPSetPostFix, v1alpha1.Input, networkchaos.Spec.Device) + if err != nil { + return v1alpha1.NotInjected, err + } + + shouldCommit = true + } + + if shouldCommit { + generationNumber, err := m.Commit(ctx, networkchaos) + if err != nil { + return v1alpha1.NotInjected, err + } + + // modify the custom status + networkchaos.Status.Instances[record.Id] = generationNumber + return waitForApplySync, nil + } + + return v1alpha1.Injected, nil + } else if record.SelectorKey == ".Target" { + shouldCommit := false + + if networkchaos.Spec.Direction == v1alpha1.From || networkchaos.Spec.Direction == v1alpha1.Both { + var targets []*v1alpha1.Record + for _, record := range records { + if record.SelectorKey == "." { + targets = append(targets, record) + } + } + + err := impl.SetDrop(ctx, m, targets, networkchaos, sourceIPSetPostFix, v1alpha1.Output, networkchaos.Spec.TargetDevice) + if err != nil { + return v1alpha1.NotInjected, err + } + + shouldCommit = true + } + + if networkchaos.Spec.Direction == v1alpha1.To || networkchaos.Spec.Direction == v1alpha1.Both { + var targets []*v1alpha1.Record + for _, record := range records { + if record.SelectorKey == "." { + targets = append(targets, record) + } + } + + err := impl.SetDrop(ctx, m, targets, networkchaos, sourceIPSetPostFix, v1alpha1.Input, networkchaos.Spec.TargetDevice) + if err != nil { + return v1alpha1.NotInjected, err + } + + shouldCommit = true + } + + if shouldCommit { + generationNumber, err := m.Commit(ctx, networkchaos) + if err != nil { + return v1alpha1.NotInjected, err + } + + // modify the custom status + networkchaos.Status.Instances[record.Id] = generationNumber + return waitForApplySync, nil + } + + return v1alpha1.Injected, nil + } else { + impl.Log.Info("unknown selector key", "record", record) + return v1alpha1.NotInjected, nil + } +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + networkchaos, ok := obj.(*v1alpha1.NetworkChaos) + if !ok { + err := errors.New("chaos is not NetworkChaos") + impl.Log.Error(err, "chaos is not NetworkChaos", "chaos", obj) + return v1alpha1.Injected, err + } + if networkchaos.Status.Instances == nil { + networkchaos.Status.Instances = make(map[string]int64) + } + + record := records[index] + phase := record.Phase + + if phase == waitForRecoverSync { + podnetworkchaos := &v1alpha1.PodNetworkChaos{} + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + // This error is not expected to exist + return waitForApplySync, err + } + err = impl.Client.Get(ctx, namespacedName, podnetworkchaos) + if err != nil { + // TODO: handle this error + if k8sError.IsNotFound(err) { + return v1alpha1.NotInjected, nil + } + return waitForRecoverSync, err + } + + if podnetworkchaos.Status.FailedMessage != "" { + return waitForRecoverSync, errors.New(podnetworkchaos.Status.FailedMessage) + } + + if podnetworkchaos.Status.ObservedGeneration >= networkchaos.Status.Instances[record.Id] { + return v1alpha1.NotInjected, nil + } + + return waitForRecoverSync, nil + } + + var pod v1.Pod + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + // This error is not expected to exist + return v1alpha1.NotInjected, err + } + err = impl.Client.Get(ctx, namespacedName, &pod) + if err != nil { + // TODO: handle this error + if k8sError.IsNotFound(err) { + return v1alpha1.NotInjected, nil + } + return v1alpha1.Injected, err + } + + source := networkchaos.Namespace + "/" + networkchaos.Name + m := impl.builder.WithInit(source, types.NamespacedName{ + Namespace: pod.Namespace, + Name: pod.Name, + }) + generationNumber, err := m.Commit(ctx, networkchaos) + if err != nil { + if err == podnetworkchaosmanager.ErrPodNotFound || err == podnetworkchaosmanager.ErrPodNotRunning { + return v1alpha1.NotInjected, nil + } + + if k8sError.IsForbidden(err) { + if strings.Contains(err.Error(), "because it is being terminated") { + return v1alpha1.NotInjected, nil + } + } + return v1alpha1.Injected, err + } + + // Now modify the custom status and phase + networkchaos.Status.Instances[record.Id] = generationNumber + return waitForRecoverSync, nil +} + +func (impl *Impl) SetDrop(ctx context.Context, m *podnetworkchaosmanager.PodNetworkManager, targets []*v1alpha1.Record, networkchaos *v1alpha1.NetworkChaos, ipSetPostFix string, chainDirection v1alpha1.ChainDirection, device string) error { + externalCidrs, err := netutils.ResolveCidrs(networkchaos.Spec.ExternalTargets) + if err != nil { + return err + } + + pbChainDirection := pb.Chain_OUTPUT + if chainDirection == v1alpha1.Input { + pbChainDirection = pb.Chain_INPUT + } + if len(targets)+len(externalCidrs) == 0 { + impl.Log.Info("apply traffic control", "sources", m.Source) + m.T.Append(v1alpha1.RawIptables{ + Name: iptable.GenerateName(pbChainDirection, networkchaos), + Direction: chainDirection, + IPSets: nil, + RawRuleSource: v1alpha1.RawRuleSource{ + Source: m.Source, + }, + Device: device, + }) + return nil + } + + targetPods := []v1.Pod{} + for _, record := range targets { + var pod v1.Pod + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + // TODO: handle this error + return err + } + err = impl.Client.Get(ctx, namespacedName, &pod) + if err != nil { + // TODO: handle this error + return err + } + targetPods = append(targetPods, pod) + } + dstIPSets := ipset.BuildIPSets(targetPods, externalCidrs, networkchaos, ipSetPostFix, m.Source) + dstSetIPSet := ipset.BuildSetIPSet(dstIPSets, networkchaos, ipSetPostFix, m.Source) + + for _, ipSet := range dstIPSets { + m.T.Append(ipSet) + } + + m.T.Append(dstSetIPSet) + + m.T.Append(v1alpha1.RawIptables{ + Name: iptable.GenerateName(pbChainDirection, networkchaos), + Direction: chainDirection, + IPSets: []string{dstSetIPSet.Name}, + RawRuleSource: v1alpha1.RawRuleSource{ + Source: m.Source, + }, + Device: device, + }) + + return nil +} + +func NewImpl(c client.Client, b *podnetworkchaosmanager.Builder, log logr.Logger) *Impl { + return &Impl{ + Client: c, + builder: b, + Log: log.WithName("partition"), + } +} diff --git a/controllers/chaosimpl/networkchaos/podnetworkchaosmanager/builder.go b/controllers/chaosimpl/networkchaos/podnetworkchaosmanager/builder.go new file mode 100644 index 0000000000..9420a05652 --- /dev/null +++ b/controllers/chaosimpl/networkchaos/podnetworkchaosmanager/builder.go @@ -0,0 +1,80 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podnetworkchaosmanager + +import ( + "github.com/go-logr/logr" + "go.uber.org/fx" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type Builder struct { + Log logr.Logger + client.Client + client.Reader + scheme *runtime.Scheme +} + +type Params struct { + fx.In + + Logger logr.Logger + Client client.Client + Reader client.Reader `name:"no-cache"` + Scheme *runtime.Scheme +} + +func NewBuilder(params Params) *Builder { + return &Builder{ + Log: params.Logger, + Client: params.Client, + Reader: params.Reader, + scheme: params.Scheme, + } +} + +func (b *Builder) Build(source string, key types.NamespacedName) *PodNetworkManager { + t := &PodNetworkTransaction{} + + return &PodNetworkManager{ + Source: source, + Log: b.Log, + Client: b.Client, + Reader: b.Reader, + scheme: b.scheme, + + Key: key, + T: t, + } +} + +func (b *Builder) WithInit(source string, key types.NamespacedName) *PodNetworkManager { + t := &PodNetworkTransaction{} + t.Clear(source) + + return &PodNetworkManager{ + Source: source, + Log: b.Log, + Client: b.Client, + Reader: b.Reader, + scheme: b.scheme, + + Key: key, + T: t, + } +} diff --git a/controllers/chaosimpl/networkchaos/podnetworkchaosmanager/podnetworkchaosmanager.go b/controllers/chaosimpl/networkchaos/podnetworkchaosmanager/podnetworkchaosmanager.go new file mode 100644 index 0000000000..60477095a4 --- /dev/null +++ b/controllers/chaosimpl/networkchaos/podnetworkchaosmanager/podnetworkchaosmanager.go @@ -0,0 +1,145 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podnetworkchaosmanager + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + k8sError "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +var ( + // ErrPodNotFound means operate pod may be deleted(almostly) + ErrPodNotFound = errors.New("pod not found") + + // ErrPodNotRunning means operate pod may be not working + // and it's non-sense to make changes on it. + ErrPodNotRunning = errors.New("pod not running") +) + +// PodNetworkManager will save all the related podnetworkchaos +type PodNetworkManager struct { + Source string + + Log logr.Logger + client.Client + client.Reader + scheme *runtime.Scheme + + Key types.NamespacedName + T *PodNetworkTransaction +} + +// CommitResponse is a tuple (Key, Err) +type CommitResponse struct { + Key types.NamespacedName + Err error +} + +// Commit will update all modifications to the cluster +func (m *PodNetworkManager) Commit(ctx context.Context, owner *v1alpha1.NetworkChaos) (int64, error) { + m.Log.Info("running modification on pod", "key", m.Key, "modification", m.T) + updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { + chaos := &v1alpha1.PodNetworkChaos{} + + err := m.Client.Get(ctx, m.Key, chaos) + if err != nil { + if !k8sError.IsNotFound(err) { + m.Log.Error(err, "error while getting podnetworkchaos") + return err + } + + err := m.CreateNewPodNetworkChaos(ctx) + if err != nil { + m.Log.Error(err, "error while creating new podnetworkchaos") + return err + } + + return nil + } + + err = m.T.Apply(chaos) + if err != nil { + m.Log.Error(err, "error while applying transactions", "transaction", m.T) + return err + } + + return m.Client.Update(ctx, chaos) + }) + if updateError != nil { + return 0, updateError + } + + chaos := &v1alpha1.PodNetworkChaos{} + err := m.Reader.Get(ctx, m.Key, chaos) + if err != nil { + m.Log.Error(err, "error while getting the latest generation number") + return 0, err + } + return chaos.GetGeneration(), nil +} + +func (m *PodNetworkManager) CreateNewPodNetworkChaos(ctx context.Context) error { + var err error + chaos := &v1alpha1.PodNetworkChaos{} + + pod := v1.Pod{} + err = m.Client.Get(ctx, m.Key, &pod) + if err != nil { + if !k8sError.IsNotFound(err) { + m.Log.Error(err, "error while finding pod") + return err + } + + m.Log.Info("pod not found", "key", m.Key, "error", err.Error()) + err = ErrPodNotFound + return err + } + + if pod.Status.Phase != v1.PodRunning { + m.Log.Info("pod is not running", "key", m.Key) + err = ErrPodNotRunning + return err + } + + chaos.Name = m.Key.Name + chaos.Namespace = m.Key.Namespace + chaos.OwnerReferences = []metav1.OwnerReference{ + { + APIVersion: pod.APIVersion, + Kind: pod.Kind, + Name: pod.Name, + UID: pod.UID, + }, + } + err = m.T.Apply(chaos) + if err != nil { + m.Log.Error(err, "error while applying transactions", "transaction", m.T) + return err + } + + return m.Client.Create(ctx, chaos) +} diff --git a/controllers/chaosimpl/networkchaos/podnetworkchaosmanager/transaction.go b/controllers/chaosimpl/networkchaos/podnetworkchaosmanager/transaction.go new file mode 100644 index 0000000000..b4f7b87b46 --- /dev/null +++ b/controllers/chaosimpl/networkchaos/podnetworkchaosmanager/transaction.go @@ -0,0 +1,121 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podnetworkchaosmanager + +import ( + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" +) + +// PodNetworkTransaction represents a modification on podnetwork +type PodNetworkTransaction struct { + Steps []Step +} + +// Step represents a step of PodNetworkTransaction +type Step interface { + // Apply will apply an action on podnetworkchaos + Apply(chaos *v1alpha1.PodNetworkChaos) error +} + +// Clear removes all resources with the same source +type Clear struct { + Source string +} + +// Apply runs this action +func (s *Clear) Apply(chaos *v1alpha1.PodNetworkChaos) error { + ipsets := []v1alpha1.RawIPSet{} + for _, ipset := range chaos.Spec.IPSets { + if ipset.Source != s.Source { + ipsets = append(ipsets, ipset) + } + } + chaos.Spec.IPSets = ipsets + + chains := []v1alpha1.RawIptables{} + for _, chain := range chaos.Spec.Iptables { + if chain.Source != s.Source { + chains = append(chains, chain) + } + } + chaos.Spec.Iptables = chains + + qdiscs := []v1alpha1.RawTrafficControl{} + for _, qdisc := range chaos.Spec.TrafficControls { + if qdisc.Source != s.Source { + qdiscs = append(qdiscs, qdisc) + } + } + chaos.Spec.TrafficControls = qdiscs + + return nil +} + +// Append adds an item to corresponding list in podnetworkchaos +type Append struct { + Item interface{} +} + +// Apply runs this action +func (a *Append) Apply(chaos *v1alpha1.PodNetworkChaos) error { + switch item := a.Item.(type) { + case v1alpha1.RawIPSet: + chaos.Spec.IPSets = append(chaos.Spec.IPSets, item) + case v1alpha1.RawIptables: + chaos.Spec.Iptables = append(chaos.Spec.Iptables, item) + case v1alpha1.RawTrafficControl: + chaos.Spec.TrafficControls = append(chaos.Spec.TrafficControls, item) + default: + return errors.Wrapf(utils.ErrUnknownType, "type: %T", item) + } + + return nil +} + +// Clear will clear all related items in podnetworkchaos +func (t *PodNetworkTransaction) Clear(source string) { + t.Steps = append(t.Steps, &Clear{ + Source: source, + }) +} + +// Append adds an item to corresponding list in podnetworkchaos +func (t *PodNetworkTransaction) Append(item interface{}) error { + switch item.(type) { + case v1alpha1.RawIPSet, v1alpha1.RawIptables, v1alpha1.RawTrafficControl: + t.Steps = append(t.Steps, &Append{ + Item: item, + }) + return nil + default: + return errors.Wrapf(utils.ErrUnknownType, "type: %T", item) + } +} + +// Apply runs every step on the chaos +func (t *PodNetworkTransaction) Apply(chaos *v1alpha1.PodNetworkChaos) error { + for _, s := range t.Steps { + err := s.Apply(chaos) + if err != nil { + return err + } + } + + return nil +} diff --git a/controllers/chaosimpl/networkchaos/trafficcontrol/impl.go b/controllers/chaosimpl/networkchaos/trafficcontrol/impl.go new file mode 100644 index 0000000000..080e23c2ec --- /dev/null +++ b/controllers/chaosimpl/networkchaos/trafficcontrol/impl.go @@ -0,0 +1,324 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package trafficcontrol + +import ( + "context" + "strings" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + k8sError "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/networkchaos/podnetworkchaosmanager" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" + "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/ipset" + "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/netutils" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +const ( + targetIPSetPostFix = "tgt" + sourceIPSetPostFix = "src" +) + +const ( + waitForApplySync v1alpha1.Phase = "Not Injected/Wait" + waitForRecoverSync v1alpha1.Phase = "Injected/Wait" +) + +type Impl struct { + client.Client + + builder *podnetworkchaosmanager.Builder + + Log logr.Logger +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + // The only possible phase to get in here is "Not Injected" or "Not Injected/Wait" + + impl.Log.Info("traffic control Apply", "namespace", obj.GetNamespace(), "name", obj.GetName()) + networkchaos := obj.(*v1alpha1.NetworkChaos) + if networkchaos.Status.Instances == nil { + networkchaos.Status.Instances = make(map[string]int64) + } + + record := records[index] + phase := record.Phase + + if phase == waitForApplySync { + podnetworkchaos := &v1alpha1.PodNetworkChaos{} + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + return waitForApplySync, err + } + err = impl.Client.Get(ctx, namespacedName, podnetworkchaos) + if err != nil { + if k8sError.IsNotFound(err) { + return v1alpha1.NotInjected, nil + } + + if k8sError.IsForbidden(err) { + if strings.Contains(err.Error(), "because it is being terminated") { + return v1alpha1.NotInjected, nil + } + } + + return waitForApplySync, err + } + + if podnetworkchaos.Status.FailedMessage != "" { + return waitForApplySync, errors.New(podnetworkchaos.Status.FailedMessage) + } + + if podnetworkchaos.Status.ObservedGeneration >= networkchaos.Status.Instances[record.Id] { + return v1alpha1.Injected, nil + } + + return waitForApplySync, nil + } + + var pod v1.Pod + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + return v1alpha1.NotInjected, err + } + err = impl.Client.Get(ctx, namespacedName, &pod) + if err != nil { + // TODO: handle this error + return v1alpha1.NotInjected, err + } + + source := networkchaos.Namespace + "/" + networkchaos.Name + m := impl.builder.WithInit(source, types.NamespacedName{ + Namespace: pod.Namespace, + Name: pod.Name, + }) + + if record.SelectorKey == "." { + if networkchaos.Spec.Direction == v1alpha1.To || networkchaos.Spec.Direction == v1alpha1.Both { + var targets []*v1alpha1.Record + for _, record := range records { + if record.SelectorKey == ".Target" { + targets = append(targets, record) + } + } + + err := impl.ApplyTc(ctx, m, targets, networkchaos, targetIPSetPostFix, networkchaos.Spec.Device) + if err != nil { + return v1alpha1.NotInjected, err + } + + generationNumber, err := m.Commit(ctx, networkchaos) + if err != nil { + return v1alpha1.NotInjected, err + } + + // modify the custom status + networkchaos.Status.Instances[record.Id] = generationNumber + return waitForApplySync, nil + } + + return v1alpha1.Injected, nil + } else if record.SelectorKey == ".Target" { + if networkchaos.Spec.Direction == v1alpha1.From || networkchaos.Spec.Direction == v1alpha1.Both { + var targets []*v1alpha1.Record + for _, record := range records { + if record.SelectorKey == "." { + targets = append(targets, record) + } + } + + err := impl.ApplyTc(ctx, m, targets, networkchaos, sourceIPSetPostFix, networkchaos.Spec.TargetDevice) + if err != nil { + return v1alpha1.NotInjected, err + } + + generationNumber, err := m.Commit(ctx, networkchaos) + if err != nil { + return v1alpha1.NotInjected, err + } + + // modify the custom status + networkchaos.Status.Instances[record.Id] = generationNumber + return waitForApplySync, nil + } + + return v1alpha1.Injected, nil + } else { + impl.Log.Info("unknown selector key", "record", record) + return v1alpha1.NotInjected, nil + } +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + // The only possible phase to get in here is "Injected" or "Injected/Wait" + + networkchaos := obj.(*v1alpha1.NetworkChaos) + if networkchaos.Status.Instances == nil { + networkchaos.Status.Instances = make(map[string]int64) + } + + record := records[index] + phase := record.Phase + + if phase == waitForRecoverSync { + podnetworkchaos := &v1alpha1.PodNetworkChaos{} + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + // This error is not expected to exist + return waitForRecoverSync, err + } + err = impl.Client.Get(ctx, namespacedName, podnetworkchaos) + if err != nil { + // TODO: handle this error + if k8sError.IsNotFound(err) { + return v1alpha1.NotInjected, nil + } + return waitForRecoverSync, err + } + + if podnetworkchaos.Status.FailedMessage != "" { + return waitForRecoverSync, errors.New(podnetworkchaos.Status.FailedMessage) + } + + if podnetworkchaos.Status.ObservedGeneration >= networkchaos.Status.Instances[record.Id] { + return v1alpha1.NotInjected, nil + } + + return waitForRecoverSync, nil + } + + var pod v1.Pod + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + // This error is not expected to exist + return v1alpha1.Injected, err + } + err = impl.Client.Get(ctx, namespacedName, &pod) + if err != nil { + // TODO: handle this error + if k8sError.IsNotFound(err) { + return v1alpha1.NotInjected, nil + } + + if k8sError.IsForbidden(err) { + if strings.Contains(err.Error(), "because it is being terminated") { + return v1alpha1.NotInjected, nil + } + } + return v1alpha1.Injected, err + } + + source := networkchaos.Namespace + "/" + networkchaos.Name + // TODO: use the DI but not construct it manually + m := impl.builder.WithInit(source, types.NamespacedName{ + Namespace: pod.Namespace, + Name: pod.Name, + }) + generationNumber, err := m.Commit(ctx, networkchaos) + if err != nil { + if err == podnetworkchaosmanager.ErrPodNotFound || err == podnetworkchaosmanager.ErrPodNotRunning { + return v1alpha1.NotInjected, nil + } + return v1alpha1.Injected, err + } + + // Now modify the custom status and phase + networkchaos.Status.Instances[record.Id] = generationNumber + return waitForRecoverSync, nil +} + +func (impl *Impl) ApplyTc(ctx context.Context, m *podnetworkchaosmanager.PodNetworkManager, targets []*v1alpha1.Record, networkchaos *v1alpha1.NetworkChaos, ipSetPostFix string, device string) error { + spec := networkchaos.Spec + tcType := v1alpha1.Bandwidth + switch spec.Action { + case v1alpha1.NetemAction, v1alpha1.DelayAction, v1alpha1.DuplicateAction, v1alpha1.CorruptAction, v1alpha1.LossAction: + tcType = v1alpha1.Netem + case v1alpha1.BandwidthAction: + tcType = v1alpha1.Bandwidth + default: + return errors.Wrapf(utils.ErrUnknownAction, "action: %s", spec.Action) + } + + externalCidrs, err := netutils.ResolveCidrs(networkchaos.Spec.ExternalTargets) + if err != nil { + return err + } + + if len(targets)+len(externalCidrs) == 0 { + impl.Log.Info("apply traffic control", "sources", m.Source) + m.T.Append(v1alpha1.RawTrafficControl{ + Type: tcType, + TcParameter: spec.TcParameter, + Source: m.Source, + Device: device, + }) + return nil + } + + targetPods := []v1.Pod{} + for _, record := range targets { + var pod v1.Pod + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + // TODO: handle this error + return err + } + err = impl.Client.Get(ctx, namespacedName, &pod) + if err != nil { + // TODO: handle this error + return err + } + targetPods = append(targetPods, pod) + } + ipSetWithTcPostFix := string(tcType[0:2]) + ipSetPostFix + dstIPSets := ipset.BuildIPSets(targetPods, externalCidrs, networkchaos, ipSetWithTcPostFix, m.Source) + dstSetIPSet := ipset.BuildSetIPSet(dstIPSets, networkchaos, ipSetWithTcPostFix, m.Source) + impl.Log.Info("apply traffic control with filter", "sources", m.Source, "setIpset", dstSetIPSet, "ipSets", dstIPSets) + + for _, ipSet := range dstIPSets { + m.T.Append(ipSet) + } + + m.T.Append(dstSetIPSet) + + m.T.Append(v1alpha1.RawTrafficControl{ + Type: tcType, + TcParameter: spec.TcParameter, + Source: m.Source, + IPSet: dstSetIPSet.Name, + Device: device, + }) + + return nil +} + +func NewImpl(c client.Client, b *podnetworkchaosmanager.Builder, log logr.Logger) *Impl { + return &Impl{ + Client: c, + builder: b, + Log: log.WithName("trafficcontrol"), + } +} diff --git a/controllers/chaosimpl/physicalmachinechaos/impl.go b/controllers/chaosimpl/physicalmachinechaos/impl.go new file mode 100644 index 0000000000..b157c58d70 --- /dev/null +++ b/controllers/chaosimpl/physicalmachinechaos/impl.go @@ -0,0 +1,260 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package physicalmachinechaos + +import ( + "bytes" + "context" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "strings" + "time" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "go.uber.org/fx" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + Log logr.Logger +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + impl.Log.Info("apply physical machine chaos") + + physicalMachineChaos := obj.(*v1alpha1.PhysicalMachineChaos) + var address string + // For compatibility with older versions, we now have two ways to select the address + // of the physical machine, so there will be two possible values for the records: + // + // 1. when using address directly, values in records are IP + // 2. when using selector, values in records are NamespacedName + if len(physicalMachineChaos.Spec.Address) > 0 { + address = records[index].Id + } else { + var physicalMachine v1alpha1.PhysicalMachine + namespacedName, err := controller.ParseNamespacedName(records[index].Id) + if err != nil { + return v1alpha1.NotInjected, err + } + err = impl.Get(ctx, namespacedName, &physicalMachine) + if err != nil { + // TODO: handle this error + return v1alpha1.NotInjected, err + } + address = physicalMachine.Spec.Address + } + + // for example, physicalMachinechaos.Spec.Action is 'network-delay', action is 'network', subAction is 'delay' + // notice: 'process', 'vm', 'clock' and 'user_defined' action has no subAction, set subAction to "" + actions := strings.SplitN(string(physicalMachineChaos.Spec.Action), "-", 2) + if len(actions) == 1 { + actions = append(actions, "") + } else if len(actions) != 2 { + err := errors.New("action invalid") + return v1alpha1.NotInjected, err + } + action, subAction := actions[0], actions[1] + physicalMachineChaos.Spec.ExpInfo.Action = subAction + + /* + transform ExpInfo in PhysicalMachineChaos to json data required by chaosd + for example: + ExpInfo: &ExpInfo { + UID: "123", + Action: "cpu", + StressCPU: &StressCPU { + Load: 1, + Workers: 1, + } + } + + transform to json data: "{\"uid\":\"123\",\"action\":\"cpu\",\"load\":1,\"workers\":1} + */ + var expInfoMap map[string]interface{} + expInfoBytes, _ := json.Marshal(physicalMachineChaos.Spec.ExpInfo) + err := json.Unmarshal(expInfoBytes, &expInfoMap) + if err != nil { + impl.Log.Error(err, "fail to unmarshal experiment info") + return v1alpha1.NotInjected, err + } + configKV, ok := expInfoMap[string(physicalMachineChaos.Spec.Action)].(map[string]interface{}) + if !ok { + err = errors.New("transform action config to map failed") + impl.Log.Error(err, "") + return v1alpha1.NotInjected, err + } + delete(expInfoMap, string(physicalMachineChaos.Spec.Action)) + for k, v := range configKV { + expInfoMap[k] = v + } + + expInfoBytes, err = json.Marshal(expInfoMap) + if err != nil { + impl.Log.Error(err, "fail to marshal experiment info") + return v1alpha1.NotInjected, err + } + + url := fmt.Sprintf("%s/api/attack/%s", address, action) + impl.Log.Info("HTTP request", "address", address, "data", string(expInfoBytes)) + + statusCode, body, err := impl.doHttpRequest("POST", url, bytes.NewBuffer(expInfoBytes)) + if err != nil { + return v1alpha1.NotInjected, errors.Wrap(err, body) + } + + if statusCode != http.StatusOK { + err = errors.New("HTTP status is not OK") + impl.Log.Error(err, body) + return v1alpha1.NotInjected, errors.Wrap(err, body) + } + + return v1alpha1.Injected, nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + impl.Log.Info("recover physical machine chaos") + + physicalMachineChaos := obj.(*v1alpha1.PhysicalMachineChaos) + var address string + if len(physicalMachineChaos.Spec.Address) > 0 { + address = records[index].Id + } else { + var physicalMachine v1alpha1.PhysicalMachine + namespacedName, err := controller.ParseNamespacedName(records[index].Id) + if err != nil { + return v1alpha1.Injected, err + } + err = impl.Get(ctx, namespacedName, &physicalMachine) + if err != nil { + // TODO: handle this error + return v1alpha1.Injected, err + } + address = physicalMachine.Spec.Address + } + + url := fmt.Sprintf("%s/api/attack/%s", address, physicalMachineChaos.Spec.ExpInfo.UID) + statusCode, body, err := impl.doHttpRequest("DELETE", url, nil) + if err != nil { + return v1alpha1.Injected, errors.Wrap(err, body) + } + + if statusCode == http.StatusNotFound { + impl.Log.Info("experiment not found", "uid", physicalMachineChaos.Spec.ExpInfo.UID) + } else if statusCode != http.StatusOK { + err = errors.New("HTTP status is not OK") + impl.Log.Error(err, body) + return v1alpha1.Injected, errors.Wrap(err, body) + } + + return v1alpha1.NotInjected, nil +} + +func (impl *Impl) doHttpRequest(method, url string, data io.Reader) (int, string, error) { + req, err := http.NewRequest(method, url, data) + if err != nil { + impl.Log.Error(err, "fail to generate HTTP request") + return 0, "", err + } + req.Header.Set("Content-Type", "application/json") + + var httpClient *http.Client + if config.ControllerCfg.ChaosdSecurityMode { + httpClient, err = securityHTTPClient(url) + if err != nil { + impl.Log.Error(err, "generate HTTPS client") + return 0, "", err + } + } else { + httpClient = &http.Client{Timeout: 5 * time.Second} + } + + resp, err := httpClient.Do(req) + if err != nil { + impl.Log.Error(err, "do HTTP request") + return 0, "", err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return 0, "", err + } + impl.Log.Info("HTTP response", "url", url, "status", resp.Status, "body", string(body)) + + return resp.StatusCode, string(body), nil +} + +func securityHTTPClient(url string) (*http.Client, error) { + if !strings.Contains(url, "https") { + return nil, errors.Errorf("a secure url should begin with `https` rather than `http`, url: %s", url) + } + + pair, err := tls.LoadX509KeyPair(config.ControllerCfg.ChaosdClientCert, config.ControllerCfg.ChaosdClientKey) + if err != nil { + return nil, errors.Wrap(err, "load x509 key pair failed") + } + + pool := x509.NewCertPool() + ca, err := os.ReadFile(config.ControllerCfg.ChaosdCACert) + if err != nil { + return nil, errors.Wrap(err, "read ChaosdCACert file failed") + } + pool.AppendCertsFromPEM(ca) + + return &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: pool, + Certificates: []tls.Certificate{pair}, + ServerName: "chaosd.chaos-mesh.org", + }, + }, + Timeout: 5 * time.Second, + }, nil +} + +func NewImpl(c client.Client, log logr.Logger) *impltypes.ChaosImplPair { + return &impltypes.ChaosImplPair{ + Name: "physicalmachinechaos", + Object: &v1alpha1.PhysicalMachineChaos{}, + Impl: &Impl{ + Client: c, + Log: log.WithName("physicalmachinechaos"), + }, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, +) diff --git a/controllers/chaosimpl/podchaos/containerkill/impl.go b/controllers/chaosimpl/podchaos/containerkill/impl.go new file mode 100644 index 0000000000..e0904dd2b1 --- /dev/null +++ b/controllers/chaosimpl/podchaos/containerkill/impl.go @@ -0,0 +1,74 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package containerkill + +import ( + "context" + + "github.com/go-logr/logr" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + + Log logr.Logger + + decoder *utils.ContainerRecordDecoder +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + decodedContainer, err := impl.decoder.DecodeContainerRecord(ctx, records[index], obj) + pbClient := decodedContainer.PbClient + containerId := decodedContainer.ContainerId + if pbClient != nil { + defer pbClient.Close() + } + if err != nil { + return v1alpha1.NotInjected, err + } + + if _, err = pbClient.ContainerKill(ctx, &pb.ContainerRequest{ + Action: &pb.ContainerAction{ + Action: pb.ContainerAction_KILL, + }, + ContainerId: containerId, + }); err != nil { + impl.Log.Error(err, "kill container error", "containerID", containerId) + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client, log logr.Logger, decoder *utils.ContainerRecordDecoder) *Impl { + return &Impl{ + Client: c, + Log: log.WithName("containerkill"), + decoder: decoder, + } +} diff --git a/controllers/chaosimpl/podchaos/impl.go b/controllers/chaosimpl/podchaos/impl.go new file mode 100644 index 0000000000..3e2c443945 --- /dev/null +++ b/controllers/chaosimpl/podchaos/impl.go @@ -0,0 +1,54 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podchaos + +import ( + "go.uber.org/fx" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/action" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/podchaos/containerkill" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/podchaos/podfailure" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/podchaos/podkill" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" +) + +type Impl struct { + fx.In + + PodKill *podkill.Impl `action:"pod-kill"` + PodFailure *podfailure.Impl `action:"pod-failure"` + ContainerKill *containerkill.Impl `action:"container-kill"` +} + +func NewImpl(impl Impl) *impltypes.ChaosImplPair { + delegate := action.NewMultiplexer(&impl) + return &impltypes.ChaosImplPair{ + Name: "podchaos", + Object: &v1alpha1.PodChaos{}, + Impl: &delegate, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, + podkill.NewImpl, + podfailure.NewImpl, + containerkill.NewImpl, +) diff --git a/controllers/chaosimpl/podchaos/podfailure/impl.go b/controllers/chaosimpl/podchaos/podfailure/impl.go new file mode 100644 index 0000000000..f852be2256 --- /dev/null +++ b/controllers/chaosimpl/podchaos/podfailure/impl.go @@ -0,0 +1,154 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podfailure + +import ( + "context" + + v1 "k8s.io/api/core/v1" + k8sError "k8s.io/apimachinery/pkg/api/errors" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" + "github.com/chaos-mesh/chaos-mesh/pkg/annotation" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + podchaos := obj.(*v1alpha1.PodChaos) + + var origin v1.Pod + namespacedName, err := controller.ParseNamespacedName(records[index].Id) + if err != nil { + return v1alpha1.NotInjected, err + } + err = impl.Get(ctx, namespacedName, &origin) + if err != nil { + // TODO: handle this error + return v1alpha1.NotInjected, err + } + pod := origin.DeepCopy() + for index := range pod.Spec.Containers { + originImage := pod.Spec.Containers[index].Image + name := pod.Spec.Containers[index].Name + + key := annotation.GenKeyForImage(podchaos, name, false) + if pod.Annotations == nil { + pod.Annotations = make(map[string]string) + } + + // If the annotation is already existed, we could skip the reconcile for this container + if _, ok := pod.Annotations[key]; ok { + continue + } + pod.Annotations[key] = originImage + pod.Spec.Containers[index].Image = config.ControllerCfg.PodFailurePauseImage + } + + for index := range pod.Spec.InitContainers { + originImage := pod.Spec.InitContainers[index].Image + name := pod.Spec.InitContainers[index].Name + + key := annotation.GenKeyForImage(podchaos, name, true) + if pod.Annotations == nil { + pod.Annotations = make(map[string]string) + } + + // If the annotation is already existed, we could skip the reconcile for this container + if _, ok := pod.Annotations[key]; ok { + continue + } + pod.Annotations[key] = originImage + pod.Spec.InitContainers[index].Image = config.ControllerCfg.PodFailurePauseImage + } + + err = impl.Patch(ctx, pod, client.MergeFrom(&origin)) + if err != nil { + // TODO: handle this error + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + podchaos := obj.(*v1alpha1.PodChaos) + + var origin v1.Pod + namespacedName, err := controller.ParseNamespacedName(records[index].Id) + if err != nil { + // This error is not expected to exist + return v1alpha1.NotInjected, err + } + err = impl.Get(ctx, namespacedName, &origin) + if err != nil { + // TODO: handle this error + if k8sError.IsNotFound(err) { + return v1alpha1.NotInjected, nil + } + return v1alpha1.Injected, err + } + pod := origin.DeepCopy() + for index := range pod.Spec.Containers { + name := pod.Spec.Containers[index].Name + key := annotation.GenKeyForImage(podchaos, name, false) + + if pod.Annotations == nil { + pod.Annotations = make(map[string]string) + } + // check annotation + if image, ok := pod.Annotations[key]; ok { + pod.Spec.Containers[index].Image = image + delete(pod.Annotations, key) + } + } + + for index := range pod.Spec.InitContainers { + name := pod.Spec.InitContainers[index].Name + key := annotation.GenKeyForImage(podchaos, name, true) + + if pod.Annotations == nil { + pod.Annotations = make(map[string]string) + } + // check annotation + if image, ok := pod.Annotations[key]; ok { + pod.Spec.InitContainers[index].Image = image + delete(pod.Annotations, key) + } + } + + err = impl.Patch(ctx, pod, client.MergeFrom(&origin)) + if err != nil { + // TODO: handle this error + return v1alpha1.Injected, err + } + + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client) *Impl { + return &Impl{ + Client: c, + } +} diff --git a/controllers/chaosimpl/podchaos/podkill/impl.go b/controllers/chaosimpl/podchaos/podkill/impl.go new file mode 100644 index 0000000000..9d89e86519 --- /dev/null +++ b/controllers/chaosimpl/podchaos/podkill/impl.go @@ -0,0 +1,68 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podkill + +import ( + "context" + + v1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + podchaos := obj.(*v1alpha1.PodChaos) + + var pod v1.Pod + namespacedName, err := controller.ParseNamespacedName(records[index].Id) + if err != nil { + return v1alpha1.NotInjected, err + } + err = impl.Get(ctx, namespacedName, &pod) + if err != nil { + // TODO: handle this error + return v1alpha1.NotInjected, err + } + + err = impl.Delete(ctx, &pod, &client.DeleteOptions{ + GracePeriodSeconds: &podchaos.Spec.GracePeriod, // PeriodSeconds has to be set specifically + }) + if err != nil { + // TODO: handle this error + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client) *Impl { + return &Impl{ + Client: c, + } +} diff --git a/controllers/chaosimpl/stresschaos/impl.go b/controllers/chaosimpl/stresschaos/impl.go new file mode 100644 index 0000000000..2d4af542b8 --- /dev/null +++ b/controllers/chaosimpl/stresschaos/impl.go @@ -0,0 +1,165 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package stresschaos + +import ( + "context" + "time" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "go.uber.org/fx" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + + Log logr.Logger + + decoder *utils.ContainerRecordDecoder +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + decodedContainer, err := impl.decoder.DecodeContainerRecord(ctx, records[index], obj) + pbClient := decodedContainer.PbClient + containerId := decodedContainer.ContainerId + if pbClient != nil { + defer pbClient.Close() + } + if err != nil { + return v1alpha1.NotInjected, err + } + + stresschaos := obj.(*v1alpha1.StressChaos) + if stresschaos.Status.Instances == nil { + stresschaos.Status.Instances = make(map[string]v1alpha1.StressInstance) + } + _, ok := stresschaos.Status.Instances[records[index].Id] + if ok { + impl.Log.Info("an stress-ng instance is running for this pod") + return v1alpha1.Injected, nil + } + + stressors := stresschaos.Spec.StressngStressors + cpuStressors := "" + memoryStressors := "" + if len(stressors) == 0 { + cpuStressors, memoryStressors, err = stresschaos.Spec.Stressors.Normalize() + if err != nil { + impl.Log.Info("fail to ") + // TODO: add an event here + return v1alpha1.NotInjected, err + } + } + + req := pb.ExecStressRequest{ + Scope: pb.ExecStressRequest_CONTAINER, + Target: containerId, + CpuStressors: cpuStressors, + MemoryStressors: memoryStressors, + EnterNS: true, + } + if stresschaos.Spec.Stressors.MemoryStressor != nil { + req.OomScoreAdj = int32(stresschaos.Spec.Stressors.MemoryStressor.OOMScoreAdj) + } + res, err := pbClient.ExecStressors(ctx, &req) + + if err != nil { + return v1alpha1.NotInjected, err + } + // TODO: support custom status + stresschaos.Status.Instances[records[index].Id] = v1alpha1.StressInstance{ + UID: res.CpuInstance, + StartTime: &metav1.Time{ + Time: time.Unix(res.CpuStartTime/1000, (res.CpuStartTime%1000)*int64(time.Millisecond)), + }, + MemoryUID: res.MemoryInstance, + MemoryStartTime: &metav1.Time{ + Time: time.Unix(res.MemoryStartTime/1000, (res.MemoryStartTime%1000)*int64(time.Millisecond)), + }, + } + + return v1alpha1.Injected, nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + decodedContainer, err := impl.decoder.DecodeContainerRecord(ctx, records[index], obj) + pbClient := decodedContainer.PbClient + if pbClient != nil { + defer pbClient.Close() + } + if err != nil { + if errors.Is(err, utils.ErrContainerNotFound) { + // pretend the disappeared container has been recovered + return v1alpha1.NotInjected, nil + } + return v1alpha1.Injected, err + } + + stresschaos := obj.(*v1alpha1.StressChaos) + if stresschaos.Status.Instances == nil { + return v1alpha1.NotInjected, nil + } + instance, ok := stresschaos.Status.Instances[records[index].Id] + if !ok { + impl.Log.Info("Pod seems already recovered", "pod", decodedContainer.Pod.UID) + return v1alpha1.NotInjected, nil + } + req := &pb.CancelStressRequest{ + CpuInstance: instance.UID, + MemoryInstance: instance.MemoryUID, + } + if instance.StartTime != nil { + req.CpuStartTime = instance.StartTime.UnixNano() / int64(time.Millisecond) + } + if instance.MemoryStartTime != nil { + req.MemoryStartTime = instance.MemoryStartTime.UnixNano() / int64(time.Millisecond) + } + if _, err = pbClient.CancelStressors(ctx, req); err != nil { + impl.Log.Error(err, "cancel stressors") + return v1alpha1.Injected, nil + } + delete(stresschaos.Status.Instances, records[index].Id) + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client, log logr.Logger, decoder *utils.ContainerRecordDecoder) *impltypes.ChaosImplPair { + return &impltypes.ChaosImplPair{ + Name: "stresschaos", + Object: &v1alpha1.StressChaos{}, + Impl: &Impl{ + Client: c, + Log: log.WithName("stresschaos"), + decoder: decoder, + }, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, +) diff --git a/controllers/chaosimpl/timechaos/impl.go b/controllers/chaosimpl/timechaos/impl.go new file mode 100644 index 0000000000..6f2747a805 --- /dev/null +++ b/controllers/chaosimpl/timechaos/impl.go @@ -0,0 +1,135 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package timechaos + +import ( + "context" + "fmt" + "time" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "go.uber.org/fx" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + timeUtils "github.com/chaos-mesh/chaos-mesh/pkg/time/utils" +) + +var _ impltypes.ChaosImpl = (*Impl)(nil) + +type Impl struct { + client.Client + Log logr.Logger + decoder *utils.ContainerRecordDecoder +} + +func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + decodedContainer, err := impl.decoder.DecodeContainerRecord(ctx, records[index], obj) + pbClient := decodedContainer.PbClient + containerId := decodedContainer.ContainerId + if pbClient != nil { + defer pbClient.Close() + } + if err != nil { + return v1alpha1.NotInjected, err + } + + timechaos := obj.(*v1alpha1.TimeChaos) + mask, err := timeUtils.EncodeClkIds(timechaos.Spec.ClockIds) + if err != nil { + return v1alpha1.NotInjected, err + } + + duration, err := time.ParseDuration(timechaos.Spec.TimeOffset) + if err != nil { + return v1alpha1.NotInjected, err + } + + sec, nsec := secAndNSecFromDuration(duration) + + impl.Log.Info("setting time shift", "mask", mask, "sec", sec, "nsec", nsec, "containerId", containerId) + _, err = pbClient.SetTimeOffset(ctx, &pb.TimeRequest{ + ContainerId: containerId, + Sec: sec, + Nsec: nsec, + ClkIdsMask: mask, + Uid: string(obj.GetUID()) + string(decodedContainer.Pod.GetUID()), + PodContainerName: fmt.Sprintf("%s:%s", decodedContainer.Pod.GetUID(), decodedContainer.ContainerName), + }) + if err != nil { + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} + +func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + decodedContainer, err := impl.decoder.DecodeContainerRecord(ctx, records[index], obj) + pbClient := decodedContainer.PbClient + containerId := decodedContainer.ContainerId + if pbClient != nil { + defer pbClient.Close() + } + if err != nil { + if errors.Is(err, utils.ErrContainerNotFound) { + // pretend the disappeared container has been recovered + return v1alpha1.NotInjected, nil + } + return v1alpha1.Injected, err + } + + impl.Log.Info("recover for container", "containerId", containerId) + _, err = pbClient.RecoverTimeOffset(ctx, &pb.TimeRequest{ + ContainerId: containerId, + Uid: string(obj.GetUID()) + string(decodedContainer.Pod.GetUID()), + PodContainerName: fmt.Sprintf("%s:%s", decodedContainer.Pod.GetUID(), decodedContainer.ContainerName), + }) + if err != nil { + return v1alpha1.Injected, err + } + + return v1alpha1.NotInjected, nil +} + +func secAndNSecFromDuration(duration time.Duration) (sec int64, nsec int64) { + sec = duration.Nanoseconds() / 1e9 + nsec = duration.Nanoseconds() - (sec * 1e9) + + return +} + +func NewImpl(c client.Client, log logr.Logger, decoder *utils.ContainerRecordDecoder) *impltypes.ChaosImplPair { + return &impltypes.ChaosImplPair{ + Name: "timechaos", + Object: &v1alpha1.TimeChaos{}, + Impl: &Impl{ + Client: c, + Log: log.WithName("timechaos"), + decoder: decoder, + }, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, +) diff --git a/controllers/chaosimpl/types/types.go b/controllers/chaosimpl/types/types.go new file mode 100644 index 0000000000..5c6d6870d7 --- /dev/null +++ b/controllers/chaosimpl/types/types.go @@ -0,0 +1,38 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package types + +import ( + "context" + + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type ChaosImpl interface { + Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) + Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) +} + +type ChaosImplPair struct { + Name string + Object v1alpha1.InnerObjectWithSelector + Impl ChaosImpl + + ObjectList v1alpha1.GenericChaosList + Controlls []client.Object +} diff --git a/controllers/chaosimpl/utils/error.go b/controllers/chaosimpl/utils/error.go new file mode 100644 index 0000000000..b89f15de2f --- /dev/null +++ b/controllers/chaosimpl/utils/error.go @@ -0,0 +1,27 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package utils + +import ( + "github.com/pkg/errors" +) + +var ( + ErrUnknownType error = errors.New("unknown type") + ErrUnknownAction error = errors.New("unknown action") + + ErrContainerNotFound error = errors.New("container not found") +) diff --git a/controllers/chaosimpl/utils/fx.go b/controllers/chaosimpl/utils/fx.go new file mode 100644 index 0000000000..b3bacb0017 --- /dev/null +++ b/controllers/chaosimpl/utils/fx.go @@ -0,0 +1,22 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package utils + +import "go.uber.org/fx" + +var Module = fx.Provide( + NewContainerRecordDecoder, +) diff --git a/controllers/chaosimpl/utils/record.go b/controllers/chaosimpl/utils/record.go new file mode 100644 index 0000000000..f41d79c7df --- /dev/null +++ b/controllers/chaosimpl/utils/record.go @@ -0,0 +1,90 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package utils + +import ( + "context" + + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" + chaosdaemonclient "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/client" +) + +type ContainerRecordDecoder struct { + client.Client + *chaosdaemon.ChaosDaemonClientBuilder +} + +func NewContainerRecordDecoder(c client.Client, builder *chaosdaemon.ChaosDaemonClientBuilder) *ContainerRecordDecoder { + return &ContainerRecordDecoder{ + Client: c, + ChaosDaemonClientBuilder: builder, + } +} + +type DecodedContainerRecord struct { + PbClient chaosdaemonclient.ChaosDaemonClientInterface + ContainerId string + ContainerName string + Pod *v1.Pod +} + +func (d *ContainerRecordDecoder) DecodeContainerRecord(ctx context.Context, record *v1alpha1.Record, obj v1alpha1.InnerObject) (decoded DecodedContainerRecord, err error) { + var pod v1.Pod + podId, containerName, err := controller.ParseNamespacedNameContainer(record.Id) + if err != nil { + err = errors.Wrapf(ErrContainerNotFound, "container with id %s not found", record.Id) + return + } + err = d.Client.Get(ctx, podId, &pod) + if err != nil { + err = errors.Wrapf(ErrContainerNotFound, "container with id %s not found", record.Id) + return + } + decoded.Pod = &pod + if len(pod.Status.ContainerStatuses) == 0 { + err = errors.Wrapf(ErrContainerNotFound, "container with id %s not found", record.Id) + return + } + + for _, container := range pod.Status.ContainerStatuses { + if container.Name == containerName { + decoded.ContainerId = container.ContainerID + decoded.ContainerName = containerName + break + } + } + if len(decoded.ContainerId) == 0 { + err = errors.Wrapf(ErrContainerNotFound, "container with id %s not found", record.Id) + return + } + + decoded.PbClient, err = d.ChaosDaemonClientBuilder.Build(ctx, &pod, &types.NamespacedName{ + Namespace: obj.GetNamespace(), + Name: obj.GetName(), + }) + if err != nil { + return + } + + return +} diff --git a/controllers/common/condition/condition_suite_test.go b/controllers/common/condition/condition_suite_test.go new file mode 100644 index 0000000000..01f84e9235 --- /dev/null +++ b/controllers/common/condition/condition_suite_test.go @@ -0,0 +1,28 @@ +// Copyright 2023 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package condition_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestCondition(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Condition Suite") +} diff --git a/controllers/common/condition/controller.go b/controllers/common/condition/controller.go new file mode 100644 index 0000000000..2ae2fc8e9c --- /dev/null +++ b/controllers/common/condition/controller.go @@ -0,0 +1,168 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package condition + +import ( + "context" + "reflect" + + "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +// Reconciler for common chaos +type Reconciler struct { + // Object is used to mark the target type of this Reconciler + Object runtime.Object + + // Client is used to operate on the Kubernetes cluster + client.Client + + Recorder record.EventRecorder + + Log logr.Logger +} + +type StatusAndReason struct { + Status corev1.ConditionStatus + Reason string +} + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject) + if err := r.Client.Get(ctx, req.NamespacedName, obj); err != nil { + if apierrors.IsNotFound(err) { + r.Log.Info("chaos not found") + } else { + // TODO: handle this error + r.Log.Error(err, "unable to get chaos") + } + return ctrl.Result{}, nil + } + + updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + conditionMap := make(map[v1alpha1.ChaosConditionType]StatusAndReason) + for _, c := range obj.GetStatus().Conditions { + conditionMap[c.Type] = StatusAndReason{ + Status: c.Status, + Reason: c.Reason, + } + } + + newConditionMap := diffConditions(obj) + + if !reflect.DeepEqual(newConditionMap, conditionMap) { + conditions := make([]v1alpha1.ChaosCondition, 0, 5) + for k, v := range newConditionMap { + conditions = append(conditions, v1alpha1.ChaosCondition{ + Type: k, + Status: v.Status, + Reason: v.Reason, + }) + } + + r.Log.Info("updating conditions", "conditions", conditions) + obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject) + + if err := r.Client.Get(ctx, req.NamespacedName, obj); err != nil { + r.Log.Error(err, "unable to get chaos") + return err + } + + obj.GetStatus().Conditions = conditions + return r.Client.Update(ctx, obj) + } + + return nil + }) + + if updateError != nil { + r.Log.Error(updateError, "fail to update") + r.Recorder.Eventf(obj, "Normal", "Failed", "Failed to update conditions: %s", updateError.Error()) + return ctrl.Result{}, nil + } + + return ctrl.Result{}, nil +} + +func diffConditions(obj v1alpha1.InnerObject) (newConditionMap map[v1alpha1.ChaosConditionType]StatusAndReason) { + records := obj.GetStatus().Experiment.Records + newConditionMap = make(map[v1alpha1.ChaosConditionType]StatusAndReason) + + if records != nil { + newConditionMap[v1alpha1.ConditionSelected] = StatusAndReason{ + Status: corev1.ConditionTrue, + } + } else { + newConditionMap[v1alpha1.ConditionSelected] = StatusAndReason{ + Status: corev1.ConditionFalse, + } + } + + // If records is `nil`, we don't need to check the `allInjected` and `allRecovered` conditions. + allInjected := corev1.ConditionFalse + if records != nil && every(records, func(record *v1alpha1.Record) bool { + return record.Phase == v1alpha1.Injected + }) { + allInjected = corev1.ConditionTrue + } + + allRecovered := corev1.ConditionFalse + if records != nil && every(records, func(record *v1alpha1.Record) bool { + return record.Phase == v1alpha1.NotInjected + }) { + allRecovered = corev1.ConditionTrue + } + + newConditionMap[v1alpha1.ConditionAllInjected] = StatusAndReason{ + Status: allInjected, + } + newConditionMap[v1alpha1.ConditionAllRecovered] = StatusAndReason{ + Status: allRecovered, + } + + if obj.IsPaused() { + newConditionMap[v1alpha1.ConditionPaused] = StatusAndReason{ + Status: corev1.ConditionTrue, + } + } else { + newConditionMap[v1alpha1.ConditionPaused] = StatusAndReason{ + Status: corev1.ConditionFalse, + } + } + + return +} + +// every returns true if all elements in the given slice satisfy the given condition. +// +// In this package, we use it to check if all records are injected or recovered. +func every[T any](arr []T, condition func(T) bool) bool { + for _, item := range arr { + if !condition(item) { + return false + } + } + return true +} diff --git a/controllers/common/condition/controller_test.go b/controllers/common/condition/controller_test.go new file mode 100644 index 0000000000..f53a540eaa --- /dev/null +++ b/controllers/common/condition/controller_test.go @@ -0,0 +1,77 @@ +// Copyright 2023 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package condition + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +var _ = Describe("Test condition controller", func() { + reconciler := Reconciler{ + Object: &v1alpha1.PodChaos{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + v1alpha1.PauseAnnotationKey: "true", + }, + }, + }, + } + + Context("Test diffConditions", func() { + It("selected/allInjected/allRecovered state should be false when records is empty", func() { + newConditionMap := diffConditions(reconciler.Object.DeepCopyObject().(v1alpha1.InnerObject)) + + Expect(newConditionMap[v1alpha1.ConditionSelected].Status).To(Equal(corev1.ConditionFalse)) + Expect(newConditionMap[v1alpha1.ConditionAllInjected].Status).To(Equal(corev1.ConditionFalse)) + Expect(newConditionMap[v1alpha1.ConditionAllRecovered].Status).To(Equal(corev1.ConditionFalse)) + }) + + It("Paused state should be true when pause annotation is true", func() { + obj := reconciler.Object.DeepCopyObject().(v1alpha1.InnerObject) + obj.SetAnnotations(map[string]string{ + v1alpha1.PauseAnnotationKey: "true", + }) + newConditionMap := diffConditions(obj) + + Expect(newConditionMap[v1alpha1.ConditionPaused].Status).To(Equal(corev1.ConditionTrue)) + }) + + It("AllInjected state should be true when all records are injected", func() { + obj := reconciler.Object.DeepCopyObject().(v1alpha1.InnerObject) + obj.GetStatus().Experiment.Records = append(obj.GetStatus().Experiment.Records, &v1alpha1.Record{ + Phase: v1alpha1.Injected, + }) + newConditionMap := diffConditions(obj) + + Expect(newConditionMap[v1alpha1.ConditionAllInjected].Status).To(Equal(corev1.ConditionTrue)) + }) + + It("AllRecovered state should be true when all records are recovered", func() { + obj := reconciler.Object.DeepCopyObject().(v1alpha1.InnerObject) + obj.GetStatus().Experiment.Records = append(obj.GetStatus().Experiment.Records, &v1alpha1.Record{ + Phase: v1alpha1.NotInjected, + }) + newConditionMap := diffConditions(obj) + + Expect(newConditionMap[v1alpha1.ConditionAllRecovered].Status).To(Equal(corev1.ConditionTrue)) + }) + }) +}) diff --git a/controllers/common/condition/step.go b/controllers/common/condition/step.go new file mode 100644 index 0000000000..9ee53848ae --- /dev/null +++ b/controllers/common/condition/step.go @@ -0,0 +1,40 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package condition + +import ( + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/chaos-mesh/chaos-mesh/controllers/common/pipeline" + "github.com/chaos-mesh/chaos-mesh/controllers/config" +) + +func Step(ctx *pipeline.PipelineContext) reconcile.Reconciler { + setupLog := ctx.Logger.WithName("setup-condition") + name := ctx.Object.Name + "-condition" + if !config.ShouldSpawnController(name) { + return nil + } + + setupLog.Info("setting up controller", "name", name) + + return &Reconciler{ + Object: ctx.Object.Object, + Client: ctx.Client, + Recorder: ctx.Mgr.GetEventRecorderFor("condition"), + Log: ctx.Logger.WithName("condition"), + } +} diff --git a/controllers/common/desiredphase/README.md b/controllers/common/desiredphase/README.md new file mode 100644 index 0000000000..2341d21df2 --- /dev/null +++ b/controllers/common/desiredphase/README.md @@ -0,0 +1,8 @@ +# DesiredPhase Controller + +This controller will control the `.Status.Experiment.DesiredPhase` field with the steps below: + +1. if the `desiredPhase` is empty, set it to "running" and go to step 4 +2. if duration exceeded, set `desiredPhase` to "stopped" and go the step 4 +3. if it has been paused, set `desiredPhase` to "stopped"; if not, set it to "running". +4. if the `desiredPhase` has been updated, sync the difference to the kubernetes server. diff --git a/controllers/common/desiredphase/controller.go b/controllers/common/desiredphase/controller.go new file mode 100644 index 0000000000..be6e3c88a7 --- /dev/null +++ b/controllers/common/desiredphase/controller.go @@ -0,0 +1,165 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package desiredphase + +import ( + "context" + "time" + + "github.com/go-logr/logr" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" +) + +// Reconciler for common chaos +type Reconciler struct { + // Object is used to mark the target type of this Reconciler + Object v1alpha1.InnerObject + + // Client is used to operate on the Kubernetes cluster + client.Client + + Recorder recorder.ChaosRecorder + Log logr.Logger +} + +// Reconcile the common chaos +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject) + + if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil { + if apierrors.IsNotFound(err) { + r.Log.Info("chaos not found") + } else { + // TODO: handle this error + r.Log.Error(err, "unable to get chaos") + } + return ctrl.Result{}, nil + } + + reconcileInfo := &reconcileInfo{ + obj: obj, + Reconciler: r, + shouldUpdate: false, + } + return reconcileInfo.Reconcile(req) +} + +type reconcileInfo struct { + obj v1alpha1.InnerObject + + *Reconciler + shouldUpdate bool + requeueAfter time.Duration +} + +func (info *reconcileInfo) GetCreationTimestamp() metav1.Time { + return info.obj.GetCreationTimestamp() +} + +func (info *reconcileInfo) CalcDesiredPhase() (v1alpha1.DesiredPhase, []recorder.ChaosEvent) { + events := []recorder.ChaosEvent{} + + // Consider the finalizers + if info.obj.IsDeleted() { + if info.obj.GetStatus().Experiment.DesiredPhase != v1alpha1.StoppedPhase { + events = append(events, recorder.Deleted{}) + } + return v1alpha1.StoppedPhase, events + } + + if info.obj.IsOneShot() { + // An oneshot chaos should always be in running phase, so that it cannot + // be applied multiple times or cause other bugs :( + return v1alpha1.RunningPhase, events + } + + // Consider the duration + now := time.Now() + + durationExceeded, untilStop, err := info.obj.DurationExceeded(now) + if err != nil { + info.Log.Error(err, "failed to parse duration") + } + if durationExceeded { + if info.obj.GetStatus().Experiment.DesiredPhase != v1alpha1.StoppedPhase { + events = append(events, recorder.TimeUp{}) + } + return v1alpha1.StoppedPhase, events + } + + info.requeueAfter = untilStop + + // Then decide the pause logic + if info.obj.IsPaused() { + if info.obj.GetStatus().Experiment.DesiredPhase != v1alpha1.StoppedPhase { + events = append(events, recorder.Paused{}) + } + return v1alpha1.StoppedPhase, events + } + + if info.obj.GetStatus().Experiment.DesiredPhase != v1alpha1.RunningPhase { + events = append(events, recorder.Started{}) + } + return v1alpha1.RunningPhase, events +} + +func (info *reconcileInfo) Reconcile(req ctrl.Request) (ctrl.Result, error) { + desiredPhase, events := info.CalcDesiredPhase() + + info.Log.Info("modify desiredPhase", "desiredPhase", desiredPhase) + if info.obj.GetStatus().Experiment.DesiredPhase != desiredPhase { + for _, ev := range events { + info.Recorder.Event(info.obj, ev) + } + + updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + obj := info.Object.DeepCopyObject().(v1alpha1.InnerObject) + + if err := info.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil { + info.Log.Error(err, "unable to get chaos") + return err + } + + if obj.GetStatus().Experiment.DesiredPhase != desiredPhase { + obj.GetStatus().Experiment.DesiredPhase = desiredPhase + info.Log.Info("update object", "namespace", obj.GetNamespace(), "name", obj.GetName()) + return info.Client.Update(context.TODO(), obj) + } + + return nil + }) + if updateError != nil { + info.Log.Error(updateError, "fail to update") + info.Recorder.Event(info.obj, recorder.Failed{ + Activity: "update desiredphase", + Err: updateError.Error(), + }) + return ctrl.Result{}, nil + } + + info.Recorder.Event(info.obj, recorder.Updated{ + Field: "desiredPhase", + }) + } + return ctrl.Result{RequeueAfter: info.requeueAfter}, nil +} diff --git a/controllers/common/desiredphase/step.go b/controllers/common/desiredphase/step.go new file mode 100644 index 0000000000..a3e1c05cab --- /dev/null +++ b/controllers/common/desiredphase/step.go @@ -0,0 +1,40 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package desiredphase + +import ( + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/chaos-mesh/chaos-mesh/controllers/common/pipeline" + "github.com/chaos-mesh/chaos-mesh/controllers/config" +) + +func Step(ctx *pipeline.PipelineContext) reconcile.Reconciler { + setupLog := ctx.Logger.WithName("setup-desiredphase") + name := ctx.Object.Name + "-desiredphase" + if !config.ShouldSpawnController(name) { + return nil + } + + setupLog.Info("setting up controller", "name", name) + + return &Reconciler{ + Object: ctx.Object.Object, + Client: ctx.Client, + Recorder: ctx.RecorderBuilder.Build("desiredphase"), + Log: ctx.Logger.WithName("desiredphase"), + } +} diff --git a/controllers/common/desiredphase_test.go b/controllers/common/desiredphase_test.go new file mode 100644 index 0000000000..f86d0491f8 --- /dev/null +++ b/controllers/common/desiredphase_test.go @@ -0,0 +1,186 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package common + +import ( + "context" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/util/retry" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var _ = Describe("Schedule", func() { + + BeforeEach(func() { + // Add any setup steps that needs to be executed before each test + }) + + AfterEach(func() { + // Add any teardown steps that needs to be executed after each test + }) + + Context("Setting phase", func() { + It("should set phase to running", func() { + key := types.NamespacedName{ + Name: "foo1", + Namespace: "default", + } + duration := "10s" + chaos := &v1alpha1.TimeChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo1", + Namespace: "default", + }, + Spec: v1alpha1.TimeChaosSpec{ + TimeOffset: "100ms", + ClockIds: []string{"CLOCK_REALTIME"}, + Duration: &duration, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Mode: v1alpha1.OneMode, + }, + }, + }, + } + + By("creating a chaos") + { + Expect(k8sClient.Create(context.TODO(), chaos)).To(Succeed()) + } + + By("Reconciling desired phase") + { + err := wait.Poll(time.Second*1, time.Second*10, func() (ok bool, err error) { + err = k8sClient.Get(context.TODO(), key, chaos) + if err != nil { + return false, err + } + return chaos.GetStatus().Experiment.DesiredPhase == v1alpha1.RunningPhase, nil + }) + Expect(err).ToNot(HaveOccurred()) + err = wait.Poll(time.Second*1, time.Second*10, func() (ok bool, err error) { + err = k8sClient.Get(context.TODO(), key, chaos) + if err != nil { + return false, err + } + return chaos.GetStatus().Experiment.DesiredPhase == v1alpha1.StoppedPhase, nil + }) + Expect(err).ToNot(HaveOccurred()) + } + + By("deleting the created object") + { + Expect(k8sClient.Delete(context.TODO(), chaos)).To(Succeed()) + } + }) + It("should stop paused chaos", func() { + key := types.NamespacedName{ + Name: "foo2", + Namespace: "default", + } + duration := "1000s" + chaos := &v1alpha1.TimeChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo2", + Namespace: "default", + }, + Spec: v1alpha1.TimeChaosSpec{ + TimeOffset: "100ms", + ClockIds: []string{"CLOCK_REALTIME"}, + Duration: &duration, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Mode: v1alpha1.OneMode, + }, + }, + }, + } + + By("creating a chaos") + { + Expect(k8sClient.Create(context.TODO(), chaos)).To(Succeed()) + } + + By("Reconciling desired phase") + { + err := wait.Poll(time.Second*1, time.Second*10, func() (ok bool, err error) { + err = k8sClient.Get(context.TODO(), key, chaos) + if err != nil { + return false, err + } + return chaos.GetStatus().Experiment.DesiredPhase == v1alpha1.RunningPhase, nil + }) + Expect(err).ToNot(HaveOccurred()) + } + By("Pause chaos") + { + err := retry.RetryOnConflict(retry.DefaultRetry, func() (err error) { + err = k8sClient.Get(context.TODO(), key, chaos) + if err != nil { + return err + } + chaos.SetAnnotations(map[string]string{v1alpha1.PauseAnnotationKey: "true"}) + return k8sClient.Update(context.TODO(), chaos) + }) + Expect(err).ToNot(HaveOccurred()) + err = wait.Poll(time.Second*5, time.Second*60, func() (ok bool, err error) { + err = k8sClient.Get(context.TODO(), key, chaos) + if err != nil { + return false, err + } + return chaos.GetStatus().Experiment.DesiredPhase == v1alpha1.StoppedPhase, nil + }) + Expect(err).ToNot(HaveOccurred()) + } + + By("Resume chaos") + { + err := retry.RetryOnConflict(retry.DefaultRetry, func() (err error) { + err = k8sClient.Get(context.TODO(), key, chaos) + if err != nil { + return err + } + chaos.SetAnnotations(map[string]string{v1alpha1.PauseAnnotationKey: "false"}) + return k8sClient.Update(context.TODO(), chaos) + }) + Expect(err).ToNot(HaveOccurred()) + err = wait.Poll(time.Second*5, time.Second*60, func() (ok bool, err error) { + err = k8sClient.Get(context.TODO(), key, chaos) + if err != nil { + return false, err + } + return chaos.GetStatus().Experiment.DesiredPhase == v1alpha1.RunningPhase, nil + }) + Expect(err).ToNot(HaveOccurred()) + } + + By("deleting the created object") + { + Expect(k8sClient.Delete(context.TODO(), chaos)).To(Succeed()) + } + }) + }) +}) diff --git a/controllers/common/finalizers/README.md b/controllers/common/finalizers/README.md new file mode 100644 index 0000000000..28c4c580cd --- /dev/null +++ b/controllers/common/finalizers/README.md @@ -0,0 +1,8 @@ +# Death Controller + +Death controller controls the `.ObjectMeta.Finalizers` field: + +1. If the object don't have a finalizer, add one for it. +2. If the finalizer has been updated, upload them to kubernetes server. +3. If the object has been deleted, and it includes `clenFinalizerForced` annotation, removes the finalizer, +or iterates over the `records`, and if all of them are "not injected", remove the finalizer. diff --git a/controllers/common/finalizers/controller.go b/controllers/common/finalizers/controller.go new file mode 100644 index 0000000000..1de364c62f --- /dev/null +++ b/controllers/common/finalizers/controller.go @@ -0,0 +1,160 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package finalizers + +import ( + "context" + + "github.com/go-logr/logr" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" +) + +const ( + // AnnotationCleanFinalizer key + AnnotationCleanFinalizer = `chaos-mesh.chaos-mesh.org/cleanFinalizer` + // AnnotationCleanFinalizerForced value + AnnotationCleanFinalizerForced = `forced` + + RecordFinalizer = "chaos-mesh/records" +) + +// ReconcilerMeta defines the meta of InitReconciler and CleanReconciler struct. +type ReconcilerMeta struct { + // Object is used to mark the target type of this Reconciler + Object v1alpha1.InnerObject + + // Client is used to operate on the Kubernetes cluster + client.Client + + Recorder recorder.ChaosRecorder + + Log logr.Logger +} + +// InitReconciler for common chaos to init the finalizer +type InitReconciler struct { + ReconcilerMeta +} + +// Reconcile the common chaos to init the finalizer +func (r *InitReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject) + + if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil { + if apierrors.IsNotFound(err) { + r.Log.Info("chaos not found") + } else { + // TODO: handle this error + r.Log.Error(err, "unable to get chaos") + } + return ctrl.Result{}, nil + } + + if !obj.IsDeleted() { + if !ContainsFinalizer(obj.(metav1.Object), RecordFinalizer) { + r.Recorder.Event(obj, recorder.FinalizerInited{}) + finalizers := append(obj.GetFinalizers(), RecordFinalizer) + return updateFinalizer(r.ReconcilerMeta, obj, req, finalizers) + } + } + + return ctrl.Result{}, nil +} + +// CleanReconciler for common chaos to clean the finalizer +type CleanReconciler struct { + ReconcilerMeta +} + +// Reconcile the common chaos to clean the finalizer +func (r *CleanReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject) + + if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil { + if apierrors.IsNotFound(err) { + r.Log.Info("chaos not found") + } else { + // TODO: handle this error + r.Log.Error(err, "unable to get chaos") + } + return ctrl.Result{}, nil + } + + finalizers := obj.GetFinalizers() + records := obj.GetStatus().Experiment.Records + if obj.IsDeleted() { + resumed := true + for _, record := range records { + if record.Phase != v1alpha1.NotInjected { + resumed = false + } + } + + if obj.GetAnnotations()[AnnotationCleanFinalizer] == AnnotationCleanFinalizerForced || (resumed && len(finalizers) != 0) { + r.Recorder.Event(obj, recorder.FinalizerRemoved{}) + finalizers = []string{} + return updateFinalizer(r.ReconcilerMeta, obj, req, finalizers) + } + } + + return ctrl.Result{}, nil +} + +func updateFinalizer(r ReconcilerMeta, obj v1alpha1.InnerObject, req ctrl.Request, finalizers []string) (ctrl.Result, error) { + updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject) + + if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil { + r.Log.Error(err, "unable to get chaos") + return err + } + + obj.SetFinalizers(finalizers) + return r.Client.Update(context.TODO(), obj) + }) + if updateError != nil { + // TODO: handle this error + r.Log.Error(updateError, "fail to update") + r.Recorder.Event(obj, recorder.Failed{ + Activity: "update finalizer", + Err: "updateError.Error()", + }) + return ctrl.Result{}, nil + } + + r.Recorder.Event(obj, recorder.Updated{ + Field: "finalizer", + }) + return ctrl.Result{}, nil +} + +// ContainsFinalizer checks an Object that the provided finalizer is present. +func ContainsFinalizer(o metav1.Object, finalizer string) bool { + f := o.GetFinalizers() + for _, e := range f { + if e == finalizer { + return true + } + } + return false +} diff --git a/controllers/common/finalizers/step.go b/controllers/common/finalizers/step.go new file mode 100644 index 0000000000..f4b3511039 --- /dev/null +++ b/controllers/common/finalizers/step.go @@ -0,0 +1,61 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package finalizers + +import ( + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/chaos-mesh/chaos-mesh/controllers/common/pipeline" + "github.com/chaos-mesh/chaos-mesh/controllers/config" +) + +func InitStep(ctx *pipeline.PipelineContext) reconcile.Reconciler { + setupLog := ctx.Logger.WithName("setup-initFinalizers") + name := ctx.Object.Name + "-initFinalizers" + if !config.ShouldSpawnController(name) { + return nil + } + + setupLog.Info("setting up controller", "name", name) + + return &InitReconciler{ + ReconcilerMeta{ + Object: ctx.Object.Object, + Client: ctx.Client, + Recorder: ctx.RecorderBuilder.Build("initFinalizers"), + Log: ctx.Logger.WithName("initFinalizers"), + }, + } +} + +func CleanStep(ctx *pipeline.PipelineContext) reconcile.Reconciler { + setupLog := ctx.Logger.WithName("setup-cleanFinalizers") + name := ctx.Object.Name + "-cleanFinalizers" + if !config.ShouldSpawnController(name) { + return nil + } + + setupLog.Info("setting up controller", "name", name) + + return &CleanReconciler{ + ReconcilerMeta{ + Object: ctx.Object.Object, + Client: ctx.Client, + Recorder: ctx.RecorderBuilder.Build("initFinalizers"), + Log: ctx.Logger.WithName("initFinalizers"), + }, + } +} diff --git a/controllers/common/finalizers_test.go b/controllers/common/finalizers_test.go new file mode 100644 index 0000000000..679fa4d44e --- /dev/null +++ b/controllers/common/finalizers_test.go @@ -0,0 +1,92 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package common + +import ( + "context" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/common/finalizers" +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var _ = Describe("Finalizer", func() { + + BeforeEach(func() { + // Add any setup steps that needs to be executed before each test + }) + + AfterEach(func() { + // Add any teardown steps that needs to be executed after each test + }) + + Context("Adding finalizer", func() { + It("should add record finalizer", func() { + key := types.NamespacedName{ + Name: "final1", + Namespace: "default", + } + duration := "1000s" + chaos := &v1alpha1.TimeChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "final1", + Namespace: "default", + }, + Spec: v1alpha1.TimeChaosSpec{ + TimeOffset: "100ms", + ClockIds: []string{"CLOCK_REALTIME"}, + Duration: &duration, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Mode: v1alpha1.OneMode, + }, + }, + }, + } + + By("creating a chaos") + { + Expect(k8sClient.Create(context.TODO(), chaos)).To(Succeed()) + } + + By("Adding finalizers") + { + err := wait.Poll(time.Second*1, time.Second*10, func() (ok bool, err error) { + err = k8sClient.Get(context.TODO(), key, chaos) + if err != nil { + return false, err + } + return len(chaos.GetObjectMeta().GetFinalizers()) > 0 && chaos.GetObjectMeta().GetFinalizers()[0] == finalizers.RecordFinalizer, nil + }) + Expect(err).ToNot(HaveOccurred()) + } + + By("deleting the created object") + { + Expect(k8sClient.Delete(context.TODO(), chaos)).To(Succeed()) + } + }) + }) +}) diff --git a/controllers/common/fx.go b/controllers/common/fx.go new file mode 100644 index 0000000000..bcd6b6c0cc --- /dev/null +++ b/controllers/common/fx.go @@ -0,0 +1,260 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package common + +import ( + "context" + "reflect" + + "github.com/go-logr/logr" + "go.uber.org/fx" + k8sTypes "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + chaosimpltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/common/pipeline" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/types" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/builder" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" + "github.com/chaos-mesh/chaos-mesh/pkg/selector" +) + +type Params struct { + fx.In + + Mgr ctrl.Manager + Client client.Client + Logger logr.Logger + Selector *selector.Selector + RecorderBuilder *recorder.RecorderBuilder + Impls []*chaosimpltypes.ChaosImplPair `group:"impl"` + Reader client.Reader `name:"no-cache"` + Steps []pipeline.PipelineStep +} + +func Bootstrap(params Params) error { + logger := params.Logger + pairs := params.Impls + mgr := params.Mgr + kubeclient := params.Client + reader := params.Reader + selector := params.Selector + recorderBuilder := params.RecorderBuilder + + setupLog := logger.WithName("setup-common") + for _, pair := range pairs { + name := pair.Name + "-records" + if !config.ShouldSpawnController(name) { + return nil + } + + setupLog.Info("setting up controller", "resource-name", pair.Name) + + builder := builder.Default(mgr). + For(pair.Object). + Named(pair.Name + "-pipeline") + + // for common CRDs, since we don't want to reconcile the object, + // when we only change the object.status.experiment.records[].events + predicaters := []predicate.Predicate{StatusRecordEventsChangePredicate{}} + + // Add owning resources + if len(pair.Controlls) > 0 { + pair := pair + for _, obj := range pair.Controlls { + builder.Watches(obj, + handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request { + reqs := []reconcile.Request{} + objName := k8sTypes.NamespacedName{ + Namespace: obj.GetNamespace(), + Name: obj.GetName(), + } + + list := pair.ObjectList.DeepCopyList() + err := kubeclient.List(context.TODO(), list) + if err != nil { + setupLog.Error(err, "fail to list object") + } + + items := reflect.ValueOf(list).Elem().FieldByName("Items") + for i := 0; i < items.Len(); i++ { + item := items.Index(i).Addr().Interface().(v1alpha1.InnerObjectWithSelector) + for _, record := range item.GetStatus().Experiment.Records { + namespacedName, err := controller.ParseNamespacedName(record.Id) + if err != nil { + setupLog.Error(err, "failed to parse record", "record", record.Id) + continue + } + if namespacedName == objName { + id := k8sTypes.NamespacedName{ + Namespace: item.GetNamespace(), + Name: item.GetName(), + } + setupLog.Info("mapping requests", "source", objName, "target", id) + reqs = append(reqs, reconcile.Request{ + NamespacedName: id, + }) + } + } + } + return reqs + }), + ) + } + predicaters = append(predicaters, PickChildCRDPredicate{}) + } + + pipe := pipeline.NewPipeline(&pipeline.PipelineContext{ + Logger: logger, + Object: &types.Object{ + Name: pair.Name, + Object: pair.Object, + }, + Impl: pair.Impl, + Mgr: mgr, + Client: kubeclient, + Reader: reader, + RecorderBuilder: recorderBuilder, + Selector: selector, + }) + + pipe.AddSteps(params.Steps...) + builder = builder.WithEventFilter(predicate.And(predicate.Or(predicaters...), RemoteChaosPredicate{})) + err := builder.Complete(pipe) + if err != nil { + return err + } + + } + + return nil +} + +// PickChildCRDPredicate allows events to trigger the Reconcile of Chaos CRD, +// for example: +// Reconcile of IOChaos could be triggered by changes on PodIOChaos. +// For now, we have PodHttpChaos/PodIOChaos/PodNetworkChaos which require to follow this pattern. +type PickChildCRDPredicate struct { + predicate.Funcs +} + +// Update implements UpdateEvent filter for child CRD. +func (PickChildCRDPredicate) Update(e event.UpdateEvent) bool { + switch e.ObjectNew.(type) { + case *v1alpha1.PodHttpChaos, *v1alpha1.PodIOChaos, *v1alpha1.PodNetworkChaos: + return true + } + return false +} + +// StatusRecordEventsChangePredicate skip the update event, +// when we Only update object.status.experiment.records[].events +type StatusRecordEventsChangePredicate struct { + predicate.Funcs +} + +// Update implements UpdateEvent filter for update to filter the events +// which we Only update object.status.experiment.records[].events +func (StatusRecordEventsChangePredicate) Update(e event.UpdateEvent) bool { + objNew, ok := e.ObjectNew.DeepCopyObject().(v1alpha1.StatefulObject) + if !ok { + return false + } + objOld, ok := e.ObjectOld.DeepCopyObject().(v1alpha1.StatefulObject) + if !ok { + return false + } + statusNew := objNew.GetStatus() + statusOld := objOld.GetStatus() + if statusNew == nil || statusOld == nil { + return true + } + objNew.SetGeneration(0) + objOld.SetGeneration(0) + objNew.SetResourceVersion("") + objOld.SetResourceVersion("") + for i := range statusNew.Experiment.Records { + statusNew.Experiment.Records[i].Events = nil + } + for i := range statusOld.Experiment.Records { + statusOld.Experiment.Records[i].Events = nil + } + return !reflect.DeepEqual(objNew, objOld) +} + +type RemoteChaosPredicate struct { + predicate.Funcs +} + +func (RemoteChaosPredicate) Create(e event.CreateEvent) bool { + obj, ok := e.Object.DeepCopyObject().(v1alpha1.RemoteObject) + if !ok { + return true + } + + if obj.GetRemoteCluster() == "" { + return true + } + + return false +} + +func (RemoteChaosPredicate) Update(e event.UpdateEvent) bool { + obj, ok := e.ObjectNew.DeepCopyObject().(v1alpha1.RemoteObject) + if !ok { + return true + } + + if obj.GetRemoteCluster() == "" { + return true + } + + return false +} + +func (RemoteChaosPredicate) Delete(e event.DeleteEvent) bool { + obj, ok := e.Object.DeepCopyObject().(v1alpha1.RemoteObject) + if !ok { + return true + } + + if obj.GetRemoteCluster() == "" { + return true + } + + return false +} + +func (RemoteChaosPredicate) Generic(e event.GenericEvent) bool { + obj, ok := e.Object.DeepCopyObject().(v1alpha1.RemoteObject) + if !ok { + return true + } + + if obj.GetRemoteCluster() == "" { + return true + } + + return false +} diff --git a/controllers/common/fx_test.go b/controllers/common/fx_test.go new file mode 100644 index 0000000000..716fb1825a --- /dev/null +++ b/controllers/common/fx_test.go @@ -0,0 +1,167 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package common + +import ( + "testing" + + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/event" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +func TestStatusRecordEventsChangePredicateEventsChange(t *testing.T) { + g := NewWithT(t) + // should skip event, if we Only the object.status.experiment.records[].events + // notice: ResourceVersion and Generation will be changed by k8s itself + newObj := &v1alpha1.HTTPChaos{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "1", + Generation: 1, + }, + Spec: v1alpha1.HTTPChaosSpec{}, + Status: v1alpha1.HTTPChaosStatus{ + ChaosStatus: v1alpha1.ChaosStatus{ + Conditions: nil, + Experiment: v1alpha1.ExperimentStatus{ + DesiredPhase: "", + Records: []*v1alpha1.Record{ + { + Id: "", + SelectorKey: "", + Phase: "", + InjectedCount: 0, + RecoveredCount: 0, + Events: []v1alpha1.RecordEvent{ + { + Type: v1alpha1.TypeFailed, + Operation: v1alpha1.Apply, + Message: "apply failed", + Timestamp: nil, + }, + }, + }, + }, + }, + }, + Instances: nil, + }, + } + oldObj := &v1alpha1.HTTPChaos{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "0", + Generation: 0, + }, + Spec: v1alpha1.HTTPChaosSpec{}, + Status: v1alpha1.HTTPChaosStatus{ + ChaosStatus: v1alpha1.ChaosStatus{ + Conditions: nil, + Experiment: v1alpha1.ExperimentStatus{ + DesiredPhase: "", + Records: []*v1alpha1.Record{ + { + Id: "", + SelectorKey: "", + Phase: "", + InjectedCount: 0, + RecoveredCount: 0, + Events: nil, + }, + }, + }, + }, + Instances: nil, + }, + } + + predicate := StatusRecordEventsChangePredicate{} + updateEvent := event.UpdateEvent{ObjectOld: oldObj, ObjectNew: newObj} + pick := predicate.Update(updateEvent) + g.Expect(pick).Should(Equal(false)) +} + +func TestStatusRecordEventsChangePredicatePhaseChange(t *testing.T) { + g := NewWithT(t) + + newObj := &v1alpha1.HTTPChaos{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "1", + Generation: 1, + }, + Spec: v1alpha1.HTTPChaosSpec{}, + Status: v1alpha1.HTTPChaosStatus{ + ChaosStatus: v1alpha1.ChaosStatus{ + Conditions: nil, + Experiment: v1alpha1.ExperimentStatus{ + DesiredPhase: v1alpha1.StoppedPhase, + Records: nil, + }, + }, + Instances: nil, + }, + } + oldObj := &v1alpha1.HTTPChaos{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "0", + Generation: 0, + }, + Spec: v1alpha1.HTTPChaosSpec{}, + Status: v1alpha1.HTTPChaosStatus{ + ChaosStatus: v1alpha1.ChaosStatus{ + Conditions: nil, + Experiment: v1alpha1.ExperimentStatus{ + DesiredPhase: v1alpha1.RunningPhase, + Records: nil, + }, + }, + Instances: nil, + }, + } + + predicate := StatusRecordEventsChangePredicate{} + updateEvent := event.UpdateEvent{ObjectOld: oldObj, ObjectNew: newObj} + pick := predicate.Update(updateEvent) + g.Expect(pick).Should(Equal(true)) +} + +func TestStatusRecordEventsChangePredicateChildCRDs(t *testing.T) { + g := NewWithT(t) + + // should allow the event about "Update" on certain Chaos Resource, v1alpha1.StatefulObject + newObj := &v1alpha1.PodIOChaos{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{}, + Spec: v1alpha1.PodIOChaosSpec{}, + Status: v1alpha1.PodIOChaosStatus{}, + } + oldObj := &v1alpha1.PodIOChaos{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{}, + Spec: v1alpha1.PodIOChaosSpec{}, + Status: v1alpha1.PodIOChaosStatus{}, + } + + predicate := StatusRecordEventsChangePredicate{} + updateEvent := event.UpdateEvent{ObjectOld: oldObj, ObjectNew: newObj} + pick := predicate.Update(updateEvent) + g.Expect(pick).Should(Equal(false)) +} diff --git a/controllers/common/pipeline/README.md b/controllers/common/pipeline/README.md new file mode 100644 index 0000000000..9514f97750 --- /dev/null +++ b/controllers/common/pipeline/README.md @@ -0,0 +1,6 @@ +# Pipeline Controller + +In early implementation of controllers in v2.0, all common controllers are registered respectively +and may be executed by different order, which result in bugs like +[#2449](https://github.com/chaos-mesh/chaos-mesh/issues/2449). So we introduce a pipeline controller +to register them and execute them in a fixed order. diff --git a/controllers/common/pipeline/pipeline.go b/controllers/common/pipeline/pipeline.go new file mode 100644 index 0000000000..acd2e67425 --- /dev/null +++ b/controllers/common/pipeline/pipeline.go @@ -0,0 +1,122 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package pipeline + +import ( + "context" + "time" + + "github.com/go-logr/logr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + chaosimpltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/types" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" + "github.com/chaos-mesh/chaos-mesh/pkg/selector" +) + +type Pipeline struct { + controllers []reconcile.Reconciler + ctx *PipelineContext +} + +type PipelineContext struct { + Object *types.Object + Mgr ctrl.Manager + Client client.Client + client.Reader + + Logger logr.Logger + RecorderBuilder *recorder.RecorderBuilder + Impl chaosimpltypes.ChaosImpl + Selector *selector.Selector +} + +type PipelineStep func(ctx *PipelineContext) reconcile.Reconciler + +func NewPipeline(ctx *PipelineContext) *Pipeline { + return &Pipeline{ + ctx: ctx, + } +} + +func (p *Pipeline) AddSteps(steps ...PipelineStep) { + for _, step := range steps { + reconciler := step(p.ctx) + if reconciler == nil { + return + } + p.controllers = append(p.controllers, reconciler) + } +} + +// Reconcile the steps +func (p *Pipeline) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + var deadline *time.Time + + for _, controller := range p.controllers { + ret, err := controller.Reconcile(ctx, req) + if err != nil { + return ctrl.Result{}, err + } + + p.ctx.Logger.WithName("pipeline").Info("reconcile result", "result", ret) + + if ret.Requeue || deadline != nil && deadline.Before(time.Now()) { + ret.Requeue = true + return ret, nil + } + + if ret.RequeueAfter != 0 { + // The controller wants us to re-enqueue after a certain amount of time, + // and the desiredphase controller will always return a RequeueAfter before the experiment is finished. + // + // So, DO NOT re-queue immediately. + end := time.Now().Add(ret.RequeueAfter) + deadline = minTime(deadline, &end) + } + } + + ret := ctrl.Result{} + + if deadline != nil { + if deadline.Before(time.Now()) { + ret.Requeue = true + } else { + ret.RequeueAfter = time.Until(*deadline) + } + } + + return ret, nil +} + +func minTime(d1, d2 *time.Time) *time.Time { + if d1 == nil { + return d2 + } + + if d2 == nil { + return d1 + } + + if d1.Before(*d2) { + return d1 + } + + return d2 +} diff --git a/controllers/common/records/README.md b/controllers/common/records/README.md new file mode 100644 index 0000000000..0b07f3cd0d --- /dev/null +++ b/controllers/common/records/README.md @@ -0,0 +1,23 @@ +# Records Controller + +Records controller controls the `.Status.Experiment.Records` field with the steps below: + +1. if the `records` are nil, try to select new objects and save to the `records`. +2. iterate over `records`, for every `record`, if the `Phase` of it doesn't match the `DesiredPhase`, try to sync them +through `Apply` or `Recover`, and update the `Phase` accordingly. +3. if the `records` has changed, upload them to the kubernetes server. + +## Design Discussion + +### The implementation of chaos should be simple + +The definition of every chaos should be simple. It needs a configuration, one or more selectors, and an implementation +for a single object. For example, the implementation of PodKill should only kill one pod, but not "select", "iterate" and +delete all of them. These things (like "select", "iterate") should be done in the powerful controller. + +### Selector should be powerful + +1. "Pod" is not the only target of chaos. We could inject chaos on volume, container, pod, ec2 machine... The selector + abstraction should be able to handle the diversity. + +2. One chaos definition should be able to have a lot of selector, e.g. the `NetworkChaos`. diff --git a/controllers/common/records/controller.go b/controllers/common/records/controller.go new file mode 100644 index 0000000000..3e4ec9dae7 --- /dev/null +++ b/controllers/common/records/controller.go @@ -0,0 +1,267 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package records + +import ( + "context" + "reflect" + "strings" + + "github.com/go-logr/logr" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" + "github.com/chaos-mesh/chaos-mesh/pkg/selector" +) + +// Reconciler for chaos records +type Reconciler struct { + Impl types.ChaosImpl + + // Object is used to mark the target type of this Reconciler + Object v1alpha1.InnerObject + + // Client is used to operate on the Kubernetes cluster + client.Client + client.Reader + + Recorder recorder.ChaosRecorder + + Selector *selector.Selector + + Log logr.Logger +} + +type Operation string + +const ( + Apply Operation = "apply" + Recover Operation = "recover" + Nothing Operation = "" +) + +// Reconcile the chaos records +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + obj := r.Object.DeepCopyObject().(v1alpha1.InnerObjectWithSelector) + if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil { + if apierrors.IsNotFound(err) { + r.Log.Info("chaos not found") + } else { + // TODO: handle this error + r.Log.Error(err, "unable to get chaos") + } + return ctrl.Result{}, nil + } + + shouldUpdate := false + + desiredPhase := obj.GetStatus().Experiment.DesiredPhase + records := obj.GetStatus().Experiment.Records + selectors := obj.GetSelectorSpecs() + + logger := r.Log.WithValues("name", obj.GetName(), "namespace", obj.GetNamespace(), "kind", obj.GetObjectKind().GroupVersionKind().Kind) + + if records == nil { + for name, sel := range selectors { + targets, err := r.Selector.Select(context.TODO(), sel) + if err != nil { + logger.Error(err, "fail to select") + r.Recorder.Event(obj, recorder.Failed{ + Activity: "select targets", + Err: err.Error(), + }) + return ctrl.Result{}, nil + } + + if len(targets) == 0 { + logger.Info("no target has been selected") + r.Recorder.Event(obj, recorder.Failed{ + Activity: "select targets", + Err: "no target has been selected", + }) + return ctrl.Result{}, nil + } + + for _, target := range targets { + records = append(records, &v1alpha1.Record{ + Id: target.Id(), + SelectorKey: name, + Phase: v1alpha1.NotInjected, + }) + shouldUpdate = true + } + } + // TODO: dynamic upgrade the records when some of these pods/containers stopped + } + + needRetry := false + for index, record := range records { + var err error + idLogger := logger.WithValues("id", records[index].Id) + idLogger.Info("iterating record", "record", record, "desiredPhase", desiredPhase) + + // The whole running logic is a cycle: + // Not Injected -> Not Injected/* -> Injected -> Injected/* -> Not Injected + // Every step should follow the cycle. For example, if it's in "Not Injected/*" status, and it wants to recover + // then it has to apply and then recover, but not recover directly. + + originalPhase := record.Phase + operation := Nothing + if desiredPhase == v1alpha1.RunningPhase && originalPhase != v1alpha1.Injected { + // The originalPhase has three possible situations: Not Injected, Not Injected/* or Injected/* + // In the first two situations, it should apply, in the last situation, it should recover + + if strings.HasPrefix(string(originalPhase), string(v1alpha1.NotInjected)) { + operation = Apply + } else { + operation = Recover + } + } + if desiredPhase == v1alpha1.StoppedPhase && originalPhase != v1alpha1.NotInjected { + // The originalPhase has three possible situations: Not Injected/*, Injected, or Injected/* + // In the first one situation, it should apply, in the last two situations, it should recover + + if strings.HasPrefix(string(originalPhase), string(v1alpha1.NotInjected)) { + operation = Apply + } else { + operation = Recover + } + } + + if operation == Apply { + idLogger.Info("apply chaos") + record.Phase, err = r.Impl.Apply(context.TODO(), index, records, obj) + if record.Phase != originalPhase { + shouldUpdate = true + } + if err != nil { + // TODO: add backoff and retry mechanism + // but the retry shouldn't block other resource process + idLogger.Error(err, "fail to apply chaos") + applyFailedEvent := newRecordEvent(v1alpha1.TypeFailed, v1alpha1.Apply, err.Error()) + if len(records[index].Events) >= config.ControllerCfg.MaxEvents { + records[index].Events = records[index].Events[1:] + } + records[index].Events = append(records[index].Events, *applyFailedEvent) + r.Recorder.Event(obj, recorder.Failed{ + Activity: "apply chaos", + Err: err.Error(), + }) + needRetry = true + // if the impl.Apply() failed, we need to update the status to update the records[index].Events + shouldUpdate = true + continue + } + + if record.Phase == v1alpha1.Injected { + records[index].InjectedCount++ + applySucceedEvent := newRecordEvent(v1alpha1.TypeSucceeded, v1alpha1.Apply, "") + if len(records[index].Events) >= config.ControllerCfg.MaxEvents { + records[index].Events = records[index].Events[1:] + } + records[index].Events = append(records[index].Events, *applySucceedEvent) + r.Recorder.Event(obj, recorder.Applied{ + Id: records[index].Id, + }) + } + } else if operation == Recover { + idLogger.Info("recover chaos") + record.Phase, err = r.Impl.Recover(context.TODO(), index, records, obj) + if record.Phase != originalPhase { + shouldUpdate = true + } + if err != nil { + // TODO: add backoff and retry mechanism + // but the retry shouldn't block other resource process + idLogger.Error(err, "fail to recover chaos") + recoverFailedEvent := newRecordEvent(v1alpha1.TypeFailed, v1alpha1.Recover, err.Error()) + if len(records[index].Events) >= config.ControllerCfg.MaxEvents { + records[index].Events = records[index].Events[1:] + } + records[index].Events = append(records[index].Events, *recoverFailedEvent) + r.Recorder.Event(obj, recorder.Failed{ + Activity: "recover chaos", + Err: err.Error(), + }) + needRetry = true + // if the impl.Recover() failed, we need to update the status to update the records[index].Events + shouldUpdate = true + continue + } + + if record.Phase == v1alpha1.NotInjected { + records[index].RecoveredCount++ + recoverSucceedEvent := newRecordEvent(v1alpha1.TypeSucceeded, v1alpha1.Recover, "") + if len(records[index].Events) >= config.ControllerCfg.MaxEvents { + records[index].Events = records[index].Events[1:] + } + records[index].Events = append(records[index].Events, *recoverSucceedEvent) + r.Recorder.Event(obj, recorder.Recovered{ + Id: records[index].Id, + }) + } + } + } + + // TODO: auto generate SetCustomStatus rather than reflect + var customStatus reflect.Value + if objWithStatus, ok := obj.(v1alpha1.InnerObjectWithCustomStatus); ok { + customStatus = reflect.Indirect(reflect.ValueOf(objWithStatus.GetCustomStatus())) + } + if shouldUpdate { + updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + logger.Info("updating records", "records", records) + obj := r.Object.DeepCopyObject().(v1alpha1.InnerObjectWithSelector) + + if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil { + logger.Error(err, "unable to get chaos") + return err + } + + obj.GetStatus().Experiment.Records = records + if objWithStatus, ok := obj.(v1alpha1.InnerObjectWithCustomStatus); ok { + ptrToCustomStatus := objWithStatus.GetCustomStatus() + // TODO: auto generate SetCustomStatus rather than reflect + reflect.Indirect(reflect.ValueOf(ptrToCustomStatus)).Set(reflect.Indirect(customStatus)) + } + return r.Client.Update(context.TODO(), obj) + }) + if updateError != nil { + logger.Error(updateError, "fail to update") + r.Recorder.Event(obj, recorder.Failed{ + Activity: "update records", + Err: updateError.Error(), + }) + return ctrl.Result{Requeue: true}, nil + } + + r.Recorder.Event(obj, recorder.Updated{ + Field: "records", + }) + } + return ctrl.Result{Requeue: needRetry}, nil +} + +func newRecordEvent(eventType v1alpha1.RecordEventType, eventStage v1alpha1.RecordEventOperation, msg string) *v1alpha1.RecordEvent { + return v1alpha1.NewRecordEvent(eventType, eventStage, msg, metav1.Now()) +} diff --git a/controllers/common/records/step.go b/controllers/common/records/step.go new file mode 100644 index 0000000000..31b65c5494 --- /dev/null +++ b/controllers/common/records/step.go @@ -0,0 +1,34 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package records + +import ( + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/chaos-mesh/chaos-mesh/controllers/common/pipeline" +) + +func Step(ctx *pipeline.PipelineContext) reconcile.Reconciler { + return &Reconciler{ + Impl: ctx.Impl, + Object: ctx.Object.Object, + Client: ctx.Client, + Reader: ctx.Reader, + Recorder: ctx.RecorderBuilder.Build("records"), + Selector: ctx.Selector, + Log: ctx.Logger.WithName("records"), + } +} diff --git a/controllers/common/step.go b/controllers/common/step.go new file mode 100644 index 0000000000..444e026ec3 --- /dev/null +++ b/controllers/common/step.go @@ -0,0 +1,34 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package common + +import ( + "github.com/chaos-mesh/chaos-mesh/controllers/common/condition" + "github.com/chaos-mesh/chaos-mesh/controllers/common/desiredphase" + "github.com/chaos-mesh/chaos-mesh/controllers/common/finalizers" + "github.com/chaos-mesh/chaos-mesh/controllers/common/pipeline" + "github.com/chaos-mesh/chaos-mesh/controllers/common/records" +) + +func AllSteps() []pipeline.PipelineStep { + return []pipeline.PipelineStep{ + finalizers.InitStep, + desiredphase.Step, + condition.Step, + records.Step, + finalizers.CleanStep, + } +} diff --git a/controllers/common/suite_test.go b/controllers/common/suite_test.go new file mode 100644 index 0000000000..4a1693a33f --- /dev/null +++ b/controllers/common/suite_test.go @@ -0,0 +1,140 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package common + +import ( + "context" + "os" + "path/filepath" + "testing" + "time" + + "github.com/go-logr/logr" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "go.uber.org/fx" + "k8s.io/client-go/rest" + "k8s.io/kubectl/pkg/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl" + "github.com/chaos-mesh/chaos-mesh/controllers/common/condition" + "github.com/chaos-mesh/chaos-mesh/controllers/common/desiredphase" + "github.com/chaos-mesh/chaos-mesh/controllers/common/finalizers" + "github.com/chaos-mesh/chaos-mesh/controllers/common/pipeline" + "github.com/chaos-mesh/chaos-mesh/controllers/schedule/utils" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/test" + "github.com/chaos-mesh/chaos-mesh/pkg/log" + "github.com/chaos-mesh/chaos-mesh/pkg/selector" +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var app *fx.App +var k8sClient client.Client +var lister *utils.ActiveLister +var cfg *rest.Config +var testEnv *envtest.Environment +var setupLog = ctrl.Log.WithName("setup") + +func TestCommon(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Common suit") +} + +var _ = BeforeSuite(func(ctx SpecContext) { + logf.SetLogger(log.NewZapLoggerWithWriter(GinkgoWriter)) + By("bootstrapping test environment") + t := true + if os.Getenv("USE_EXISTING_CLUSTER") == "true" { + testEnv = &envtest.Environment{ + UseExistingCluster: &t, + } + } else { + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, + } + } + + err := v1alpha1.SchemeBuilder.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + cfg, err = testEnv.Start() + Expect(err).ToNot(HaveOccurred()) + Expect(cfg).ToNot(BeNil()) + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + Expect(err).ToNot(HaveOccurred()) + Expect(k8sClient).ToNot(BeNil()) + + rootLogger, err := log.NewDefaultZapLogger() + Expect(err).ToNot(HaveOccurred()) + By("start application") + app = fx.New( + fx.Options( + fx.Supply(rootLogger), + test.Module, + chaosimpl.AllImpl, + selector.Module, + fx.Provide(chaosdaemon.New), + fx.Provide(func() []pipeline.PipelineStep { + return []pipeline.PipelineStep{finalizers.InitStep, desiredphase.Step, condition.Step, finalizers.CleanStep} + }), + fx.Invoke(Bootstrap), + fx.Supply(cfg), + ), + fx.Invoke(Run), + ) + startCtx, cancel := context.WithTimeout(context.Background(), app.StartTimeout()) + defer cancel() + + if err := app.Start(startCtx); err != nil { + setupLog.Error(err, "fail to start manager") + } + Expect(err).ToNot(HaveOccurred()) + +}, NodeTimeout(60*time.Second)) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + stopCtx, cancel := context.WithTimeout(context.Background(), app.StopTimeout()) + defer cancel() + + if err := app.Stop(stopCtx); err != nil { + setupLog.Error(err, "fail to stop manager") + } + err := testEnv.Stop() + Expect(err).ToNot(HaveOccurred()) +}) + +type RunParams struct { + fx.In + + Mgr ctrl.Manager + Logger logr.Logger +} + +func Run(params RunParams) error { + lister = utils.NewActiveLister(k8sClient, params.Logger) + return nil +} diff --git a/controllers/common/types.go b/controllers/common/types.go deleted file mode 100644 index 10e792276f..0000000000 --- a/controllers/common/types.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package common - -import ( - "context" - "time" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - endpoint "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/util/retry" - - ctrl "sigs.k8s.io/controller-runtime" -) - -const ( - // AnnotationCleanFinalizer key - AnnotationCleanFinalizer = `chaos-mesh.chaos-mesh.org/cleanFinalizer` - // AnnotationCleanFinalizerForced value - AnnotationCleanFinalizerForced = `forced` -) - -const emptyString = "" - -// Reconciler for common chaos -type Reconciler struct { - endpoint.Endpoint - ctx.Context -} - -// NewReconciler would create Reconciler for common chaos -func NewReconciler(req ctrl.Request, e endpoint.Endpoint, ctx ctx.Context) *Reconciler { - ctx.Log = ctx.Log.WithName(req.NamespacedName.String()) - - return &Reconciler{ - Endpoint: e, - Context: ctx, - } -} - -// Reconcile the common chaos -func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { - var err error - - r.Log.Info("Reconciling a common chaos", "name", req.Name, "namespace", req.Namespace) - ctx := context.Background() - - chaos := r.Object() - if err = r.Client.Get(ctx, req.NamespacedName, chaos); err != nil { - r.Log.Error(err, "unable to get chaos") - return ctrl.Result{}, err - } - - status := chaos.GetStatus() - - if chaos.IsDeleted() { - // This chaos was deleted - r.Log.Info("Removing self") - if err = r.Recover(ctx, req, chaos); err != nil { - r.Log.Error(err, "failed to recover chaos") - updateFailedMessage(ctx, r, chaos, err.Error()) - return ctrl.Result{Requeue: true}, err - } - status.Experiment.Phase = v1alpha1.ExperimentPhaseFinished - status.FailedMessage = emptyString - } else if chaos.IsPaused() { - if status.Experiment.Phase == v1alpha1.ExperimentPhaseRunning { - r.Log.Info("Pausing") - - if err = r.Recover(ctx, req, chaos); err != nil { - r.Log.Error(err, "failed to pause chaos") - updateFailedMessage(ctx, r, chaos, err.Error()) - return ctrl.Result{Requeue: true}, err - } - now := time.Now() - status.Experiment.EndTime = &metav1.Time{ - Time: now, - } - if status.Experiment.StartTime != nil { - status.Experiment.Duration = now.Sub(status.Experiment.StartTime.Time).String() - } - } - status.Experiment.Phase = v1alpha1.ExperimentPhasePaused - status.FailedMessage = emptyString - } else if status.Experiment.Phase == v1alpha1.ExperimentPhaseRunning { - r.Log.Info("The common chaos is already running", "name", req.Name, "namespace", req.Namespace) - return ctrl.Result{}, nil - } else { - // Start chaos action - r.Log.Info("Performing Action") - - if err = r.Apply(ctx, req, chaos); err != nil { - r.Log.Error(err, "failed to apply chaos action") - updateFailedMessage(ctx, r, chaos, err.Error()) - - status.Experiment.Phase = v1alpha1.ExperimentPhaseFailed - - updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { - return r.Update(ctx, chaos) - }) - if updateError != nil { - r.Log.Error(updateError, "unable to update chaos finalizers") - updateFailedMessage(ctx, r, chaos, updateError.Error()) - } - - return ctrl.Result{Requeue: true}, err - } - status.Experiment.StartTime = &metav1.Time{ - Time: time.Now(), - } - status.Experiment.Phase = v1alpha1.ExperimentPhaseRunning - status.FailedMessage = emptyString - } - - if err := r.Update(ctx, chaos); err != nil { - r.Log.Error(err, "unable to update chaos status") - return ctrl.Result{}, err - } - - return ctrl.Result{}, nil -} - -func updateFailedMessage( - ctx context.Context, - r *Reconciler, - chaos v1alpha1.InnerObject, - err string, -) { - status := chaos.GetStatus() - status.FailedMessage = err - if err := r.Update(ctx, chaos); err != nil { - r.Log.Error(err, "unable to update chaos status") - } -} diff --git a/controllers/config/config.go b/controllers/config/config.go index e65b14baf1..4445c11d20 100644 --- a/controllers/config/config.go +++ b/controllers/config/config.go @@ -1,28 +1,29 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package config import ( - "fmt" "os" "strings" + "github.com/pkg/errors" + ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/log/zap" "github.com/chaos-mesh/chaos-mesh/pkg/config" - - ctrl "sigs.k8s.io/controller-runtime" ) // ControllerCfg is a global variable to keep the configuration for Chaos Controller @@ -50,21 +51,9 @@ func init() { func validate(config *config.ChaosControllerConfig) error { - if config.WatcherConfig == nil { - return fmt.Errorf("required WatcherConfig is missing") - } - - if config.ClusterScoped != config.WatcherConfig.ClusterScoped { - return fmt.Errorf("K8sConfigMapWatcher config ClusterScoped is not same with controller-manager ClusterScoped. k8s configmap watcher: %t, controller manager: %t", config.WatcherConfig.ClusterScoped, config.ClusterScoped) - } - if !config.ClusterScoped { if strings.TrimSpace(config.TargetNamespace) == "" { - return fmt.Errorf("no target namespace specified with namespace scoped mode") - } - - if config.TargetNamespace != config.WatcherConfig.TargetNamespace { - return fmt.Errorf("K8sConfigMapWatcher config TargertNamespace is not same with controller-manager TargetNamespace. k8s configmap watcher: %s, controller manager: %s", config.WatcherConfig.TargetNamespace, config.TargetNamespace) + return errors.New("no target namespace specified with namespace scoped mode") } } diff --git a/controllers/config/types_test.go b/controllers/config/types_test.go index 1afb7fe980..a8c9a5cde8 100644 --- a/controllers/config/types_test.go +++ b/controllers/config/types_test.go @@ -1,37 +1,33 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package config import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/envtest" "github.com/chaos-mesh/chaos-mesh/pkg/config" - "github.com/chaos-mesh/chaos-mesh/pkg/webhook/config/watcher" ) func TestValidations(t *testing.T) { RegisterFailHandler(Fail) - RunSpecsWithDefaultAndCustomReporters(t, - "Namespace scoped", - []Reporter{envtest.NewlineReporter{}}) + RunSpecs(t, "Namespace scoped") } var _ = Describe("Namespace-scoped Chaos", func() { @@ -47,54 +43,11 @@ var _ = Describe("Namespace-scoped Chaos", func() { { name: "target namespace should not be empty with namespaced scope", config: config.ChaosControllerConfig{ - WatcherConfig: &watcher.Config{ - ClusterScoped: false, - TemplateNamespace: "", - TargetNamespace: "", - TemplateLabels: nil, - ConfigLabels: nil, - }, ClusterScoped: false, TargetNamespace: "", }, expectValid: false, }, - { - name: "Watcher Config is always required", - config: config.ChaosControllerConfig{ - WatcherConfig: nil, - ClusterScoped: true, - TargetNamespace: "", - }, - expectValid: false, - }, - { - name: "clusterScope should keep constant", - config: config.ChaosControllerConfig{ - WatcherConfig: &watcher.Config{ - ClusterScoped: false, - TemplateNamespace: "", - TargetNamespace: "", - TemplateLabels: nil, - ConfigLabels: nil, - }, - ClusterScoped: true, - TargetNamespace: "", - }, - expectValid: false, - }, - { - name: "ns should keep constant", - config: config.ChaosControllerConfig{ - WatcherConfig: &watcher.Config{ - ClusterScoped: false, - TargetNamespace: "ns1", - }, - ClusterScoped: false, - TargetNamespace: "ns2", - }, - expectValid: false, - }, } for _, testCase := range testCases { @@ -109,32 +62,3 @@ var _ = Describe("Namespace-scoped Chaos", func() { }) }) }) - -// TODO: reuse this function -func newPod( - name string, - status v1.PodPhase, - namespace string, - ans map[string]string, - ls map[string]string, - nodename string, -) v1.Pod { - return v1.Pod{ - TypeMeta: metav1.TypeMeta{ - Kind: "Pod", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - Labels: ls, - Annotations: ans, - }, - Spec: v1.PodSpec{ - NodeName: nodename, - }, - Status: v1.PodStatus{ - Phase: status, - }, - } -} diff --git a/controllers/config/util.go b/controllers/config/util.go new file mode 100644 index 0000000000..8f39904b13 --- /dev/null +++ b/controllers/config/util.go @@ -0,0 +1,34 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package config + +import "github.com/bxcodec/faker/support/slice" + +func ShouldSpawnController(name string) bool { + if slice.Contains(ControllerCfg.EnabledControllers, "*") || slice.Contains(ControllerCfg.EnabledControllers, name) { + return true + } + + return false +} + +func ShouldStartWebhook(name string) bool { + if slice.Contains(ControllerCfg.EnabledWebhooks, "*") || slice.Contains(ControllerCfg.EnabledWebhooks, name) { + return true + } + + return false +} diff --git a/controllers/dnschaos/types.go b/controllers/dnschaos/types.go deleted file mode 100644 index 481faabef1..0000000000 --- a/controllers/dnschaos/types.go +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package dnschaos - -import ( - "context" - "errors" - "fmt" - "time" - - dnspb "github.com/chaos-mesh/k8s_dns_chaos/pb" - "github.com/go-logr/logr" - "golang.org/x/sync/errgroup" - "google.golang.org/grpc" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/tools/cache" - ctrl "sigs.k8s.io/controller-runtime" - kubeclient "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/config" - "github.com/chaos-mesh/chaos-mesh/controllers/recover" - "github.com/chaos-mesh/chaos-mesh/controllers/utils" - "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" - "github.com/chaos-mesh/chaos-mesh/pkg/events" - "github.com/chaos-mesh/chaos-mesh/pkg/finalizer" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" -) - -// endpoint is dns-chaos reconciler -type endpoint struct { - ctx.Context -} - -type recoverer struct { - kubeclient.Client - Log logr.Logger -} - -// Apply applies dns-chaos -func (r *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - dnschaos, ok := chaos.(*v1alpha1.DNSChaos) - if !ok { - err := errors.New("chaos is not DNSChaos") - r.Log.Error(err, "chaos is not DNSChaos", "chaos", chaos) - return err - } - - pods, err := selector.SelectAndFilterPods(ctx, r.Client, r.Reader, &dnschaos.Spec, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) - if err != nil { - r.Log.Error(err, "failed to select and generate pods") - return err - } - - // get dns server's ip used for chaos - service, err := selector.GetService(ctx, r.Client, "", config.ControllerCfg.Namespace, config.ControllerCfg.DNSServiceName) - if err != nil { - r.Log.Error(err, "fail to get service") - return err - } - r.Log.Info("Set DNS chaos to DNS service", "ip", service.Spec.ClusterIP) - - err = r.setDNSServerRules(service.Spec.ClusterIP, config.ControllerCfg.DNSServicePort, dnschaos.Name, pods, dnschaos.Spec.Action, dnschaos.Spec.DomainNamePatterns) - if err != nil { - r.Log.Error(err, "fail to set DNS server rules") - return err - } - - if err = r.applyAllPods(ctx, pods, dnschaos, service.Spec.ClusterIP); err != nil { - r.Log.Error(err, "failed to apply chaos on all pods") - return err - } - - dnschaos.Status.Experiment.PodRecords = make([]v1alpha1.PodStatus, 0, len(pods)) - for _, pod := range pods { - ps := v1alpha1.PodStatus{ - Namespace: pod.Namespace, - Name: pod.Name, - HostIP: pod.Status.HostIP, - PodIP: pod.Status.PodIP, - } - - dnschaos.Status.Experiment.PodRecords = append(dnschaos.Status.Experiment.PodRecords, ps) - } - r.Event(dnschaos, v1.EventTypeNormal, events.ChaosInjected, "") - return nil -} - -// Recover means the reconciler recovers the chaos action -func (r *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - dnschaos, ok := chaos.(*v1alpha1.DNSChaos) - if !ok { - err := errors.New("chaos is not DNSChaos") - r.Log.Error(err, "chaos is not DNSChaos", "chaos", chaos) - return err - } - - // get dns server's ip used for chaos - service, err := selector.GetService(ctx, r.Client, "", config.ControllerCfg.Namespace, config.ControllerCfg.DNSServiceName) - if err != nil { - r.Log.Error(err, "fail to get service") - return err - } - r.Log.Info("Cancel DNS chaos to DNS service", "ip", service.Spec.ClusterIP) - - r.cancelDNSServerRules(service.Spec.ClusterIP, config.ControllerCfg.DNSServicePort, dnschaos.Name) - - rd := recover.Delegate{Client: r.Client, Log: r.Log, RecoverIntf: &recoverer{r.Client, r.Log}} - - finalizers, err := rd.CleanFinalizersAndRecover(ctx, chaos, dnschaos.Finalizers, dnschaos.Annotations) - if err != nil { - return err - } - dnschaos.Finalizers = finalizers - r.Event(dnschaos, v1.EventTypeNormal, events.ChaosRecovered, "") - - return nil -} - -func (r *recoverer) RecoverPod(ctx context.Context, pod *v1.Pod, somechaos v1alpha1.InnerObject) error { - r.Log.Info("Try to recover pod", "namespace", pod.Namespace, "name", pod.Name) - - daemonClient, err := utils.NewChaosDaemonClient(ctx, r.Client, pod) - if err != nil { - r.Log.Error(err, "get chaos daemon client") - return err - } - defer daemonClient.Close() - if len(pod.Status.ContainerStatuses) == 0 { - return fmt.Errorf("%s %s can't get the state of container", pod.Namespace, pod.Name) - } - - target := pod.Status.ContainerStatuses[0].ContainerID - - _, err = daemonClient.SetDNSServer(ctx, &pb.SetDNSServerRequest{ - ContainerId: target, - Enable: false, - EnterNS: true, - }) - if err != nil { - r.Log.Error(err, "recover pod for DNS chaos") - return err - } - - return nil -} - -// Object would return the instance of chaos -func (r *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.DNSChaos{} -} - -func (r *endpoint) applyAllPods(ctx context.Context, pods []v1.Pod, chaos *v1alpha1.DNSChaos, dnsServerIP string) error { - g := errgroup.Group{} - for index := range pods { - pod := &pods[index] - - key, err := cache.MetaNamespaceKeyFunc(pod) - if err != nil { - r.Log.Error(err, "get meta namespace key") - return err - } - chaos.Finalizers = finalizer.InsertFinalizer(chaos.Finalizers, key) - - g.Go(func() error { - return r.applyPod(ctx, pod, dnsServerIP) - }) - } - err := g.Wait() - if err != nil { - r.Log.Error(err, "g.Wait") - return err - } - return nil -} - -func (r *endpoint) applyPod(ctx context.Context, pod *v1.Pod, dnsServerIP string) error { - r.Log.Info("Try to apply dns chaos", "namespace", - pod.Namespace, "name", pod.Name) - daemonClient, err := utils.NewChaosDaemonClient(ctx, r.Client, pod) - if err != nil { - r.Log.Error(err, "get chaos daemon client") - return err - } - defer daemonClient.Close() - if len(pod.Status.ContainerStatuses) == 0 { - return fmt.Errorf("%s %s can't get the state of container", pod.Namespace, pod.Name) - } - - target := pod.Status.ContainerStatuses[0].ContainerID - - _, err = daemonClient.SetDNSServer(ctx, &pb.SetDNSServerRequest{ - ContainerId: target, - DnsServer: dnsServerIP, - Enable: true, - EnterNS: true, - }) - if err != nil { - r.Log.Error(err, "set dns server") - return err - } - - return nil -} - -func (r *endpoint) setDNSServerRules(dnsServerIP string, port int, name string, pods []v1.Pod, action v1alpha1.DNSChaosAction, patterns []string) error { - r.Log.Info("setDNSServerRules", "name", name) - - pbPods := make([]*dnspb.Pod, len(pods)) - for i, pod := range pods { - pbPods[i] = &dnspb.Pod{ - Name: pod.Name, - Namespace: pod.Namespace, - } - } - - conn, err := grpc.Dial(fmt.Sprintf("%s:%d", dnsServerIP, port), grpc.WithInsecure()) - if err != nil { - return err - } - defer conn.Close() - - c := dnspb.NewDNSClient(conn) - request := &dnspb.SetDNSChaosRequest{ - Name: name, - Action: string(action), - Pods: pbPods, - Patterns: patterns, - } - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - response, err := c.SetDNSChaos(ctx, request) - if err != nil { - return err - } - - if !response.Result { - return fmt.Errorf("set dns chaos to dns server error %s", response.Msg) - } - - return nil -} - -func (r *endpoint) cancelDNSServerRules(dnsServerIP string, port int, name string) error { - conn, err := grpc.Dial(fmt.Sprintf("%s:%d", dnsServerIP, port), grpc.WithInsecure()) - if err != nil { - return err - } - defer conn.Close() - - c := dnspb.NewDNSClient(conn) - request := &dnspb.CancelDNSChaosRequest{ - Name: name, - } - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - response, err := c.CancelDNSChaos(ctx, request) - if err != nil { - return err - } - - if !response.Result { - return fmt.Errorf("set dns chaos to dns server error %s", response.Msg) - } - - return nil -} - -func init() { - router.Register("dnschaos", &v1alpha1.DNSChaos{}, func(obj runtime.Object) bool { - return true - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/fx.go b/controllers/fx.go new file mode 100644 index 0000000000..6c3d76a3cd --- /dev/null +++ b/controllers/fx.go @@ -0,0 +1,54 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controllers + +import ( + "go.uber.org/fx" + + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl" + "github.com/chaos-mesh/chaos-mesh/controllers/common" + "github.com/chaos-mesh/chaos-mesh/controllers/multicluster/clusterregistry" + "github.com/chaos-mesh/chaos-mesh/controllers/multicluster/remotechaos" + "github.com/chaos-mesh/chaos-mesh/controllers/multicluster/remotecluster" + "github.com/chaos-mesh/chaos-mesh/controllers/podhttpchaos" + "github.com/chaos-mesh/chaos-mesh/controllers/podiochaos" + "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos" + "github.com/chaos-mesh/chaos-mesh/controllers/schedule" + "github.com/chaos-mesh/chaos-mesh/controllers/statuscheck" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" + wfcontrollers "github.com/chaos-mesh/chaos-mesh/pkg/workflow/controllers" +) + +var Module = fx.Options( + fx.Provide( + chaosdaemon.New, + recorder.NewRecorderBuilder, + common.AllSteps, + clusterregistry.New, + ), + fx.Invoke(common.Bootstrap), + fx.Invoke(podhttpchaos.Bootstrap), + fx.Invoke(podnetworkchaos.Bootstrap), + fx.Invoke(podiochaos.Bootstrap), + fx.Invoke(wfcontrollers.BootstrapWorkflowControllers), + fx.Invoke(statuscheck.Bootstrap), + fx.Invoke(remotecluster.Bootstrap), + fx.Invoke(remotechaos.Bootstrap), + + schedule.Module, + chaosimpl.AllImpl, +) diff --git a/controllers/gcpchaos/diskloss/types.go b/controllers/gcpchaos/diskloss/types.go deleted file mode 100644 index de43faaadc..0000000000 --- a/controllers/gcpchaos/diskloss/types.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package diskloss - -import ( - "context" - "encoding/json" - "errors" - "fmt" - - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - - "google.golang.org/api/compute/v1" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - gcp "github.com/chaos-mesh/chaos-mesh/controllers/gcpchaos" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" -) - -const ( - GcpFinalizer = "gcp-finalizer" -) - -type endpoint struct { - ctx.Context -} - -func (e *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - gcpchaos, ok := chaos.(*v1alpha1.GcpChaos) - if !ok { - err := errors.New("chaos is not gcpchaos") - e.Log.Error(err, "chaos is not GcpChaos", "chaos", chaos) - return err - } - computeService, err := gcp.GetComputeService(ctx, e.Client, gcpchaos) - if err != nil { - e.Log.Error(err, "fail to get the compute service") - return err - } - - haveDisk := false - instance, err := computeService.Instances.Get(gcpchaos.Spec.Project, gcpchaos.Spec.Zone, gcpchaos.Spec.Instance).Do() - if err != nil { - e.Log.Error(err, "fail to get the instance") - return err - } - var bytes []byte - for _, disk := range instance.Disks { - if disk.DeviceName == *gcpchaos.Spec.DeviceName { - haveDisk = true - bytes, err = json.Marshal(disk) - if err != nil { - e.Log.Error(err, "fail to marshal the disk info") - return err - } - break - } - } - if haveDisk == false { - err = fmt.Errorf("instance (%s) does not have the disk (%s)", gcpchaos.Spec.Instance, *gcpchaos.Spec.DeviceName) - e.Log.Error(err, "the instance does not have the disk") - return err - } - - gcpchaos.Finalizers = []string{GcpFinalizer} - _, err = computeService.Instances.DetachDisk(gcpchaos.Spec.Project, gcpchaos.Spec.Zone, gcpchaos.Spec.Instance, *gcpchaos.Spec.DeviceName).Do() - gcpchaos.Status.AttachedDiskString = string(bytes) - if err != nil { - gcpchaos.Finalizers = make([]string, 0) - e.Log.Error(err, "fail to detach the disk") - return err - } - - return nil -} - -func (e *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - gcpchaos, ok := chaos.(*v1alpha1.GcpChaos) - if !ok { - err := errors.New("chaos is not gcpchaos") - e.Log.Error(err, "chaos is not GcpChaos", "chaos", chaos) - return err - } - gcpchaos.Finalizers = make([]string, 0) - computeService, err := gcp.GetComputeService(ctx, e.Client, gcpchaos) - if err != nil { - e.Log.Error(err, "fail to get the compute service") - return err - } - var disk compute.AttachedDisk - err = json.Unmarshal([]byte(gcpchaos.Status.AttachedDiskString), &disk) - if err != nil { - e.Log.Error(err, "fail to unmarshal the disk info") - return err - } - _, err = computeService.Instances.AttachDisk(gcpchaos.Spec.Project, gcpchaos.Spec.Zone, gcpchaos.Spec.Instance, &disk).Do() - if err != nil { - e.Log.Error(err, "fail to attach the disk to the instance") - return err - } - return nil -} - -func (e *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.GcpChaos{} -} - -func init() { - router.Register("gcpchaos", &v1alpha1.GcpChaos{}, func(obj runtime.Object) bool { - chaos, ok := obj.(*v1alpha1.GcpChaos) - if !ok { - return false - } - - return chaos.Spec.Action == v1alpha1.DiskLoss - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/gcpchaos/nodereset/types.go b/controllers/gcpchaos/nodereset/types.go deleted file mode 100644 index 2ac177518a..0000000000 --- a/controllers/gcpchaos/nodereset/types.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package nodereset - -import ( - "context" - "errors" - - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - gcp "github.com/chaos-mesh/chaos-mesh/controllers/gcpchaos" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" -) - -type endpoint struct { - ctx.Context -} - -func (e *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - gcpchaos, ok := chaos.(*v1alpha1.GcpChaos) - if !ok { - err := errors.New("chaos is not gcpchaos") - e.Log.Error(err, "chaos is not GcpChaos", "chaos", chaos) - return err - } - computeService, err := gcp.GetComputeService(ctx, e.Client, gcpchaos) - if err != nil { - e.Log.Error(err, "fail to get the compute service") - return err - } - _, err = computeService.Instances.Reset(gcpchaos.Spec.Project, gcpchaos.Spec.Zone, gcpchaos.Spec.Instance).Do() - if err != nil { - e.Log.Error(err, "fail to reset the instance") - return err - } - - return nil -} - -func (e *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - return nil -} - -func (e *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.GcpChaos{} -} - -func init() { - router.Register("gcpchaos", &v1alpha1.GcpChaos{}, func(obj runtime.Object) bool { - chaos, ok := obj.(*v1alpha1.GcpChaos) - if !ok { - return false - } - - return chaos.Spec.Action == v1alpha1.NodeReset - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/gcpchaos/nodestop/types.go b/controllers/gcpchaos/nodestop/types.go deleted file mode 100644 index 77b999b02a..0000000000 --- a/controllers/gcpchaos/nodestop/types.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package nodestop - -import ( - "context" - "errors" - - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - gcp "github.com/chaos-mesh/chaos-mesh/controllers/gcpchaos" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" -) - -const ( - GcpFinalizer = "gcp-finalizer" -) - -type endpoint struct { - ctx.Context -} - -func (e *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - gcpchaos, ok := chaos.(*v1alpha1.GcpChaos) - if !ok { - err := errors.New("chaos is not gcpchaos") - e.Log.Error(err, "chaos is not GcpChaos", "chaos", chaos) - return err - } - computeService, err := gcp.GetComputeService(ctx, e.Client, gcpchaos) - if err != nil { - e.Log.Error(err, "fail to get the compute service") - return err - } - gcpchaos.Finalizers = []string{GcpFinalizer} - _, err = computeService.Instances.Stop(gcpchaos.Spec.Project, gcpchaos.Spec.Zone, gcpchaos.Spec.Instance).Do() - if err != nil { - gcpchaos.Finalizers = make([]string, 0) - e.Log.Error(err, "fail to stop the instance") - return err - } - - return nil -} - -func (e *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - gcpchaos, ok := chaos.(*v1alpha1.GcpChaos) - if !ok { - err := errors.New("chaos is not gcpchaos") - e.Log.Error(err, "chaos is not GcpChaos", "chaos", chaos) - return err - } - gcpchaos.Finalizers = make([]string, 0) - computeService, err := gcp.GetComputeService(ctx, e.Client, gcpchaos) - if err != nil { - e.Log.Error(err, "fail to get the compute service") - return err - } - _, err = computeService.Instances.Start(gcpchaos.Spec.Project, gcpchaos.Spec.Zone, gcpchaos.Spec.Instance).Do() - if err != nil { - e.Log.Error(err, "fail to stop the instance") - return err - } - return nil -} - -func (e *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.GcpChaos{} -} - -func init() { - router.Register("gcpchaos", &v1alpha1.GcpChaos{}, func(obj runtime.Object) bool { - chaos, ok := obj.(*v1alpha1.GcpChaos) - if !ok { - return false - } - - return chaos.Spec.Action == v1alpha1.NodeStop - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/gcpchaos/types.go b/controllers/gcpchaos/types.go deleted file mode 100644 index b1c4e6f465..0000000000 --- a/controllers/gcpchaos/types.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package gcpchaos - -import ( - "context" - "encoding/base64" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - "google.golang.org/api/compute/v1" - "google.golang.org/api/option" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -// GetComputeService is used to get the GCP compute Service. -func GetComputeService(ctx context.Context, cli client.Client, gcpchaos *v1alpha1.GcpChaos) (*compute.Service, error) { - if gcpchaos.Spec.SecretName != nil { - secret := &v1.Secret{} - err := cli.Get(ctx, types.NamespacedName{ - Name: *gcpchaos.Spec.SecretName, - Namespace: gcpchaos.Namespace, - }, secret) - if err != nil { - return nil, err - } - - decodeBytes, err := base64.StdEncoding.DecodeString(string(secret.Data["service_account"])) - if err != nil { - return nil, err - } - computeService, err := compute.NewService(ctx, option.WithCredentialsJSON(decodeBytes)) - if err != nil { - return nil, err - } - return computeService, nil - } - - computeService, err := compute.NewService(ctx) - if err != nil { - return nil, err - } - return computeService, nil -} diff --git a/controllers/httpchaos/types.go b/controllers/httpchaos/types.go deleted file mode 100644 index 30496d795a..0000000000 --- a/controllers/httpchaos/types.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package httpchaos - -import ( - "context" - "errors" - - "golang.org/x/sync/errgroup" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/tools/cache" - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/config" - "github.com/chaos-mesh/chaos-mesh/pkg/events" - "github.com/chaos-mesh/chaos-mesh/pkg/finalizer" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" -) - -type endpoint struct { - ctx.Context -} - -func (r *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - httpFaultChaos, ok := chaos.(*v1alpha1.HTTPChaos) - if !ok { - err := errors.New("chaos is not HttpFaultChaos") - r.Log.Error(err, "chaos is not HttpFaultChaos", "chaos", chaos) - return err - } - - pods, err := selector.SelectAndFilterPods(ctx, r.Client, r.Reader, &httpFaultChaos.Spec, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) - if err != nil { - r.Log.Error(err, "failed to select and filter pods") - return err - } - if err = r.applyAllPods(ctx, pods, httpFaultChaos); err != nil { - r.Log.Error(err, "failed to apply chaos on all pods") - return err - } - return nil -} - -func (r *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - httpFaultChaos, ok := chaos.(*v1alpha1.HTTPChaos) - if !ok { - err := errors.New("chaos is not HttpChaos") - r.Log.Error(err, "chaos is not HttpChaos", "chaos", chaos) - return err - } - r.Event(httpFaultChaos, v1.EventTypeNormal, events.ChaosRecovered, "") - return nil -} - -func (r *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.HTTPChaos{} -} - -func (r *endpoint) applyAllPods(ctx context.Context, pods []v1.Pod, chaos *v1alpha1.HTTPChaos) error { - g := errgroup.Group{} - for index := range pods { - pod := &pods[index] - - key, err := cache.MetaNamespaceKeyFunc(pod) - if err != nil { - return err - } - chaos.Finalizers = finalizer.InsertFinalizer(chaos.Finalizers, key) - - g.Go(func() error { - return r.applyPod(ctx, pod, chaos) - }) - } - - return g.Wait() -} - -func (r *endpoint) applyPod(ctx context.Context, pod *v1.Pod, chaos *v1alpha1.HTTPChaos) error { - //TODO: The way to connect with sidecar need be discussed & It will work after the sidecar add to the repo. - r.Log.Info("Try to inject Http chaos on pod", "namespace", pod.Namespace, "name", pod.Name) - return nil -} - -func init() { - router.Register("httpchaos", &v1alpha1.HTTPChaos{}, func(obj runtime.Object) bool { - return true - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/iochaos/podiochaosmanager/podiochaosmanager.go b/controllers/iochaos/podiochaosmanager/podiochaosmanager.go deleted file mode 100644 index 733cede192..0000000000 --- a/controllers/iochaos/podiochaosmanager/podiochaosmanager.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package podiochaosmanager - -import ( - "context" - "errors" - - "github.com/go-logr/logr" - "golang.org/x/sync/errgroup" - v1 "k8s.io/api/core/v1" - k8sError "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/util/retry" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -var ( - // ErrPodNotFound means operate pod may be deleted(almostly) - ErrPodNotFound = errors.New("pod not found") - - // ErrPodNotRunning means operate pod may be not working - // and it's non-sense to make changes on it. - ErrPodNotRunning = errors.New("pod not running") -) - -// PodIoManager will save all the related podiochaos -type PodIoManager struct { - Source string - Log logr.Logger - client.Client - - Modifications map[types.NamespacedName]*PodIoTransaction -} - -// New creates a new PodIoMap -func New(source string, logger logr.Logger, client client.Client) *PodIoManager { - return &PodIoManager{ - Source: source, - Log: logger, - Client: client, - Modifications: make(map[types.NamespacedName]*PodIoTransaction), - } -} - -// WithInit will get a transaction or start a transaction with initially clear -func (m *PodIoManager) WithInit(key types.NamespacedName) *PodIoTransaction { - t, ok := m.Modifications[key] - if ok { - return t - } - - t = &PodIoTransaction{} - t.Clear(m.Source) - m.Modifications[key] = t - return t -} - -// CommitResponse is a tuple (Key, Err) -type CommitResponse struct { - Key types.NamespacedName - Err error -} - -// Commit will update all modifications to the cluster -func (m *PodIoManager) Commit(ctx context.Context) []CommitResponse { - g := errgroup.Group{} - results := make([]CommitResponse, len(m.Modifications)) - index := 0 - for key, t := range m.Modifications { - i := index - - key := key - t := t - g.Go(func() error { - m.Log.Info("running modification on pod", "key", key, "modification", t) - updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { - chaos := &v1alpha1.PodIoChaos{} - - err := m.Client.Get(ctx, key, chaos) - if err != nil { - if !k8sError.IsNotFound(err) { - m.Log.Error(err, "error while getting podiochaos") - return err - } - - pod := v1.Pod{} - err = m.Client.Get(ctx, key, &pod) - if err != nil { - if !k8sError.IsNotFound(err) { - m.Log.Error(err, "error while finding pod") - return err - } - - m.Log.Info("pod not found", "key", key, "error", err.Error()) - err = ErrPodNotFound - return err - } - - if pod.Status.Phase != v1.PodRunning { - m.Log.Info("pod is not running", "key", key) - err = ErrPodNotRunning - return err - } - - chaos.Name = key.Name - chaos.Namespace = key.Namespace - chaos.OwnerReferences = []metav1.OwnerReference{ - { - APIVersion: pod.APIVersion, - Kind: pod.Kind, - Name: pod.Name, - UID: pod.UID, - }, - } - err = m.Client.Create(ctx, chaos) - - if err != nil { - m.Log.Error(err, "error while creating podiochaos") - return err - } - } - - err = t.Apply(chaos) - if err != nil { - m.Log.Error(err, "error while applying transactions", "transaction", t) - return err - } - - return m.Client.Update(ctx, chaos) - }) - - results[i] = CommitResponse{ - Key: key, - Err: updateError, - } - - return nil - }) - - index++ - } - - g.Wait() - - return results -} diff --git a/controllers/iochaos/podiochaosmanager/transaction.go b/controllers/iochaos/podiochaosmanager/transaction.go deleted file mode 100644 index 674ea61b75..0000000000 --- a/controllers/iochaos/podiochaosmanager/transaction.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package podiochaosmanager - -import ( - "fmt" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -// PodIoTransaction represents a modification on podnetwork -type PodIoTransaction struct { - Steps []Step -} - -// Step represents a step of PodIoTransaction -type Step interface { - // Apply will apply an action on podnetworkchaos - Apply(chaos *v1alpha1.PodIoChaos) error -} - -// Clear removes all resources with the same source -type Clear struct { - Source string -} - -// Apply runs this action -func (s *Clear) Apply(chaos *v1alpha1.PodIoChaos) error { - actions := []v1alpha1.IoChaosAction{} - for _, action := range chaos.Spec.Actions { - if action.Source != s.Source { - actions = append(actions, action) - } - } - chaos.Spec.Actions = actions - - return nil -} - -// Append adds an item to corresponding list in podnetworkchaos -type Append struct { - Item interface{} -} - -// Apply runs this action -func (a *Append) Apply(chaos *v1alpha1.PodIoChaos) error { - switch item := a.Item.(type) { - case v1alpha1.IoChaosAction: - chaos.Spec.Actions = append(chaos.Spec.Actions, item) - default: - return fmt.Errorf("unknown type of item") - } - - return nil -} - -// SetContainer sets the container field of podiochaos -type SetContainer struct { - Container string -} - -// Apply runs this action -func (s *SetContainer) Apply(chaos *v1alpha1.PodIoChaos) error { - chaos.Spec.Container = &s.Container - - return nil -} - -// SetVolumePath sets the volumePath field of podiochaos -type SetVolumePath struct { - Path string -} - -// Apply runs this action -func (s *SetVolumePath) Apply(chaos *v1alpha1.PodIoChaos) error { - chaos.Spec.VolumeMountPath = s.Path - - return nil -} - -// Clear will clear all related items in podnetworkchaos -func (t *PodIoTransaction) Clear(source string) { - t.Steps = append(t.Steps, &Clear{ - Source: source, - }) -} - -// Append adds an item to corresponding list in podnetworkchaos -func (t *PodIoTransaction) Append(item interface{}) error { - switch item.(type) { - case v1alpha1.IoChaosAction: - t.Steps = append(t.Steps, &Append{ - Item: item, - }) - return nil - default: - return fmt.Errorf("unknown type of item") - } -} - -// SetVolumePath sets the volumePath field of podiochaos -func (t *PodIoTransaction) SetVolumePath(path string) error { - t.Steps = append(t.Steps, &SetVolumePath{ - Path: path, - }) - - return nil -} - -func (t *PodIoTransaction) SetContainer(container string) error { - t.Steps = append(t.Steps, &SetContainer{ - Container: container, - }) - - return nil -} - -// Apply runs every step on the chaos -func (t *PodIoTransaction) Apply(chaos *v1alpha1.PodIoChaos) error { - for _, s := range t.Steps { - err := s.Apply(chaos) - if err != nil { - return err - } - } - - return nil -} diff --git a/controllers/iochaos/types.go b/controllers/iochaos/types.go deleted file mode 100644 index e57aba5e44..0000000000 --- a/controllers/iochaos/types.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package iochaos - -import ( - "context" - "errors" - "strings" - - "github.com/hashicorp/go-multierror" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/cache" - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/common" - "github.com/chaos-mesh/chaos-mesh/controllers/config" - "github.com/chaos-mesh/chaos-mesh/controllers/iochaos/podiochaosmanager" - "github.com/chaos-mesh/chaos-mesh/pkg/events" - "github.com/chaos-mesh/chaos-mesh/pkg/finalizer" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" -) - -type endpoint struct { - ctx.Context -} - -func (r *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.IoChaos{} -} - -// Apply implements the reconciler.InnerReconciler.Apply -func (r *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - iochaos, ok := chaos.(*v1alpha1.IoChaos) - if !ok { - err := errors.New("chaos is not IOChaos") - r.Log.Error(err, "chaos is not IOChaos", "chaos", chaos) - return err - } - - source := iochaos.Namespace + "/" + iochaos.Name - m := podiochaosmanager.New(source, r.Log, r.Client) - - pods, err := selector.SelectAndFilterPods(ctx, r.Client, r.Reader, &iochaos.Spec, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) - if err != nil { - r.Log.Error(err, "failed to select and filter pods") - return err - } - - keyPodMap := make(map[types.NamespacedName]v1.Pod) - for _, pod := range pods { - keyPodMap[types.NamespacedName{ - Name: pod.Name, - Namespace: pod.Namespace, - }] = pod - } - - r.Log.Info("applying iochaos", "iochaos", iochaos) - - for _, pod := range pods { - t := m.WithInit(types.NamespacedName{ - Name: pod.Name, - Namespace: pod.Namespace, - }) - - // TODO: support chaos on multiple volume - t.SetVolumePath(iochaos.Spec.VolumePath) - - if iochaos.Spec.ContainerName != nil && - len(strings.TrimSpace(*iochaos.Spec.ContainerName)) != 0 { - t.SetContainer(*iochaos.Spec.ContainerName) - } - - t.Append(v1alpha1.IoChaosAction{ - Type: iochaos.Spec.Action, - Filter: v1alpha1.Filter{ - Path: iochaos.Spec.Path, - Percent: iochaos.Spec.Percent, - Methods: iochaos.Spec.Methods, - }, - Faults: []v1alpha1.IoFault{ - { - Errno: iochaos.Spec.Errno, - Weight: 1, - }, - }, - Latency: iochaos.Spec.Delay, - AttrOverrideSpec: iochaos.Spec.Attr, - MistakeSpec: iochaos.Spec.Mistake, - Source: m.Source, - }) - - key, err := cache.MetaNamespaceKeyFunc(&pod) - if err != nil { - return err - } - iochaos.Finalizers = finalizer.InsertFinalizer(iochaos.Finalizers, key) - } - r.Log.Info("committing updates of podiochaos") - responses := m.Commit(ctx) - iochaos.Status.Experiment.PodRecords = make([]v1alpha1.PodStatus, 0, len(pods)) - for _, keyErrorTuple := range responses { - key := keyErrorTuple.Key - err := keyErrorTuple.Err - if err != nil { - if err != podiochaosmanager.ErrPodNotFound && err != podiochaosmanager.ErrPodNotRunning { - r.Log.Error(err, "fail to commit") - } else { - r.Log.Info("pod is not found or not running", "key", key) - } - return err - } - - pod := keyPodMap[keyErrorTuple.Key] - - ps := v1alpha1.PodStatus{ - Namespace: pod.Namespace, - Name: pod.Name, - HostIP: pod.Status.HostIP, - PodIP: pod.Status.PodIP, - Action: string(iochaos.Spec.Action), - } - - iochaos.Status.Experiment.PodRecords = append(iochaos.Status.Experiment.PodRecords, ps) - } - r.Event(iochaos, v1.EventTypeNormal, events.ChaosInjected, "") - - return nil -} - -// Recover means the reconciler recovers the chaos action -func (r *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - iochaos, ok := chaos.(*v1alpha1.IoChaos) - if !ok { - err := errors.New("chaos is not IoChaos") - r.Log.Error(err, "chaos is not IoChaos", "chaos", chaos) - return err - } - - if err := r.cleanFinalizersAndRecover(ctx, iochaos); err != nil { - return err - } - r.Event(iochaos, v1.EventTypeNormal, events.ChaosRecovered, "") - return nil -} - -func (r *endpoint) cleanFinalizersAndRecover(ctx context.Context, chaos *v1alpha1.IoChaos) error { - var result error - - source := chaos.Namespace + "/" + chaos.Name - m := podiochaosmanager.New(source, r.Log, r.Client) - - for _, key := range chaos.Finalizers { - ns, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - result = multierror.Append(result, err) - continue - } - - _ = m.WithInit(types.NamespacedName{ - Namespace: ns, - Name: name, - }) - } - responses := m.Commit(ctx) - for _, response := range responses { - key := response.Key - err := response.Err - // if pod not found or not running, directly return and giveup recover. - if err != nil { - if err != podiochaosmanager.ErrPodNotFound && err != podiochaosmanager.ErrPodNotRunning { - r.Log.Error(err, "fail to commit", "key", key) - - result = multierror.Append(result, err) - continue - } - - r.Log.Info("pod is not found or not running", "key", key) - } - - chaos.Finalizers = finalizer.RemoveFromFinalizer(chaos.Finalizers, response.Key.String()) - } - r.Log.Info("After recovering", "finalizers", chaos.Finalizers) - - if chaos.Annotations[common.AnnotationCleanFinalizer] == common.AnnotationCleanFinalizerForced { - r.Log.Info("Force cleanup all finalizers", "chaos", chaos) - chaos.Finalizers = make([]string, 0) - return nil - } - - return result -} - -func init() { - router.Register("iochaos", &v1alpha1.IoChaos{}, func(obj runtime.Object) bool { - return true - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/jvmchaos/types.go b/controllers/jvmchaos/types.go deleted file mode 100644 index 1b61ada22c..0000000000 --- a/controllers/jvmchaos/types.go +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package jvmchaos - -import ( - "context" - "errors" - "fmt" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/common" - "github.com/chaos-mesh/chaos-mesh/controllers/config" - "github.com/chaos-mesh/chaos-mesh/pkg/events" - "github.com/chaos-mesh/chaos-mesh/pkg/finalizer" - "github.com/chaos-mesh/chaos-mesh/pkg/jvm" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" - - "github.com/hashicorp/go-multierror" - "golang.org/x/sync/errgroup" - - v1 "k8s.io/api/core/v1" - k8serror "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/cache" - ctrl "sigs.k8s.io/controller-runtime" -) - -const sandboxPort = 10086 - -type endpoint struct { - ctx.Context -} - -// Apply applies jvm-chaos -func (r *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - jvmchaos, ok := chaos.(*v1alpha1.JVMChaos) - if !ok { - err := errors.New("chaos is not JVMChaos") - r.Log.Error(err, "chaos is not JVMChaos", "chaos", chaos) - return err - } - - pods, err := selector.SelectAndFilterPods(ctx, r.Client, r.Reader, &jvmchaos.Spec, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) - if err != nil { - r.Log.Error(err, "failed to select and generate pods") - return err - } - - if err = r.applyAllPods(ctx, pods, jvmchaos); err != nil { - r.Log.Error(err, "failed to apply chaos on all pods") - return err - } - - jvmchaos.Status.Experiment.PodRecords = make([]v1alpha1.PodStatus, 0, len(pods)) - for _, pod := range pods { - ps := v1alpha1.PodStatus{ - Namespace: pod.Namespace, - Name: pod.Name, - HostIP: pod.Status.HostIP, - PodIP: pod.Status.PodIP, - } - - jvmchaos.Status.Experiment.PodRecords = append(jvmchaos.Status.Experiment.PodRecords, ps) - } - r.Event(jvmchaos, v1.EventTypeNormal, events.ChaosInjected, "") - return nil -} - -func (r *endpoint) applyAllPods(ctx context.Context, pods []v1.Pod, chaos *v1alpha1.JVMChaos) error { - g := errgroup.Group{} - for index := range pods { - pod := &pods[index] - - key, err := cache.MetaNamespaceKeyFunc(pod) - if err != nil { - r.Log.Error(err, "get meta namespace key") - return err - } - chaos.Finalizers = finalizer.InsertFinalizer(chaos.Finalizers, key) - - g.Go(func() error { - return r.applyPod(ctx, pod, chaos) - }) - } - err := g.Wait() - if err != nil { - r.Log.Error(err, "g.Wait") - return err - } - return nil -} - -func (r *endpoint) applyPod(ctx context.Context, pod *v1.Pod, chaos *v1alpha1.JVMChaos) error { - r.Log.Info("Try to apply jvm chaos", "namespace", - pod.Namespace, "name", pod.Name) - - // TODO: Custom port may be required - err := jvm.ActiveSandbox(pod.Status.PodIP, sandboxPort) - if err != nil { - return err - } - - r.Log.Info("active sandbox", "pod", pod.Name) - - suid := genSUID(pod, chaos) - jsonBytes, err := jvm.ToSandboxAction(suid, chaos) - - if err != nil { - return err - } - // TODO: Custom port may be required - err = jvm.InjectChaos(pod.Status.PodIP, sandboxPort, jsonBytes) - if err != nil { - return err - } - r.Log.Info("Inject JVM Chaos", "pod", pod.Name, "action", chaos.Spec.Action) - return nil -} - -func genSUID(pod *v1.Pod, chaos *v1alpha1.JVMChaos) string { - return fmt.Sprintf("%s:%s:%s:%s:%s", - pod.Name, - chaos.Spec.Action, - chaos.Spec.Target, - chaos.Name, - chaos.Namespace) -} - -// Recover means the reconciler recovers the chaos action -func (r *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - jvmchaos, ok := chaos.(*v1alpha1.JVMChaos) - if !ok { - err := errors.New("chaos is not JVMChaos") - r.Log.Error(err, "chaos is not JVMChaos", "chaos", chaos) - return err - } - if err := r.cleanFinalizersAndRecover(ctx, jvmchaos); err != nil { - return err - } - - r.Event(jvmchaos, v1.EventTypeNormal, events.ChaosRecovered, "") - - return nil -} - -func (r *endpoint) cleanFinalizersAndRecover(ctx context.Context, chaos *v1alpha1.JVMChaos) error { - var result error - - for _, key := range chaos.Finalizers { - ns, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - result = multierror.Append(result, err) - continue - } - - var pod v1.Pod - err = r.Client.Get(ctx, types.NamespacedName{ - Namespace: ns, - Name: name, - }, &pod) - - if err != nil { - if !k8serror.IsNotFound(err) { - result = multierror.Append(result, err) - continue - } - - r.Log.Info("Pod not found", "namespace", ns, "name", name) - chaos.Finalizers = finalizer.RemoveFromFinalizer(chaos.Finalizers, key) - continue - } - - err = r.recoverPod(ctx, &pod, chaos) - if err != nil { - result = multierror.Append(result, err) - continue - } - - chaos.Finalizers = finalizer.RemoveFromFinalizer(chaos.Finalizers, key) - } - - if chaos.Annotations[common.AnnotationCleanFinalizer] == common.AnnotationCleanFinalizerForced { - r.Log.Info("Force cleanup all finalizers", "chaos", chaos) - chaos.Finalizers = chaos.Finalizers[:0] - return nil - } - - return result -} - -func (r *endpoint) recoverPod(ctx context.Context, pod *v1.Pod, chaos *v1alpha1.JVMChaos) error { - r.Log.Info("Try to recover pod", "namespace", pod.Namespace, "name", pod.Name) - - suid := genSUID(pod, chaos) - jsonBytes, err := jvm.ToSandboxAction(suid, chaos) - if err != nil { - return err - } - - // TODO: Custom port may be required - err = jvm.RecoverChaos(pod.Status.PodIP, sandboxPort, jsonBytes) - if err != nil { - return err - } - return nil -} - -// Object would return the instance of chaos -func (r *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.JVMChaos{} -} - -func init() { - router.Register("jvmchaos", &v1alpha1.JVMChaos{}, func(obj runtime.Object) bool { - return true - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/kernelchaos/types.go b/controllers/kernelchaos/types.go deleted file mode 100644 index be6db0a809..0000000000 --- a/controllers/kernelchaos/types.go +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package kernelchaos - -import ( - "context" - "errors" - "fmt" - - "github.com/go-logr/logr" - "golang.org/x/sync/errgroup" - "google.golang.org/grpc" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/tools/cache" - ctrl "sigs.k8s.io/controller-runtime" - kubeclient "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/config" - "github.com/chaos-mesh/chaos-mesh/controllers/recover" - "github.com/chaos-mesh/chaos-mesh/controllers/utils" - pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" - pb_ "github.com/chaos-mesh/chaos-mesh/pkg/chaoskernel/pb" - "github.com/chaos-mesh/chaos-mesh/pkg/events" - "github.com/chaos-mesh/chaos-mesh/pkg/finalizer" - grpcUtils "github.com/chaos-mesh/chaos-mesh/pkg/grpc" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" -) - -const kernelChaosMsg = "kernel is injected with %v" - -// endpoint is KernelChaos reconciler -type endpoint struct { - ctx.Context -} - -type recoverer struct { - kubeclient.Client - Log logr.Logger -} - -// Apply applies KernelChaos -func (r *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - kernelChaos, ok := chaos.(*v1alpha1.KernelChaos) - if !ok { - err := errors.New("chaos is not kernelChaos") - r.Log.Error(err, "chaos is not KernelChaos", "chaos", chaos) - return err - } - - pods, err := selector.SelectAndFilterPods(ctx, r.Client, r.Reader, &kernelChaos.Spec, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) - if err != nil { - r.Log.Error(err, "failed to select and filter pods") - return err - } - - if err = r.applyAllPods(ctx, pods, kernelChaos); err != nil { - r.Log.Error(err, "failed to apply chaos on all pods") - return err - } - - kernelChaos.Status.Experiment.PodRecords = make([]v1alpha1.PodStatus, 0, len(pods)) - for _, pod := range pods { - ps := v1alpha1.PodStatus{ - Namespace: pod.Namespace, - Name: pod.Name, - HostIP: pod.Status.HostIP, - PodIP: pod.Status.PodIP, - Message: fmt.Sprintf(kernelChaosMsg, kernelChaos.Spec.FailKernRequest), - } - - kernelChaos.Status.Experiment.PodRecords = append(kernelChaos.Status.Experiment.PodRecords, ps) - } - r.Event(kernelChaos, v1.EventTypeNormal, events.ChaosInjected, "") - - return nil -} - -// Recover means the reconciler recovers the chaos action -func (r *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - kernelchaos, ok := chaos.(*v1alpha1.KernelChaos) - if !ok { - err := errors.New("chaos is not KernelChaos") - r.Log.Error(err, "chaos is not KernelChaos", "chaos", chaos) - return err - } - - rd := recover.Delegate{Client: r.Client, Log: r.Log, RecoverIntf: &recoverer{r.Client, r.Log}} - - finalizers, err := rd.CleanFinalizersAndRecover(ctx, chaos, kernelchaos.Finalizers, kernelchaos.Annotations) - if err != nil { - return err - } - kernelchaos.Finalizers = finalizers - r.Event(kernelchaos, v1.EventTypeNormal, events.ChaosRecovered, "") - - return nil -} - -func (r *recoverer) RecoverPod(ctx context.Context, pod *v1.Pod, somechaos v1alpha1.InnerObject) error { - // judged type in `Recover` already so no need to judge again - chaos, _ := somechaos.(*v1alpha1.KernelChaos) - r.Log.Info("try to recover pod", "namespace", pod.Namespace, "name", pod.Name) - - pbClient, err := utils.NewChaosDaemonClient(ctx, r.Client, pod) - if err != nil { - return err - } - defer pbClient.Close() - - if len(pod.Status.ContainerStatuses) == 0 { - return fmt.Errorf("%s %s can't get the state of container", pod.Namespace, pod.Name) - } - - containerResponse, err := pbClient.ContainerGetPid(ctx, &pb.ContainerRequest{ - Action: &pb.ContainerAction{ - Action: pb.ContainerAction_GETPID, - }, - ContainerId: pod.Status.ContainerStatuses[0].ContainerID, - }) - - if err != nil { - r.Log.Error(err, "Get container pid error", "namespace", pod.Namespace, "name", pod.Name) - return err - } - - r.Log.Info("Get container pid", "namespace", pod.Namespace, "name", pod.Name) - conn, err := CreateBPFKIConnection(ctx, r.Client, pod) - if err != nil { - return err - } - defer conn.Close() - - var callchain []*pb_.FailKernRequestFrame - for _, frame := range chaos.Spec.FailKernRequest.Callchain { - callchain = append(callchain, &pb_.FailKernRequestFrame{ - Funcname: frame.Funcname, - Parameters: frame.Parameters, - Predicate: frame.Predicate, - }) - } - - bpfClient := pb_.NewBPFKIServiceClient(conn) - _, err = bpfClient.RecoverMMOrBIO(ctx, &pb_.FailKernRequest{ - Pid: containerResponse.Pid, - Callchain: callchain, - }) - - return err -} - -// Object would return the instance of chaos -func (r *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.KernelChaos{} -} - -func (r *endpoint) applyAllPods(ctx context.Context, pods []v1.Pod, chaos *v1alpha1.KernelChaos) error { - g := errgroup.Group{} - for index := range pods { - pod := &pods[index] - - key, err := cache.MetaNamespaceKeyFunc(pod) - if err != nil { - return err - } - chaos.Finalizers = finalizer.InsertFinalizer(chaos.Finalizers, key) - - g.Go(func() error { - return r.applyPod(ctx, pod, chaos) - }) - } - - return g.Wait() -} - -func (r *endpoint) applyPod(ctx context.Context, pod *v1.Pod, chaos *v1alpha1.KernelChaos) error { - r.Log.Info("Try to inject kernel on pod", "namespace", pod.Namespace, "name", pod.Name) - - pbClient, err := utils.NewChaosDaemonClient(ctx, r.Client, pod) - if err != nil { - return err - } - defer pbClient.Close() - - if len(pod.Status.ContainerStatuses) == 0 { - return fmt.Errorf("%s %s can't get the state of container", pod.Namespace, pod.Name) - } - - containerResponse, err := pbClient.ContainerGetPid(ctx, &pb.ContainerRequest{ - Action: &pb.ContainerAction{ - Action: pb.ContainerAction_GETPID, - }, - ContainerId: pod.Status.ContainerStatuses[0].ContainerID, - }) - if err != nil { - r.Log.Error(err, "Get container pid error", "namespace", pod.Namespace, "name", pod.Name) - return err - } - - r.Log.Info("Get container pid", "namespace", pod.Namespace, "name", pod.Name) - conn, err := CreateBPFKIConnection(ctx, r.Client, pod) - if err != nil { - return err - } - defer conn.Close() - - var callchain []*pb_.FailKernRequestFrame - for _, frame := range chaos.Spec.FailKernRequest.Callchain { - callchain = append(callchain, &pb_.FailKernRequestFrame{ - Funcname: frame.Funcname, - Parameters: frame.Parameters, - Predicate: frame.Predicate, - }) - } - - bpfClient := pb_.NewBPFKIServiceClient(conn) - _, err = bpfClient.FailMMOrBIO(ctx, &pb_.FailKernRequest{ - Pid: containerResponse.Pid, - Ftype: pb_.FailKernRequest_FAILTYPE(chaos.Spec.FailKernRequest.FailType), - Headers: chaos.Spec.FailKernRequest.Headers, - Callchain: callchain, - Probability: float32(chaos.Spec.FailKernRequest.Probability) / 100, - Times: chaos.Spec.FailKernRequest.Times, - }) - - return err -} - -// CreateBPFKIConnection create a grpc connection with bpfki -func CreateBPFKIConnection(ctx context.Context, c kubeclient.Client, pod *v1.Pod) (*grpc.ClientConn, error) { - daemonIP, err := utils.FindDaemonIP(ctx, c, pod) - if err != nil { - return nil, err - } - - return grpcUtils.CreateGrpcConnection(daemonIP, config.ControllerCfg.BPFKIPort, config.ControllerCfg.TLSConfig.ChaosMeshCACert, config.ControllerCfg.TLSConfig.ChaosDaemonClientCert, config.ControllerCfg.TLSConfig.ChaosDaemonClientKey) -} - -func init() { - router.Register("kernelchaos", &v1alpha1.KernelChaos{}, func(obj runtime.Object) bool { - return true - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/metrics/metrics.go b/controllers/metrics/metrics.go deleted file mode 100644 index 6f7b13ae2c..0000000000 --- a/controllers/metrics/metrics.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package metrics - -import ( - "context" - - "github.com/prometheus/client_golang/prometheus" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/cache" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -var log = ctrl.Log.WithName("metrics-collector") - -// ChaosCollector implements prometheus.Collector interface -type ChaosCollector struct { - store cache.Cache - experimentStatus *prometheus.GaugeVec - SidecarTemplates prometheus.Gauge - ConfigTemplates *prometheus.GaugeVec - InjectionConfigs *prometheus.GaugeVec - TemplateNotExist *prometheus.CounterVec - TemplateLoadError prometheus.Counter - ConfigNameDuplicate *prometheus.CounterVec - InjectRequired *prometheus.CounterVec - Injections *prometheus.CounterVec -} - -// NewChaosCollector initializes metrics and collector -func NewChaosCollector(store cache.Cache, registerer prometheus.Registerer) *ChaosCollector { - c := &ChaosCollector{ - store: store, - experimentStatus: prometheus.NewGaugeVec(prometheus.GaugeOpts{ - Name: "chaos_mesh_experiments", - Help: "Total number of chaos experiments and their phases", - }, []string{"namespace", "kind", "phase"}), - SidecarTemplates: prometheus.NewGauge(prometheus.GaugeOpts{ - Name: "chaos_mesh_templates", - Help: "Total number of injection templates", - }), - ConfigTemplates: prometheus.NewGaugeVec(prometheus.GaugeOpts{ - Name: "chaos_mesh_config_templates", - Help: "Total number of config templates", - }, []string{"namespace", "template"}), - InjectionConfigs: prometheus.NewGaugeVec(prometheus.GaugeOpts{ - Name: "chaos_mesh_injection_configs", - Help: "Total number of injection configs", - }, []string{"namespace", "template"}), - TemplateNotExist: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "chaos_mesh_template_not_exist_total", - Help: "Total number of template not exist error", - }, []string{"namespace", "template"}), - ConfigNameDuplicate: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "chaos_mesh_config_name_duplicate_total", - Help: "Total number of config name duplication error", - }, []string{"namespace", "config"}), - TemplateLoadError: prometheus.NewCounter(prometheus.CounterOpts{ - Name: "chaos_mesh_template_load_failed_total", - Help: "Total number of failures when rendering config args to template", - }), - InjectRequired: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "chaos_mesh_inject_required_total", - Help: "Total number of injections required", - }, []string{"namespace", "config"}), - Injections: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "chaos_mesh_injections_total", - Help: "Total number of sidecar injections performed on the webhook", - }, []string{"namespace", "config"}), - } - registerer.MustRegister(c) - return c -} - -// Describe implements the prometheus.Collector interface. -func (c *ChaosCollector) Describe(ch chan<- *prometheus.Desc) { - c.experimentStatus.Describe(ch) - c.SidecarTemplates.Describe(ch) - c.ConfigTemplates.Describe(ch) - c.InjectionConfigs.Describe(ch) - c.TemplateNotExist.Describe(ch) - c.ConfigNameDuplicate.Describe(ch) - c.TemplateLoadError.Describe(ch) - c.InjectRequired.Describe(ch) - c.Injections.Describe(ch) -} - -// Collect implements the prometheus.Collector interface. -func (c *ChaosCollector) Collect(ch chan<- prometheus.Metric) { - c.collect() - c.SidecarTemplates.Collect(ch) - c.ConfigTemplates.Collect(ch) - c.InjectionConfigs.Collect(ch) - c.TemplateNotExist.Collect(ch) - c.ConfigNameDuplicate.Collect(ch) - c.TemplateLoadError.Collect(ch) - c.InjectRequired.Collect(ch) - c.Injections.Collect(ch) - c.experimentStatus.Collect(ch) -} - -func (c *ChaosCollector) collect() { - // TODO(yeya24) if there is an error in List - // the experiment status will be lost - c.experimentStatus.Reset() - - for kind, obj := range v1alpha1.AllKinds() { - expCache := map[string]map[string]int{} - if err := c.store.List(context.TODO(), obj.ChaosList); err != nil { - log.Error(err, "failed to list chaos", "kind", kind) - return - } - for _, chaos := range obj.ListChaos() { - if _, ok := expCache[chaos.Namespace]; !ok { - // There is only 4 supported phases - expCache[chaos.Namespace] = make(map[string]int, 4) - } - expCache[chaos.Namespace][chaos.Status]++ - } - - for ns, v := range expCache { - for phase, count := range v { - c.experimentStatus.WithLabelValues(ns, kind, phase).Set(float64(count)) - } - } - } -} diff --git a/controllers/multicluster/clusterregistry/README.md b/controllers/multicluster/clusterregistry/README.md new file mode 100644 index 0000000000..6b403e5f1c --- /dev/null +++ b/controllers/multicluster/clusterregistry/README.md @@ -0,0 +1,92 @@ +# Multicluster Technical Documents + +This documents not only describe the behavior of `clusterregistry`, it +also describes the technical framework which can help the chaos mesh developers +to develop the multicluster application. + +A `clusterregistry` will manage all controllers watching a remote cluster. The +construction of these controllers (managers) will be managed by `fx`. The main +process of constructing a controller manage is nearly the same with the main +one. The only difference is that we'll need to provide a new `RestConfig`, and +`Populate` the client to allow others to use its client. + +The `RemoteClusterRegistry` provides three methods: `Spawn`, `Stop` and +`WithClient`. `Spawn` allows you to setup a new controller-manager watching +resources inside the remote cluster, and `Stop` allows you to stop a running +controller-manager. `WithClient` enables the developer to get a client to +operate in the remote cluster. + +For more details about these three functions, please read the documents of them. + +## Bootstrap Process + +You'll need a `*rest.Config` to start a controller manager inside remote +cluster. This config is used to setup client, watch changes... This client will +also be used by any other called `WithClient`, so make sure it has enough +priviledges. + +With this `*rest.Config`, the `Spawn` method will construct a new fx App, which +is nearly the same with the main one. The difference between this fx App and the +main one is that it only adds reconciler which is needed by multicluster, and it +doesn't start webhook, doesn't listen on the metrics. + +Except `ctrl.Option` and `*rest.Config`, all other arguments used by manager are +provided by the same one in the `provider`. Only the default client is passed +inside. If you need more different client, it won't be too complicated to add +them to this construction process. + +It also passes a cancelable context to the `run` function. This context is used +to stop the controller. + +## Stop Process + +The stop / cancel is managed directly by the fx lifecycle. We added a stop hook +to cancel the context used by the controller manager when we are stopping the fx +app. + +## Register Reconciler + +If you need to register a reconciler for a remote cluster, add a new `fx.Invoke` +to the construction of cluster (in the `Spawn` method), register the new +reconciler to the manager inside that function. + +See `/controllers/multicluster/remotepodreconciler/fx.go` for an example. + +## Use the remote cluster client in manage cluster reconciler + +To manage the resources in the remote cluster, you may need to get a client of +remote cluster. With a `ClusterRegistry`, it would be really easy! + +```go +err := r.registry.WithClient(obj.Name, func(c client.Client) error { + return c.Create(ctx, &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "hello-world", + Namespace: "default", + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Image: "docker/whalesay", + ImagePullPolicy: corev1.PullIfNotPresent, + Name: "hello-world", + Command: []string{"cowsay", "Hello World"}, + }, + }, + }, + }) +}) +if err != nil { + if !k8sError.IsAlreadyExists(err) { + r.Log.Error(err, "fail to create pod") + } + +} +``` + +## Use the manage cluster client in remote cluster reconciler + +`ClusterRegistry` provides a `client.Client` annotated with +`name:"manage-client"` to allow remote cluster reconciler operates on the manage +cluster. See `/controllers/multicluster/remotepodreconciler/fx.go` for an +example. diff --git a/controllers/multicluster/clusterregistry/error.go b/controllers/multicluster/clusterregistry/error.go new file mode 100644 index 0000000000..da6707dc8a --- /dev/null +++ b/controllers/multicluster/clusterregistry/error.go @@ -0,0 +1,23 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package clusterregistry + +import "github.com/pkg/errors" + +var ( + ErrAlreadyExist = errors.New("controllers of cluster has already been started") + ErrNotExist = errors.New("controllers of cluster doesn't exist") +) diff --git a/controllers/multicluster/clusterregistry/registry.go b/controllers/multicluster/clusterregistry/registry.go new file mode 100644 index 0000000000..ef1111c799 --- /dev/null +++ b/controllers/multicluster/clusterregistry/registry.go @@ -0,0 +1,207 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package clusterregistry + +import ( + "context" + "os" + "sync" + + fxlogr "github.com/chaos-mesh/fx-logr" + "github.com/go-logr/logr" + "github.com/pkg/errors" + "go.uber.org/fx" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + controllermetrics "sigs.k8s.io/controller-runtime/pkg/metrics" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + + "github.com/chaos-mesh/chaos-mesh/cmd/chaos-controller-manager/provider" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/multicluster/remotechaosmonitor" + "github.com/chaos-mesh/chaos-mesh/controllers/types" +) + +type remoteCluster struct { + app *fx.App + + client.Client +} + +// RemoteClusterRegistry will manage all controllers running on a remote +// cluster. The construction of these controllers (managers) will be managed by +// `fx`. The main process of constructing a controller manage is nearly the same +// with the main one. The only difference is that we'll need to provide a new +// `RestConfig`, and `Populate` the client to allow others to use its client. +type RemoteClusterRegistry struct { + clusters map[string]*remoteCluster + logger logr.Logger + client client.Client + + lock *sync.Mutex +} + +func New(logger logr.Logger, client client.Client) *RemoteClusterRegistry { + return &RemoteClusterRegistry{ + clusters: make(map[string]*remoteCluster), + logger: logger.WithName("clusterregistry"), + client: client, + + lock: &sync.Mutex{}, + } +} + +// run will start the controller manager of the remote cluster +func run(lc fx.Lifecycle, mgr ctrl.Manager, logger logr.Logger) error { + // TODO: use the global signal context with a cancel function + executionCtx, cancel := context.WithCancel(context.TODO()) + stopChan := make(chan struct{}) + + go func() { + setupLog := logger.WithName("setup") + setupLog.Info("Starting manager") + + if err := mgr.Start(executionCtx); err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + stopChan <- struct{}{} + }() + + lc.Append(fx.Hook{ + OnStop: func(ctx context.Context) error { + cancel() + <-stopChan + return nil + }, + }) + + return nil +} + +// TODO: unify this option with global provider.NewOption +func controllerManagerOption(scheme *runtime.Scheme) *ctrl.Options { + options := ctrl.Options{ + // TODO: accept the schema from parameter instead of using scheme directly + Scheme: scheme, + Metrics: metricsserver.Options{ + BindAddress: "0", + }, + // TODO: enable leader election + LeaderElection: false, + RetryPeriod: &config.ControllerCfg.LeaderElectRetryPeriod, + RenewDeadline: &config.ControllerCfg.LeaderElectRenewDeadline, + } + + // TODO: consider the cluster scope / namespace scope with multi-cluster + + return &options +} + +// WithClient enables developer getting a client of remote cluster to operate +// inside the remote cluster. +// +// TODO: add more kinds of client, like `no-cache` into this registry, if they +// are needed +func (r *RemoteClusterRegistry) WithClient(name string, f func(c client.Client) error) error { + r.lock.Lock() + defer r.lock.Unlock() + + cluster, ok := r.clusters[name] + if !ok { + return errors.Wrapf(ErrNotExist, "lookup cluster: %s", name) + } + + return f(cluster.Client) +} + +// Stop stops the running controller-manager which watches the remote cluster. +func (r *RemoteClusterRegistry) Stop(ctx context.Context, name string) error { + r.lock.Lock() + defer r.lock.Unlock() + + cluster, ok := r.clusters[name] + if !ok { + return errors.Wrapf(ErrNotExist, "lookup cluster: %s", name) + } + + err := cluster.app.Stop(ctx) + if err != nil { + return errors.Wrapf(err, "stop fx app: %s", name) + } + delete(r.clusters, name) + + r.logger.Info("controller manager stopped", "name", name) + + return nil +} + +// Spawn starts the controller-manager and watches the remote cluster +func (r *RemoteClusterRegistry) Spawn(name string, config *rest.Config) error { + r.lock.Lock() + defer r.lock.Unlock() + + if _, ok := r.clusters[name]; ok { + return errors.Wrapf(ErrAlreadyExist, "spawn cluster: %s", name) + } + + remoteFxLogger := r.logger.WithName("remotecluster-fx-" + name) + + localClient := r.client + var remoteClient client.Client + app := fx.New( + fx.WithLogger(fxlogr.WithLogr(&remoteFxLogger)), + fx.Supply(controllermetrics.Registry), + fx.Supply(r.logger.WithName("remotecluster-"+name)), + fx.Supply(config), + fx.Supply(fx.Annotated{ + Name: "cluster-name", + Target: name, + }), + fx.Provide( + fx.Annotate(func() client.Client { + return localClient + }, fx.ResultTags(`name:"manage-client"`)), + ), + fx.Provide( + controllerManagerOption, + provider.NewClient, + provider.NewManager, + provider.NewScheme, + ), + fx.Option(types.ChaosObjects), + // more reconcilers can be listed here to add themselves to the + // controller manager + remotechaosmonitor.Module, + fx.Populate(&remoteClient), + fx.Invoke(run), + ) + + err := app.Start(context.TODO()) + if err != nil { + return errors.Wrapf(err, "start controller-manager of remote cluster %s", name) + } + + r.clusters[name] = &remoteCluster{ + app: app, + Client: remoteClient, + } + + return nil +} diff --git a/controllers/multicluster/remotechaos/controller.go b/controllers/multicluster/remotechaos/controller.go new file mode 100644 index 0000000000..4ed4bd6b52 --- /dev/null +++ b/controllers/multicluster/remotechaos/controller.go @@ -0,0 +1,126 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package remotechaos + +import ( + "context" + "reflect" + + "github.com/go-logr/logr" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/multicluster/clusterregistry" +) + +type Reconciler struct { + client.Client + Log logr.Logger + + Object v1alpha1.InnerObject + + registry *clusterregistry.RemoteClusterRegistry +} + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + obj := r.Object.DeepCopyObject().(v1alpha1.RemoteObject) + + if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil { + if apierrors.IsNotFound(err) { + r.Log.Info("chaos not found") + } else { + // TODO: handle this error + r.Log.Error(err, "unable to get chaos") + } + return ctrl.Result{}, nil + } + + err := r.registry.WithClient(obj.GetRemoteCluster(), func(c client.Client) error { + r.Log.Info("handling chaos with remote client", "cluster", obj.GetRemoteCluster()) + + localObj := obj.DeepCopyObject().(v1alpha1.RemoteObject) + + remoteObj := obj.DeepCopyObject().(v1alpha1.RemoteObject) + err := c.Get(ctx, req.NamespacedName, remoteObj) + if err != nil { + if apierrors.IsNotFound(err) { + // remote chaos doesn't exist, while the local one is being deleted + if localObj.GetDeletionTimestamp() != nil { + return retry.RetryOnConflict(retry.DefaultRetry, func() error { + var obj v1alpha1.RemoteObject + r.Log.Info("resetting finalizers of local objects") + if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil { + if apierrors.IsNotFound(err) { + r.Log.Info("chaos has been removed") + return nil + } + // TODO: handle this error + r.Log.Error(err, "unable to get chaos") + + return err + } + + obj.SetFinalizers([]string{}) + return r.Client.Update(ctx, obj) + }) + } + + // omit the remoteCluster + localSpecValue := reflect.Indirect(reflect.ValueOf(localObj)).FieldByName("Spec") + localSpecValue.FieldByName("RemoteCluster").Set(reflect.ValueOf("")) + + // only Spec, Name, Namespace and a label will be initialized + newObj := r.Object.DeepCopyObject().(v1alpha1.RemoteObject) + reflect.Indirect(reflect.ValueOf(newObj)).FieldByName("Spec").Set(localSpecValue) + + newObj.SetLabels(map[string]string{ + "chaos-mesh.org/controlled-by": "remote-chaos", + }) + newObj.SetName(obj.GetName()) + newObj.SetNamespace(obj.GetNamespace()) + + return c.Create(ctx, newObj) + } + + // TODO: handle this error + r.Log.Error(err, "unable to get chaos") + return nil + } + + // remote chaos exists + if localObj.GetDeletionTimestamp() != nil { + r.Log.Info("deleting remote obj", "namespace", remoteObj.GetNamespace(), "name", remoteObj.GetName()) + err := c.Delete(ctx, remoteObj) + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + } + return nil + }) + if err != nil { + r.Log.Error(err, "unable to handle chaos") + // TODO: handle the error + // TODO: retry + } + + return ctrl.Result{}, nil +} diff --git a/controllers/multicluster/remotechaos/fx.go b/controllers/multicluster/remotechaos/fx.go new file mode 100644 index 0000000000..753433a697 --- /dev/null +++ b/controllers/multicluster/remotechaos/fx.go @@ -0,0 +1,133 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package remotechaos + +import ( + "fmt" + + "github.com/go-logr/logr" + "go.uber.org/fx" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/multicluster/clusterregistry" + "github.com/chaos-mesh/chaos-mesh/controllers/types" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/builder" +) + +type Params struct { + fx.In + + Mgr ctrl.Manager + Client client.Client + Logger logr.Logger + Objs []types.Object `group:"objs"` + Registry *clusterregistry.RemoteClusterRegistry +} + +func Bootstrap(params Params) error { + logger := params.Logger + mgr := params.Mgr + objs := params.Objs + client := params.Client + registry := params.Registry + setupLog := logger.WithName("setup-remotechaos") + + for _, obj := range objs { + name := obj.Name + "-remote-apply" + if !config.ShouldSpawnController(name) { + return nil + } + + setupLog.Info("setting up controller", "resource-name", obj.Name) + + builder := builder.Default(mgr). + For(obj.Object). + Named(obj.Name + "-remotechaos"). + WithEventFilter(remotePredicates) + err := builder.Complete(&Reconciler{ + Client: client, + Log: logger.WithName("remotechaos"), + + Object: obj.Object, + + registry: registry, + }) + + if err != nil { + return err + } + + } + + return nil +} + +// this controller will only create or delete the remote chaos +var remotePredicates = predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + obj, ok := e.Object.DeepCopyObject().(v1alpha1.RemoteObject) + if !ok { + fmt.Println("not a remote object") + return false + } + + if obj.GetRemoteCluster() == "" { + return false + } + + return true + }, + UpdateFunc: func(e event.UpdateEvent) bool { + // TODO: consider carefully whether we'll need to handle + // delete event + obj, ok := e.ObjectNew.DeepCopyObject().(v1alpha1.RemoteObject) + if !ok { + fmt.Println("not a remote object") + return false + } + + if obj.GetRemoteCluster() == "" { + fmt.Println("remote cluster is empty") + return false + } + + return true + }, + DeleteFunc: func(e event.DeleteEvent) bool { + // TODO: consider carefully whether we'll need to handle + // delete event + obj, ok := e.Object.DeepCopyObject().(v1alpha1.RemoteObject) + if !ok { + fmt.Println("not a remote object") + return false + } + + if obj.GetRemoteCluster() == "" { + fmt.Println("remote cluster is empty") + return false + } + + return true + }, + GenericFunc: func(e event.GenericEvent) bool { + return false + }, +} diff --git a/controllers/multicluster/remotechaosmonitor/controller.go b/controllers/multicluster/remotechaosmonitor/controller.go new file mode 100644 index 0000000000..46237ecc7c --- /dev/null +++ b/controllers/multicluster/remotechaosmonitor/controller.go @@ -0,0 +1,142 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package remotechaosmonitor + +import ( + "context" + "reflect" + + "github.com/go-logr/logr" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type Reconciler struct { + clusterName string + + obj v1alpha1.InnerObject + + logger logr.Logger + localClient client.Client + remoteClient client.Client +} + +func New(obj v1alpha1.InnerObject, manageClient client.Client, clusterName string, localClient client.Client, logger logr.Logger) *Reconciler { + return &Reconciler{ + clusterName: clusterName, + obj: obj, + logger: logger.WithName("remotechaos-monitor"), + localClient: manageClient, + remoteClient: localClient, + } +} + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + r.logger.Info("reconcile chaos", "clusterName", r.clusterName, "namespace", req.Namespace, "name", req.Name) + + shouldDelete := false + remoteObj := r.obj.DeepCopyObject().(v1alpha1.RemoteObject) + err := r.remoteClient.Get(ctx, req.NamespacedName, remoteObj) + if err != nil { + if apierrors.IsNotFound(err) { + r.logger.Info("chaos not found") + + shouldDelete = true + } else { + // TODO: handle this error + r.logger.Error(err, "unable to get remote chaos") + return ctrl.Result{}, nil + } + } + + localObj := r.obj.DeepCopyObject().(v1alpha1.RemoteObject) + err = r.localClient.Get(ctx, req.NamespacedName, localObj) + if err != nil { + if apierrors.IsNotFound(err) { + r.logger.Info("local chaos not found") + + err = r.remoteClient.Delete(ctx, remoteObj) + if err != nil { + if apierrors.IsNotFound(err) { + r.logger.Info("remote chaos deleted") + } else { + // TODO: retry for some error + r.logger.Error(err, "unable to get remote chaos") + } + } + + return ctrl.Result{}, nil + } + + // TODO: handle this error + r.logger.Error(err, "unable to get local chaos") + return ctrl.Result{}, nil + } + + if shouldDelete { + r.logger.Info("deleting local obj", "namespace", localObj.GetNamespace(), "name", localObj.GetName()) + localObj.SetFinalizers([]string{}) + err := r.localClient.Update(ctx, localObj) + if err != nil { + // TODO: retry + r.logger.Error(err, "fail to update localObj") + // it's expected to not return, as we could still try + // to remove this object + } + + err = r.localClient.Delete(ctx, localObj) + if err != nil { + // TODO: retry + r.logger.Error(err, "fail to delete local object") + } + + return ctrl.Result{}, nil + } + + shouldUpdate := false + if !reflect.DeepEqual(localObj.GetFinalizers(), remoteObj.GetFinalizers()) { + r.logger.Info("setting new finalizers") + localObj.SetFinalizers(remoteObj.GetFinalizers()) + + shouldUpdate = true + } + + // TODO: set the status + if !reflect.DeepEqual(localObj.GetStatus(), remoteObj.GetStatus()) { + r.logger.Info("setting new status", "local:", localObj.GetStatus(), "remote:", remoteObj.GetStatus()) + shouldUpdate = true + } + + if shouldUpdate { + retry.RetryOnConflict(retry.DefaultRetry, func() error { + localObj := r.obj.DeepCopyObject().(v1alpha1.RemoteObject) + err = r.localClient.Get(ctx, req.NamespacedName, localObj) + if err != nil { + return err + } + + // TODO: also refresh the remote chaos object + localObj.SetFinalizers(remoteObj.GetFinalizers()) + remoteObj.GetStatus().DeepCopyInto(localObj.GetStatus()) + return r.localClient.Update(ctx, localObj) + }) + } + return ctrl.Result{}, nil +} diff --git a/controllers/multicluster/remotechaosmonitor/fx.go b/controllers/multicluster/remotechaosmonitor/fx.go new file mode 100644 index 0000000000..b4299d175b --- /dev/null +++ b/controllers/multicluster/remotechaosmonitor/fx.go @@ -0,0 +1,72 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package remotechaosmonitor + +import ( + "github.com/go-logr/logr" + "go.uber.org/fx" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/types" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/builder" +) + +type Params struct { + fx.In + + Mgr ctrl.Manager + ManageClient client.Client `name:"manage-client"` + LocalClient client.Client + ClusterName string `name:"cluster-name"` + Logger logr.Logger + Objs []types.Object `group:"objs"` +} + +func Bootstrap(params Params) error { + logger := params.Logger + mgr := params.Mgr + objs := params.Objs + setupLog := logger.WithName("setup-remotechaosmonitor") + + for _, obj := range objs { + name := obj.Name + "-remotechaos-monitor" + + if !config.ShouldSpawnController(name) { + return nil + } + + setupLog.Info("setting up controller", "resource-name", obj.Name) + + // TODO: filter out chaos controlled by remote chaos + builder := builder.Default(mgr). + For(obj.Object). + Named(obj.Name + "-remotechaos-monitor") + + err := builder.Complete(New(obj.Object, params.ManageClient, params.ClusterName, params.LocalClient, params.Logger)) + + if err != nil { + return err + } + + } + return nil +} + +var Module = fx.Options( + fx.Invoke(Bootstrap), +) diff --git a/controllers/multicluster/remotecluster/condition.go b/controllers/multicluster/remotecluster/condition.go new file mode 100644 index 0000000000..ab70f532da --- /dev/null +++ b/controllers/multicluster/remotecluster/condition.go @@ -0,0 +1,42 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package remotecluster + +import ( + corev1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +func setRemoteClusterCondition(obj *v1alpha1.RemoteCluster, typ v1alpha1.RemoteClusterConditionType, status corev1.ConditionStatus, reason string) { + conditionMap := map[v1alpha1.RemoteClusterConditionType]v1alpha1.RemoteClusterCondition{ + v1alpha1.RemoteClusterConditionInstalled: {Type: v1alpha1.RemoteClusterConditionInstalled, Status: corev1.ConditionFalse}, + v1alpha1.RemoteClusterConditionReady: {Type: v1alpha1.RemoteClusterConditionReady, Status: corev1.ConditionFalse}, + } + + for _, condition := range obj.Status.Conditions { + conditionMap[condition.Type] = condition + } + + conditionMap[typ] = v1alpha1.RemoteClusterCondition{Type: typ, Status: status, Reason: reason} + + conditions := make([]v1alpha1.RemoteClusterCondition, 0, len(conditionMap)) + for _, condition := range conditionMap { + conditions = append(conditions, condition) + } + + obj.Status.Conditions = conditions +} diff --git a/controllers/multicluster/remotecluster/condition_test.go b/controllers/multicluster/remotecluster/condition_test.go new file mode 100644 index 0000000000..d4721dce30 --- /dev/null +++ b/controllers/multicluster/remotecluster/condition_test.go @@ -0,0 +1,47 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package remotecluster + +import ( + "testing" + + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +func TestSetRemoteClusterCondition(t *testing.T) { + RegisterTestingT(t) + + obj := &v1alpha1.RemoteCluster{} + setRemoteClusterCondition(obj, v1alpha1.RemoteClusterConditionInstalled, corev1.ConditionTrue, "test") + + Expect(len(obj.Status.Conditions)).To(Equal(2)) + haveConditionInstalled := false + for _, condition := range obj.Status.Conditions { + if condition.Type == v1alpha1.RemoteClusterConditionInstalled { + Expect(condition.Status).To(Equal(corev1.ConditionTrue)) + Expect(condition.Reason).To(Equal("test")) + + haveConditionInstalled = true + } else { + Expect(condition.Status).To(Equal(corev1.ConditionFalse)) + } + } + + Expect(haveConditionInstalled).To(Equal(true)) +} diff --git a/controllers/multicluster/remotecluster/controller.go b/controllers/multicluster/remotecluster/controller.go new file mode 100644 index 0000000000..382bca1c12 --- /dev/null +++ b/controllers/multicluster/remotecluster/controller.go @@ -0,0 +1,260 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package remotecluster + +import ( + "context" + "encoding/json" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "helm.sh/helm/v3/pkg/release" + "helm.sh/helm/v3/pkg/storage/driver" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/multicluster/clusterregistry" + "github.com/chaos-mesh/chaos-mesh/pkg/helm" +) + +const remoteClusterControllerFinalizer = "chaos-mesh/remotecluster-controllers" +const chaosMeshReleaseName = "chaos-mesh" + +type Reconciler struct { + Log logr.Logger + registry *clusterregistry.RemoteClusterRegistry + + client.Client +} + +func (r *Reconciler) getRestConfig(ctx context.Context, secretRef v1alpha1.RemoteClusterSecretRef) (clientcmd.ClientConfig, error) { + var secret corev1.Secret + err := r.Client.Get(ctx, types.NamespacedName{ + Namespace: secretRef.Namespace, + Name: secretRef.Name, + }, &secret) + if err != nil { + return nil, errors.Wrapf(err, "get secret %s/%s", secretRef.Namespace, secretRef.Name) + } + + kubeconfig := secret.Data[secretRef.Key] + + config, err := clientcmd.Load(kubeconfig) + if err != nil { + return nil, errors.Wrap(err, "load kubeconfig") + } + + return clientcmd.NewDefaultClientConfig(*config, nil), nil +} + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + var obj v1alpha1.RemoteCluster + err := r.Client.Get(ctx, req.NamespacedName, &obj) + if err != nil { + if apierrors.IsNotFound(err) { + r.Log.Info("remote cluster not found", "namespace", req.Namespace, "name", req.Name) + } else { + // TODO: handle this error + r.Log.Error(err, "unable to get remote cluster", "namespace", req.Namespace, "name", req.Name) + } + return ctrl.Result{}, nil + } + + r.Log.Info("remote cluster", "Generation:", obj.ObjectMeta.Generation, "ObservedGeneration:", obj.Status.ObservedGeneration) + + if obj.ObjectMeta.Generation <= obj.Status.ObservedGeneration { + r.Log.Info("the target remote cluster has been up to date", "remote cluster", obj.Namespace+"/"+obj.Name) + return ctrl.Result{}, nil + } + + clientConfig, err := r.getRestConfig(ctx, obj.Spec.KubeConfig.SecretRef) + if err != nil { + r.Log.Error(err, "fail to get clientConfig from secret") + return ctrl.Result{Requeue: true}, nil + } + + // if the remoteCluster itself is being deleted, we should remove the cluster controller manager + if !obj.DeletionTimestamp.IsZero() { + err := r.registry.Stop(ctx, obj.Name) + if err != nil { + if !errors.Is(err, clusterregistry.ErrNotExist) { + r.Log.Error(err, "fail to stop cluster") + return ctrl.Result{Requeue: true}, nil + } + } + + err = r.uninstallHelmRelease(ctx, &obj, clientConfig) + if err != nil { + r.Log.Error(err, "fail to uninstall helm release") + return ctrl.Result{Requeue: true}, nil + } + + err = retry.RetryOnConflict(retry.DefaultRetry, func() error { + var newObj v1alpha1.RemoteCluster + r.Client.Get(ctx, req.NamespacedName, &newObj) + + newObj.Finalizers = []string{} + setRemoteClusterCondition(&newObj, v1alpha1.RemoteClusterConditionInstalled, corev1.ConditionFalse, "") + + return r.Client.Update(ctx, &newObj) + }) + if err != nil { + r.Log.Error(err, "fail to update finalizer", "name", obj.Name) + return ctrl.Result{Requeue: true}, nil + } + return ctrl.Result{}, nil + } + + currentVersion, err := r.ensureHelmRelease(ctx, &obj, clientConfig) + if err != nil { + r.Log.Error(err, "fail to list or install remote helm release") + return ctrl.Result{Requeue: true}, nil + } + + err = r.ensureClusterControllerManager(ctx, &obj, clientConfig) + if err != nil { + r.Log.Error(err, "fail to boot remote cluster controller manager") + return ctrl.Result{Requeue: true}, nil + } + obj.Finalizers = []string{remoteClusterControllerFinalizer} + + if err != nil { + r.Log.Error(err, "fail to operate the helm release in remote cluster") + return ctrl.Result{Requeue: true}, nil + } + + observedGeneration := obj.ObjectMeta.Generation + err = retry.RetryOnConflict(retry.DefaultRetry, func() error { + var newObj v1alpha1.RemoteCluster + r.Client.Get(ctx, req.NamespacedName, &newObj) + + newObj.Finalizers = obj.Finalizers + setRemoteClusterCondition(&newObj, v1alpha1.RemoteClusterConditionInstalled, corev1.ConditionTrue, "") + + if err = r.Client.Update(ctx, &newObj); err != nil { + return err + } + newObj.Status.CurrentVersion = currentVersion + newObj.Status.ObservedGeneration = observedGeneration + err = r.Client.Status().Update(ctx, &newObj) + return err + }) + if err != nil { + r.Log.Error(err, "fail to update finalizer", "name", obj.Name) + return ctrl.Result{Requeue: true}, nil + } + + return ctrl.Result{}, nil +} + +func (r *Reconciler) ensureClusterControllerManager(ctx context.Context, obj *v1alpha1.RemoteCluster, config clientcmd.ClientConfig) error { + restConfig, err := config.ClientConfig() + if err != nil { + return errors.Wrap(err, "get rest config from client config") + } + + err = r.registry.Spawn(obj.Name, restConfig) + if err != nil { + if !errors.Is(err, clusterregistry.ErrAlreadyExist) { + return err + } + } + + return nil +} + +func (r *Reconciler) getHelmClient(ctx context.Context, clientConfig clientcmd.ClientConfig) (*helm.HelmClient, error) { + restClientGetter := helm.NewRESTClientGetter(clientConfig) + + helmClient, err := helm.NewHelmClient(restClientGetter, r.Log) + if err != nil { + return nil, err + } + + return helmClient, nil +} + +func (r *Reconciler) ensureHelmRelease(ctx context.Context, obj *v1alpha1.RemoteCluster, clientConfig clientcmd.ClientConfig) (string, error) { + helmClient, err := r.getHelmClient(ctx, clientConfig) + if err != nil { + return "", err + } + _, releaseErr := helmClient.GetRelease(obj.Spec.Namespace, chaosMeshReleaseName) + if releaseErr != nil && !errors.Is(releaseErr, driver.ErrReleaseNotFound) { + return "", releaseErr + } + chart, err := helm.FetchChaosMeshChart(ctx, obj.Spec.Version, config.ControllerCfg.LocalHelmChartPath) + if err != nil { + return "", err + } + + values := make(map[string]interface{}) + if obj.Spec.ConfigOverride != nil { + err = json.Unmarshal(obj.Spec.ConfigOverride, &values) + if err != nil { + return "", err + } + } + var release *release.Release + if errors.Is(releaseErr, driver.ErrReleaseNotFound) { + release, err = helmClient.InstallRelease(obj.Spec.Namespace, chaosMeshReleaseName, chart, values) + if err != nil { + return "", err + } + } else { + release, err = helmClient.UpgradeRelease(obj.Spec.Namespace, chaosMeshReleaseName, chart, values) + if err != nil { + return "", err + } + } + + return release.Chart.AppVersion(), nil +} + +func (r *Reconciler) uninstallHelmRelease(ctx context.Context, obj *v1alpha1.RemoteCluster, clientConfig clientcmd.ClientConfig) error { + helmClient, err := r.getHelmClient(ctx, clientConfig) + if err != nil { + return err + } + + _, err = helmClient.GetRelease(obj.Spec.Namespace, chaosMeshReleaseName) + if err != nil { + if errors.Is(err, driver.ErrReleaseNotFound) { + return nil + } + + return err + } + + // the release still exist + _, err = helmClient.UninstallRelease(obj.Spec.Namespace, chaosMeshReleaseName) + if err != nil { + if errors.Is(err, driver.ErrReleaseNotFound) { + return nil + } + + return err + } + + return nil +} diff --git a/controllers/multicluster/remotecluster/fx.go b/controllers/multicluster/remotecluster/fx.go new file mode 100644 index 0000000000..0e65e3fc90 --- /dev/null +++ b/controllers/multicluster/remotecluster/fx.go @@ -0,0 +1,44 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package remotecluster + +import ( + "github.com/go-logr/logr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/multicluster/clusterregistry" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/builder" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" +) + +func Bootstrap(mgr ctrl.Manager, client client.Client, logger logr.Logger, recorderBuilder *recorder.RecorderBuilder, registry *clusterregistry.RemoteClusterRegistry) error { + if !config.ShouldSpawnController("remotecluster") { + return nil + } + + return builder.Default(mgr). + For(&v1alpha1.RemoteCluster{}). + Named("remotecluster"). + Complete(&Reconciler{ + Client: client, + Log: logger.WithName("remotecluster"), + + registry: registry, + }) +} diff --git a/controllers/multicluster/remotepodreconciler/fx.go b/controllers/multicluster/remotepodreconciler/fx.go new file mode 100644 index 0000000000..39e06e1bcd --- /dev/null +++ b/controllers/multicluster/remotepodreconciler/fx.go @@ -0,0 +1,48 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package remotepodreconciler + +import ( + "github.com/go-logr/logr" + "go.uber.org/fx" + corev1 "k8s.io/api/core/v1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/controller" +) + +func Bootstrap(mgr ctrl.Manager, podReconciler *Reconciler, logger logr.Logger) error { + return ctrl.NewControllerManagedBy(mgr). + WithOptions(controller.Options{ + // TODO: in a newer version `controller-runtime`, it would be + // possible to set a customized rate limiter. + // + // After upgrading `controller-runtime`, we could choose a better + // rate limiter for error handling + MaxConcurrentReconciles: 1, + }). + For(&corev1.Pod{}). + Complete(podReconciler) +} + +var Module = fx.Options( + fx.Provide( + fx.Annotate( + New, + fx.ParamTags(`name:"manage-client"`, `name:"cluster-name"`), + ), + ), + fx.Invoke(Bootstrap), +) diff --git a/controllers/multicluster/remotepodreconciler/remote_pod_reconciler.go b/controllers/multicluster/remotepodreconciler/remote_pod_reconciler.go new file mode 100644 index 0000000000..a97767bcb0 --- /dev/null +++ b/controllers/multicluster/remotepodreconciler/remote_pod_reconciler.go @@ -0,0 +1,46 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package remotepodreconciler + +import ( + "context" + + "github.com/go-logr/logr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type Reconciler struct { + clusterName string + + logger logr.Logger + manageClient client.Client + localClient client.Client +} + +func New(manageClient client.Client, clusterName string, localClient client.Client, logger logr.Logger) *Reconciler { + return &Reconciler{ + clusterName: clusterName, + logger: logger.WithName("example-pod"), + manageClient: manageClient, + localClient: localClient, + } +} + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + r.logger.Info("reconcile pod", "clusterName", r.clusterName, "namespace", req.Namespace, "name", req.Name) + return ctrl.Result{}, nil +} diff --git a/controllers/networkchaos/partition/types.go b/controllers/networkchaos/partition/types.go deleted file mode 100644 index b9edd5cd94..0000000000 --- a/controllers/networkchaos/partition/types.go +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package partition - -import ( - "context" - "errors" - "fmt" - - "github.com/hashicorp/go-multierror" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/cache" - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/common" - "github.com/chaos-mesh/chaos-mesh/controllers/config" - "github.com/chaos-mesh/chaos-mesh/controllers/networkchaos/podnetworkchaosmanager" - "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/ipset" - "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/iptable" - "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/netutils" - pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" - "github.com/chaos-mesh/chaos-mesh/pkg/events" - "github.com/chaos-mesh/chaos-mesh/pkg/finalizer" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" -) - -const ( - networkPartitionActionMsg = " partition network duration %s" - networkChaosSourceMsg = "This is a source pod." - networkChaosTargetMsg = "This is a target pod." - - sourceIPSetPostFix = "src" - targetIPSetPostFix = "tgt" -) - -type endpoint struct { - ctx.Context -} - -// Object implements the reconciler.InnerReconciler.Object -func (e *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.NetworkChaos{} -} - -// Apply applies the chaos operation -func (e *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - e.Log.Info("Applying network partition") - - networkchaos, ok := chaos.(*v1alpha1.NetworkChaos) - if !ok { - err := errors.New("chaos is not NetworkChaos") - e.Log.Error(err, "chaos is not NetworkChaos", "chaos", chaos) - - return err - } - - source := networkchaos.Namespace + "/" + networkchaos.Name - m := podnetworkchaosmanager.New(source, e.Log, e.Client) - - sources, err := selector.SelectAndFilterPods(ctx, e.Client, e.Reader, &networkchaos.Spec, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) - - if err != nil { - e.Log.Error(err, "failed to select and filter source pods") - return err - } - - var targets []v1.Pod - - if networkchaos.Spec.Target != nil { - targets, err = selector.SelectAndFilterPods(ctx, e.Client, e.Reader, networkchaos.Spec.Target, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) - if err != nil { - e.Log.Error(err, "failed to select and filter target pods") - return err - } - } - - sourceSet := ipset.BuildIPSet(sources, []string{}, networkchaos, sourceIPSetPostFix, source) - externalCidrs, err := netutils.ResolveCidrs(networkchaos.Spec.ExternalTargets) - if err != nil { - e.Log.Error(err, "failed to resolve external targets") - return err - } - targetSet := ipset.BuildIPSet(targets, externalCidrs, networkchaos, targetIPSetPostFix, source) - - allPods := append(sources, targets...) - - type podPositionTuple struct { - Pod v1.Pod - Position string - } - keyPodMap := make(map[types.NamespacedName]podPositionTuple) - for index, pod := range allPods { - position := "" - if index < len(sources) { - position = "source" - } else { - position = "target" - } - keyPodMap[types.NamespacedName{ - Name: pod.Name, - Namespace: pod.Namespace, - }] = podPositionTuple{ - Pod: pod, - Position: position, - } - } - - // Set up ipset in every related pods - for index := range allPods { - pod := allPods[index] - e.Log.Info("PODS", "name", pod.Name, "namespace", pod.Namespace) - - t := m.WithInit(types.NamespacedName{ - Name: pod.Name, - Namespace: pod.Namespace, - }) - - t.Append(sourceSet) - t.Append(targetSet) - } - - sourcesChains := []v1alpha1.RawIptables{} - targetsChains := []v1alpha1.RawIptables{} - if networkchaos.Spec.Direction == v1alpha1.To || networkchaos.Spec.Direction == v1alpha1.Both { - sourcesChains = append(sourcesChains, v1alpha1.RawIptables{ - Name: iptable.GenerateName(pb.Chain_OUTPUT, networkchaos), - Direction: v1alpha1.Output, - IPSets: []string{targetSet.Name}, - RawRuleSource: v1alpha1.RawRuleSource{ - Source: source, - }, - }) - - targetsChains = append(targetsChains, v1alpha1.RawIptables{ - Name: iptable.GenerateName(pb.Chain_INPUT, networkchaos), - Direction: v1alpha1.Input, - IPSets: []string{sourceSet.Name}, - RawRuleSource: v1alpha1.RawRuleSource{ - Source: source, - }, - }) - } - - if networkchaos.Spec.Direction == v1alpha1.From || networkchaos.Spec.Direction == v1alpha1.Both { - sourcesChains = append(sourcesChains, v1alpha1.RawIptables{ - Name: iptable.GenerateName(pb.Chain_INPUT, networkchaos), - Direction: v1alpha1.Input, - IPSets: []string{targetSet.Name}, - RawRuleSource: v1alpha1.RawRuleSource{ - Source: source, - }, - }) - - targetsChains = append(targetsChains, v1alpha1.RawIptables{ - Name: iptable.GenerateName(pb.Chain_OUTPUT, networkchaos), - Direction: v1alpha1.Output, - IPSets: []string{sourceSet.Name}, - RawRuleSource: v1alpha1.RawRuleSource{ - Source: source, - }, - }) - } - e.Log.Info("chains prepared", "sourcesChains", sourcesChains, "targetsChains", targetsChains) - - err = e.SetChains(ctx, sources, sourcesChains, m, networkchaos) - if err != nil { - return err - } - - err = e.SetChains(ctx, targets, targetsChains, m, networkchaos) - if err != nil { - return err - } - - responses := m.Commit(ctx) - - networkchaos.Status.Experiment.PodRecords = make([]v1alpha1.PodStatus, 0, len(allPods)) - for _, keyErrorTuple := range responses { - key := keyErrorTuple.Key - err := keyErrorTuple.Err - if err != nil { - if err != podnetworkchaosmanager.ErrPodNotFound && err != podnetworkchaosmanager.ErrPodNotRunning { - e.Log.Error(err, "fail to commit") - } else { - e.Log.Info("pod is not found or not running", "key", key) - } - return err - } - - pod := keyPodMap[keyErrorTuple.Key] - ps := v1alpha1.PodStatus{ - Namespace: pod.Pod.Namespace, - Name: pod.Pod.Name, - HostIP: pod.Pod.Status.HostIP, - PodIP: pod.Pod.Status.PodIP, - Action: string(networkchaos.Spec.Action), - } - if pod.Position == "source" { - ps.Message = networkChaosSourceMsg - } else { - ps.Message = networkChaosTargetMsg - } - - // TODO: add source, target and tc action message - if networkchaos.Spec.Duration != nil { - ps.Message += fmt.Sprintf(networkPartitionActionMsg, *networkchaos.Spec.Duration) - } - networkchaos.Status.Experiment.PodRecords = append(networkchaos.Status.Experiment.PodRecords, ps) - } - - e.Event(networkchaos, v1.EventTypeNormal, events.ChaosInjected, "") - return nil -} - -// SetChains sets iptables chains for pods -func (e *endpoint) SetChains(ctx context.Context, pods []v1.Pod, chains []v1alpha1.RawIptables, m *podnetworkchaosmanager.PodNetworkManager, networkchaos *v1alpha1.NetworkChaos) error { - for index := range pods { - pod := &pods[index] - - key, err := cache.MetaNamespaceKeyFunc(pod) - if err != nil { - return err - } - - t := m.WithInit(types.NamespacedName{ - Name: pod.Name, - Namespace: pod.Namespace, - }) - for _, chain := range chains { - t.Append(chain) - } - - networkchaos.Finalizers = finalizer.InsertFinalizer(networkchaos.Finalizers, key) - - } - return nil -} - -// Recover means the reconciler recovers the chaos action -func (e *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - networkchaos, ok := chaos.(*v1alpha1.NetworkChaos) - if !ok { - err := errors.New("chaos is not NetworkChaos") - e.Log.Error(err, "chaos is not NetworkChaos", "chaos", chaos) - return err - } - - if err := e.cleanFinalizersAndRecover(ctx, networkchaos); err != nil { - return err - } - e.Event(networkchaos, v1.EventTypeNormal, events.ChaosRecovered, "") - - return nil -} - -func (e *endpoint) cleanFinalizersAndRecover(ctx context.Context, chaos *v1alpha1.NetworkChaos) error { - var result error - - source := chaos.Namespace + "/" + chaos.Name - m := podnetworkchaosmanager.New(source, e.Log, e.Client) - - for _, key := range chaos.Finalizers { - ns, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - result = multierror.Append(result, err) - continue - } - - _ = m.WithInit(types.NamespacedName{ - Namespace: ns, - Name: name, - }) - } - responses := m.Commit(ctx) - for _, response := range responses { - key := response.Key - err := response.Err - // if pod not found or not running, directly return and giveup recover. - if err != nil { - if err != podnetworkchaosmanager.ErrPodNotFound && err != podnetworkchaosmanager.ErrPodNotRunning { - e.Log.Error(err, "fail to commit", "key", key) - - result = multierror.Append(result, err) - continue - } - - e.Log.Info("pod is not found or not running", "key", key) - } - - chaos.Finalizers = finalizer.RemoveFromFinalizer(chaos.Finalizers, response.Key.String()) - } - e.Log.Info("After recovering", "finalizers", chaos.Finalizers) - - if chaos.Annotations[common.AnnotationCleanFinalizer] == common.AnnotationCleanFinalizerForced { - e.Log.Info("Force cleanup all finalizers", "chaos", chaos) - chaos.Finalizers = make([]string, 0) - return nil - } - - return result -} - -func init() { - router.Register("networkchaos", &v1alpha1.NetworkChaos{}, func(obj runtime.Object) bool { - chaos, ok := obj.(*v1alpha1.NetworkChaos) - if !ok { - return false - } - - return chaos.Spec.Action == v1alpha1.PartitionAction - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/networkchaos/podnetworkchaosmanager/podnetworkchaosmanager.go b/controllers/networkchaos/podnetworkchaosmanager/podnetworkchaosmanager.go deleted file mode 100644 index 45968e1bd5..0000000000 --- a/controllers/networkchaos/podnetworkchaosmanager/podnetworkchaosmanager.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package podnetworkchaosmanager - -import ( - "context" - "errors" - - "github.com/go-logr/logr" - "golang.org/x/sync/errgroup" - v1 "k8s.io/api/core/v1" - k8sError "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/util/retry" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -var ( - // ErrPodNotFound means operate pod may be deleted(almostly) - ErrPodNotFound = errors.New("pod not found") - - // ErrPodNotRunning means operate pod may be not working - // and it's non-sense to make changes on it. - ErrPodNotRunning = errors.New("pod not running") -) - -// PodNetworkManager will save all the related podnetworkchaos -type PodNetworkManager struct { - Source string - Log logr.Logger - client.Client - - Modifications map[types.NamespacedName]*PodNetworkTransaction -} - -// New creates a new PodNetworkMap -func New(source string, logger logr.Logger, client client.Client) *PodNetworkManager { - return &PodNetworkManager{ - Source: source, - Log: logger, - Client: client, - Modifications: make(map[types.NamespacedName]*PodNetworkTransaction), - } -} - -// WithInit will get a transaction or start a transaction with initially clear -func (m *PodNetworkManager) WithInit(key types.NamespacedName) *PodNetworkTransaction { - t, ok := m.Modifications[key] - if ok { - return t - } - - t = &PodNetworkTransaction{} - t.Clear(m.Source) - m.Modifications[key] = t - return t -} - -// CommitResponse is a tuple (Key, Err) -type CommitResponse struct { - Key types.NamespacedName - Err error -} - -// Commit will update all modifications to the cluster -func (m *PodNetworkManager) Commit(ctx context.Context) []CommitResponse { - g := errgroup.Group{} - results := make([]CommitResponse, len(m.Modifications)) - index := 0 - for key, t := range m.Modifications { - i := index - - key := key - t := t - g.Go(func() error { - m.Log.Info("running modification on pod", "key", key, "modification", t) - updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { - chaos := &v1alpha1.PodNetworkChaos{} - - err := m.Client.Get(ctx, key, chaos) - if err != nil { - if !k8sError.IsNotFound(err) { - m.Log.Error(err, "error while getting podnetworkchaos") - return err - } - - pod := v1.Pod{} - err = m.Client.Get(ctx, key, &pod) - if err != nil { - if !k8sError.IsNotFound(err) { - m.Log.Error(err, "error while finding pod") - return err - } - - m.Log.Info("pod not found", "key", key, "error", err.Error()) - err = ErrPodNotFound - return err - } - - if pod.Status.Phase != v1.PodRunning { - m.Log.Info("pod is not running", "key", key) - err = ErrPodNotRunning - return err - } - - chaos.Name = key.Name - chaos.Namespace = key.Namespace - chaos.OwnerReferences = []metav1.OwnerReference{ - { - APIVersion: pod.APIVersion, - Kind: pod.Kind, - Name: pod.Name, - UID: pod.UID, - }, - } - err = m.Client.Create(ctx, chaos) - - if err != nil { - m.Log.Error(err, "error while creating podnetworkchaos") - return err - } - } - - err = t.Apply(chaos) - if err != nil { - m.Log.Error(err, "error while applying transactions", "transaction", t) - return err - } - - return m.Client.Update(ctx, chaos) - }) - - results[i] = CommitResponse{ - Key: key, - Err: updateError, - } - - return nil - }) - - index++ - } - - g.Wait() - return results -} diff --git a/controllers/networkchaos/podnetworkchaosmanager/transaction.go b/controllers/networkchaos/podnetworkchaosmanager/transaction.go deleted file mode 100644 index c83c03c1ef..0000000000 --- a/controllers/networkchaos/podnetworkchaosmanager/transaction.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package podnetworkchaosmanager - -import ( - "fmt" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -// PodNetworkTransaction represents a modification on podnetwork -type PodNetworkTransaction struct { - Steps []Step -} - -// Step represents a step of PodNetworkTransaction -type Step interface { - // Apply will apply an action on podnetworkchaos - Apply(chaos *v1alpha1.PodNetworkChaos) error -} - -// Clear removes all resources with the same source -type Clear struct { - Source string -} - -// Apply runs this action -func (s *Clear) Apply(chaos *v1alpha1.PodNetworkChaos) error { - ipsets := []v1alpha1.RawIPSet{} - for _, ipset := range chaos.Spec.IPSets { - if ipset.Source != s.Source { - ipsets = append(ipsets, ipset) - } - } - chaos.Spec.IPSets = ipsets - - chains := []v1alpha1.RawIptables{} - for _, chain := range chaos.Spec.Iptables { - if chain.Source != s.Source { - chains = append(chains, chain) - } - } - chaos.Spec.Iptables = chains - - qdiscs := []v1alpha1.RawTrafficControl{} - for _, qdisc := range chaos.Spec.TrafficControls { - if qdisc.Source != s.Source { - qdiscs = append(qdiscs, qdisc) - } - } - chaos.Spec.TrafficControls = qdiscs - - return nil -} - -// Append adds an item to corresponding list in podnetworkchaos -type Append struct { - Item interface{} -} - -// Apply runs this action -func (a *Append) Apply(chaos *v1alpha1.PodNetworkChaos) error { - switch item := a.Item.(type) { - case v1alpha1.RawIPSet: - chaos.Spec.IPSets = append(chaos.Spec.IPSets, item) - case v1alpha1.RawIptables: - chaos.Spec.Iptables = append(chaos.Spec.Iptables, item) - case v1alpha1.RawTrafficControl: - chaos.Spec.TrafficControls = append(chaos.Spec.TrafficControls, item) - default: - return fmt.Errorf("unknown type of item") - } - - return nil -} - -// Clear will clear all related items in podnetworkchaos -func (t *PodNetworkTransaction) Clear(source string) { - t.Steps = append(t.Steps, &Clear{ - Source: source, - }) -} - -// Append adds an item to corresponding list in podnetworkchaos -func (t *PodNetworkTransaction) Append(item interface{}) error { - switch item.(type) { - case v1alpha1.RawIPSet, v1alpha1.RawIptables, v1alpha1.RawTrafficControl: - t.Steps = append(t.Steps, &Append{ - Item: item, - }) - return nil - default: - return fmt.Errorf("unknown type of item") - } -} - -// Apply runs every step on the chaos -func (t *PodNetworkTransaction) Apply(chaos *v1alpha1.PodNetworkChaos) error { - for _, s := range t.Steps { - err := s.Apply(chaos) - if err != nil { - return err - } - } - - return nil -} diff --git a/controllers/networkchaos/trafficcontrol/types.go b/controllers/networkchaos/trafficcontrol/types.go deleted file mode 100644 index 5e089d9bb6..0000000000 --- a/controllers/networkchaos/trafficcontrol/types.go +++ /dev/null @@ -1,344 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package trafficcontrol - -import ( - "context" - "errors" - "fmt" - - "github.com/hashicorp/go-multierror" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/cache" - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/common" - "github.com/chaos-mesh/chaos-mesh/controllers/config" - "github.com/chaos-mesh/chaos-mesh/controllers/iochaos/podiochaosmanager" - "github.com/chaos-mesh/chaos-mesh/controllers/networkchaos/podnetworkchaosmanager" - "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/ipset" - "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/netutils" - "github.com/chaos-mesh/chaos-mesh/pkg/events" - "github.com/chaos-mesh/chaos-mesh/pkg/finalizer" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" -) - -const ( - networkTcActionMsg = "network traffic control action duration %s" - networkChaosSourceMsg = "This is a source pod." - networkChaosTargetMsg = "This is a target pod." - - targetIPSetPostFix = "tgt" - sourceIPSetPostFix = "src" -) - -type endpoint struct { - ctx.Context -} - -// Object implements the reconciler.InnerReconciler.Object -func (r *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.NetworkChaos{} -} - -// Apply implements the reconciler.InnerReconciler.Apply -func (r *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - r.Log.Info("traffic control Apply", "req", req, "chaos", chaos) - - networkchaos, ok := chaos.(*v1alpha1.NetworkChaos) - if !ok { - err := errors.New("chaos is not NetworkChaos") - r.Log.Error(err, "chaos is not NetworkChaos", "chaos", chaos) - return err - } - - source := networkchaos.Namespace + "/" + networkchaos.Name - m := podnetworkchaosmanager.New(source, r.Log, r.Client) - - sources, err := selector.SelectAndFilterPods(ctx, r.Client, r.Reader, &networkchaos.Spec, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) - if err != nil { - r.Log.Error(err, "failed to select and filter source pods") - return err - } - - var targets []v1.Pod - - // We should only apply filter when we specify targets - if networkchaos.Spec.Target != nil { - targets, err = selector.SelectAndFilterPods(ctx, r.Client, r.Reader, networkchaos.Spec.Target, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) - if err != nil { - r.Log.Error(err, "failed to select and filter target pods") - return err - } - } - - pods := append(sources, targets...) - type podPositionTuple struct { - Pod v1.Pod - Position string - } - keyPodMap := make(map[types.NamespacedName]podPositionTuple) - for index, pod := range pods { - position := "" - if index < len(sources) { - position = "source" - } else { - position = "target" - } - keyPodMap[types.NamespacedName{ - Name: pod.Name, - Namespace: pod.Namespace, - }] = podPositionTuple{ - Pod: pod, - Position: position, - } - } - - externalCidrs, err := netutils.ResolveCidrs(networkchaos.Spec.ExternalTargets) - if err != nil { - r.Log.Error(err, "failed to resolve external targets") - return err - } - - switch networkchaos.Spec.Direction { - case v1alpha1.To: - err = r.applyTc(ctx, sources, targets, externalCidrs, targetIPSetPostFix, m, networkchaos) - if err != nil { - r.Log.Error(err, "failed to apply traffic control", "sources", sources, "targets", targets) - return err - } - case v1alpha1.From: - err = r.applyTc(ctx, targets, sources, []string{}, sourceIPSetPostFix, m, networkchaos) - if err != nil { - r.Log.Error(err, "failed to apply traffic control", "sources", targets, "targets", sources) - return err - } - case v1alpha1.Both: - err = r.applyTc(ctx, sources, targets, externalCidrs, targetIPSetPostFix, m, networkchaos) - if err != nil { - r.Log.Error(err, "failed to apply traffic control", "sources", sources, "targets", targets) - return err - } - - err = r.applyTc(ctx, targets, sources, []string{}, sourceIPSetPostFix, m, networkchaos) - if err != nil { - r.Log.Error(err, "failed to apply traffic control", "sources", targets, "targets", sources) - return err - } - default: - err = fmt.Errorf("unknown direction %s", networkchaos.Spec.Direction) - r.Log.Error(err, "unknown direction", "direction", networkchaos.Spec.Direction) - return err - } - - responses := m.Commit(ctx) - - networkchaos.Status.Experiment.PodRecords = make([]v1alpha1.PodStatus, 0, len(pods)) - for _, keyErrorTuple := range responses { - key := keyErrorTuple.Key - err := keyErrorTuple.Err - if err != nil { - if err != podiochaosmanager.ErrPodNotFound && err != podiochaosmanager.ErrPodNotRunning { - r.Log.Error(err, "fail to commit") - } else { - r.Log.Info("pod is not found or not running", "key", key) - } - return err - } - - pod := keyPodMap[keyErrorTuple.Key] - ps := v1alpha1.PodStatus{ - Namespace: pod.Pod.Namespace, - Name: pod.Pod.Name, - HostIP: pod.Pod.Status.HostIP, - PodIP: pod.Pod.Status.PodIP, - Action: string(networkchaos.Spec.Action), - } - if pod.Position == "source" { - ps.Message = networkChaosSourceMsg - } else { - ps.Message = networkChaosTargetMsg - } - - // TODO: add source, target and tc action message - if networkchaos.Spec.Duration != nil { - ps.Message += fmt.Sprintf(networkTcActionMsg, *networkchaos.Spec.Duration) - } - networkchaos.Status.Experiment.PodRecords = append(networkchaos.Status.Experiment.PodRecords, ps) - } - - r.Event(networkchaos, v1.EventTypeNormal, events.ChaosInjected, "") - return nil -} - -// Recover means the reconciler recovers the chaos action -func (r *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - networkchaos, ok := chaos.(*v1alpha1.NetworkChaos) - if !ok { - err := errors.New("chaos is not NetworkChaos") - r.Log.Error(err, "chaos is not NetworkChaos", "chaos", chaos) - return err - } - - if err := r.cleanFinalizersAndRecover(ctx, networkchaos); err != nil { - return err - } - r.Event(networkchaos, v1.EventTypeNormal, events.ChaosRecovered, "") - return nil -} - -func (r *endpoint) cleanFinalizersAndRecover(ctx context.Context, chaos *v1alpha1.NetworkChaos) error { - var result error - - source := chaos.Namespace + "/" + chaos.Name - m := podnetworkchaosmanager.New(source, r.Log, r.Client) - - for _, key := range chaos.Finalizers { - ns, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - result = multierror.Append(result, err) - continue - } - - _ = m.WithInit(types.NamespacedName{ - Namespace: ns, - Name: name, - }) - } - responses := m.Commit(ctx) - for _, response := range responses { - key := response.Key - err := response.Err - // if pod not found or not running, directly return and giveup recover. - if err != nil { - if err != podnetworkchaosmanager.ErrPodNotFound && err != podnetworkchaosmanager.ErrPodNotRunning { - r.Log.Error(err, "fail to commit", "key", key) - - result = multierror.Append(result, err) - continue - } - - r.Log.Info("pod is not found or not running", "key", key) - } - - chaos.Finalizers = finalizer.RemoveFromFinalizer(chaos.Finalizers, response.Key.String()) - } - r.Log.Info("After recovering", "finalizers", chaos.Finalizers) - - if chaos.Annotations[common.AnnotationCleanFinalizer] == common.AnnotationCleanFinalizerForced { - r.Log.Info("Force cleanup all finalizers", "chaos", chaos) - chaos.Finalizers = make([]string, 0) - return nil - } - - return result -} - -func (r *endpoint) applyTc( - ctx context.Context, - sources, targets []v1.Pod, - externalTargets []string, - ipSetPostFix string, - m *podnetworkchaosmanager.PodNetworkManager, - networkchaos *v1alpha1.NetworkChaos, -) error { - for index := range sources { - pod := &sources[index] - - key, err := cache.MetaNamespaceKeyFunc(pod) - if err != nil { - return err - } - - networkchaos.Finalizers = finalizer.InsertFinalizer(networkchaos.Finalizers, key) - } - - tcType := v1alpha1.Bandwidth - switch networkchaos.Spec.Action { - case v1alpha1.NetemAction, v1alpha1.DelayAction, v1alpha1.DuplicateAction, v1alpha1.CorruptAction, v1alpha1.LossAction: - tcType = v1alpha1.Netem - case v1alpha1.BandwidthAction: - tcType = v1alpha1.Bandwidth - default: - return fmt.Errorf("unknown action %s", networkchaos.Spec.Action) - } - - // if we don't specify targets, then sources pods apply traffic control on all egress traffic - if len(targets)+len(externalTargets) == 0 { - r.Log.Info("apply traffic control", "sources", sources) - for index := range sources { - pod := &sources[index] - - t := m.WithInit(types.NamespacedName{ - Name: pod.Name, - Namespace: pod.Namespace, - }) - t.Append(v1alpha1.RawTrafficControl{ - Type: tcType, - TcParameter: networkchaos.Spec.TcParameter, - Source: m.Source, - }) - } - return nil - } - - // create ipset contains all target ips - dstIpset := ipset.BuildIPSet(targets, externalTargets, networkchaos, string(tcType[0:2])+ipSetPostFix, m.Source) - r.Log.Info("apply traffic control with filter", "sources", sources, "ipset", dstIpset) - - for index := range sources { - pod := &sources[index] - - t := m.WithInit(types.NamespacedName{ - Name: pod.Name, - Namespace: pod.Namespace, - }) - t.Append(dstIpset) - t.Append(v1alpha1.RawTrafficControl{ - Type: tcType, - TcParameter: networkchaos.Spec.TcParameter, - Source: m.Source, - IPSet: dstIpset.Name, - }) - } - - return nil -} - -func init() { - router.Register("networkchaos", &v1alpha1.NetworkChaos{}, func(obj runtime.Object) bool { - chaos, ok := obj.(*v1alpha1.NetworkChaos) - if !ok { - return false - } - - return chaos.Spec.Action == v1alpha1.BandwidthAction || - chaos.Spec.Action == v1alpha1.NetemAction || - chaos.Spec.Action == v1alpha1.DelayAction || - chaos.Spec.Action == v1alpha1.LossAction || - chaos.Spec.Action == v1alpha1.DuplicateAction || - chaos.Spec.Action == v1alpha1.CorruptAction - - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/networkchaos/trafficcontrol/types_test.go b/controllers/networkchaos/trafficcontrol/types_test.go deleted file mode 100644 index 3b6f695ead..0000000000 --- a/controllers/networkchaos/trafficcontrol/types_test.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package trafficcontrol - -import ( - "context" - "testing" - - . "github.com/onsi/gomega" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/tools/record" - "k8s.io/kubectl/pkg/scheme" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/test" - "github.com/chaos-mesh/chaos-mesh/pkg/mock" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" -) - -func TestReconciler_applyNetem(t *testing.T) { - g := NewWithT(t) - - podObjects, pods := GenerateNPods("p", 1, PodArg{}) - - v1alpha1.SchemeBuilder.AddToScheme(scheme.Scheme) - - r := endpoint{ - Context: ctx.Context{ - Client: fake.NewFakeClientWithScheme(scheme.Scheme, podObjects...), - EventRecorder: &record.FakeRecorder{}, - Log: ctrl.Log.WithName("controllers").WithName("NetworkChaos"), - }, - } - - t.Run("netem without filter", func(t *testing.T) { - networkChaos := v1alpha1.NetworkChaos{ - TypeMeta: metav1.TypeMeta{ - Kind: "NetworkChaos", - APIVersion: "v1", - }, - Spec: v1alpha1.NetworkChaosSpec{ - Action: "netem", - Direction: v1alpha1.To, - TcParameter: v1alpha1.TcParameter{ - Delay: &v1alpha1.DelaySpec{ - Latency: "90ms", - Correlation: "25", - Jitter: "90ms", - }, - Loss: &v1alpha1.LossSpec{ - Loss: "25", - Correlation: "25", - }, - }, - }, - } - - defer mock.With("MockSelectAndFilterPods", func() []v1.Pod { - return pods - })() - defer mock.With("MockChaosDaemonClient", &test.MockChaosDaemonClient{})() - - err := r.Apply(context.TODO(), ctrl.Request{}, &networkChaos) - - g.Expect(err).ToNot(HaveOccurred()) - }) - - t.Run("netem with targets", func(t *testing.T) { - networkChaos := v1alpha1.NetworkChaos{ - TypeMeta: metav1.TypeMeta{ - Kind: "TimeChaos", - APIVersion: "v1", - }, - Spec: v1alpha1.NetworkChaosSpec{ - Action: "netem", - TcParameter: v1alpha1.TcParameter{ - Delay: &v1alpha1.DelaySpec{ - Latency: "90ms", - Correlation: "25", - Jitter: "90ms", - }, - Loss: &v1alpha1.LossSpec{ - Loss: "25", - Correlation: "25", - }, - }, - Direction: v1alpha1.To, - Target: &v1alpha1.Target{ - TargetSelector: v1alpha1.SelectorSpec{}, - }, - ExternalTargets: []string{"8.8.8.8", "www.google.com"}, - }, - } - - defer mock.With("MockSelectAndFilterPods", func() []v1.Pod { - return pods - })() - defer mock.With("MockChaosDaemonClient", &test.MockChaosDaemonClient{})() - - err := r.Apply(context.TODO(), ctrl.Request{}, &networkChaos) - - g.Expect(err).ToNot(HaveOccurred()) - }) -} diff --git a/controllers/podchaos/containerkill/containerkill_suite_test.go b/controllers/podchaos/containerkill/containerkill_suite_test.go deleted file mode 100644 index 139f338127..0000000000 --- a/controllers/podchaos/containerkill/containerkill_suite_test.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package containerkill - -import ( - "context" - "errors" - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/tools/record" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - . "github.com/chaos-mesh/chaos-mesh/controllers/test" - "github.com/chaos-mesh/chaos-mesh/pkg/mock" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" -) - -func TestContainerKill(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "ContainerKill Suite", - []Reporter{envtest.NewlineReporter{}}) -} - -var _ = BeforeSuite(func(done Done) { - logf.SetLogger(zap.LoggerTo(GinkgoWriter, true)) - - Expect(v1.AddToScheme(scheme.Scheme)).To(Succeed()) - Expect(v1alpha1.AddToScheme(scheme.Scheme)).To(Succeed()) - - close(done) -}, 60) - -var _ = AfterSuite(func() { -}) - -var _ = Describe("PodChaos", func() { - Context("ContainerKill", func() { - objs, _ := GenerateNPods("p", 1, PodArg{ContainerStatus: v1.ContainerStatus{ - ContainerID: "fake-container-id", - Name: "container-name", - }}) - - podChaos := v1alpha1.PodChaos{ - TypeMeta: metav1.TypeMeta{ - Kind: "PodChaos", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "podchaos-name", - }, - Spec: v1alpha1.PodChaosSpec{ - Selector: v1alpha1.SelectorSpec{}, - Mode: v1alpha1.OnePodMode, - ContainerName: "container-name", - Scheduler: &v1alpha1.SchedulerSpec{Cron: "@hourly"}, - }, - } - - r := endpoint{ - Context: ctx.Context{ - Client: fake.NewFakeClientWithScheme(scheme.Scheme, objs...), - EventRecorder: &record.FakeRecorder{}, - Log: ctrl.Log.WithName("controllers").WithName("PodChaos"), - }, - } - - It("ContainerKill Apply", func() { - defer mock.With("MockChaosDaemonClient", &MockChaosDaemonClient{})() - - err := r.Apply(context.TODO(), ctrl.Request{}, &podChaos) - Expect(err).ToNot(HaveOccurred()) - - err = r.Recover(context.TODO(), ctrl.Request{}, &podChaos) - Expect(err).ToNot(HaveOccurred()) - }) - - It("ContainerKill Apply Error", func() { - defer mock.With("MockChaosDaemonClient", &MockChaosDaemonClient{})() - defer mock.With("MockContainerKillError", errors.New("ContainerKillError"))() - - err := r.Apply(context.TODO(), ctrl.Request{}, &podChaos) - - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("ContainerKillError")) - }) - }) -}) diff --git a/controllers/podchaos/containerkill/types.go b/controllers/podchaos/containerkill/types.go deleted file mode 100644 index bde931be1e..0000000000 --- a/controllers/podchaos/containerkill/types.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package containerkill - -import ( - "context" - "errors" - "fmt" - - "golang.org/x/sync/errgroup" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/config" - "github.com/chaos-mesh/chaos-mesh/controllers/utils" - pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" - "github.com/chaos-mesh/chaos-mesh/pkg/events" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" -) - -const ( - containerKillActionMsg = "delete container %s" -) - -type endpoint struct { - ctx.Context -} - -// Apply implements the reconciler.InnerReconciler.Apply -func (r *endpoint) Apply(ctx context.Context, req ctrl.Request, obj v1alpha1.InnerObject) error { - var err error - - podchaos, ok := obj.(*v1alpha1.PodChaos) - if !ok { - err = errors.New("chaos is not PodChaos") - r.Log.Error(err, "chaos is not PodChaos", "chaos", obj) - return err - } - - if podchaos.Spec.ContainerName == "" { - r.Log.Error(nil, "the name of container is empty", "name", req.Name, "namespace", req.Namespace) - return fmt.Errorf("podchaos[%s/%s] the name of container is empty", podchaos.Namespace, podchaos.Name) - } - - pods, err := selector.SelectAndFilterPods(ctx, r.Client, r.Reader, &podchaos.Spec, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) - if err != nil { - r.Log.Error(err, "fail to select and filter pods") - return err - } - - var podsNotHaveContainer []string - for podIndex := range pods { - pod := &pods[podIndex] - haveContainer := false - - for _, item := range pod.Status.ContainerStatuses { - if item.Name == podchaos.Spec.ContainerName { - haveContainer = true - break - } - } - - if !haveContainer { - podsNotHaveContainer = append(podsNotHaveContainer, pod.Name) - r.Log.Error(nil, fmt.Sprintf("the pod %s doesn't have container %s", pod.Name, podchaos.Spec.ContainerName)) - } - } - - if len(podsNotHaveContainer) != 0 { - return fmt.Errorf("the pod %v doesn't have container %s", podsNotHaveContainer, podchaos.Spec.ContainerName) - } - - g := errgroup.Group{} - for podIndex := range pods { - pod := &pods[podIndex] - - for containerIndex := range pod.Status.ContainerStatuses { - containerName := pod.Status.ContainerStatuses[containerIndex].Name - containerID := pod.Status.ContainerStatuses[containerIndex].ContainerID - - if containerName == podchaos.Spec.ContainerName { - g.Go(func() error { - err = r.KillContainer(ctx, pod, containerID) - if err != nil { - r.Log.Error(err, fmt.Sprintf( - "failed to kill container: %s, pod: %s, namespace: %s", - containerName, pod.Name, pod.Namespace)) - } - return err - }) - } - } - } - - if err := g.Wait(); err != nil { - return err - } - - podchaos.Status.Experiment.PodRecords = make([]v1alpha1.PodStatus, 0, len(pods)) - for _, pod := range pods { - ps := v1alpha1.PodStatus{ - Namespace: pod.Namespace, - Name: pod.Name, - HostIP: pod.Status.HostIP, - PodIP: pod.Status.PodIP, - Action: string(podchaos.Spec.Action), - Message: fmt.Sprintf(containerKillActionMsg, podchaos.Spec.ContainerName), - } - - podchaos.Status.Experiment.PodRecords = append(podchaos.Status.Experiment.PodRecords, ps) - } - r.Event(podchaos, v1.EventTypeNormal, events.ChaosRecovered, "") - return nil -} - -// Recover implements the reconciler.InnerReconciler.Recover -func (r *endpoint) Recover(ctx context.Context, req ctrl.Request, obj v1alpha1.InnerObject) error { - return nil -} - -// Object implements the reconciler.InnerReconciler.Object -func (r *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.PodChaos{} -} - -// KillContainer kills container according to containerID -// Use client in chaos-daemon -func (r *endpoint) KillContainer(ctx context.Context, pod *v1.Pod, containerID string) error { - r.Log.Info("Try to kill container", "namespace", pod.Namespace, "podName", pod.Name, "containerID", containerID) - - pbClient, err := utils.NewChaosDaemonClient(ctx, r.Client, pod) - if err != nil { - return err - } - defer pbClient.Close() - - if len(pod.Status.ContainerStatuses) == 0 { - return fmt.Errorf("%s %s can't get the state of container", pod.Namespace, pod.Name) - } - - if _, err = pbClient.ContainerKill(ctx, &pb.ContainerRequest{ - Action: &pb.ContainerAction{ - Action: pb.ContainerAction_KILL, - }, - ContainerId: containerID, - }); err != nil { - r.Log.Error(err, "kill container error", "namespace", pod.Namespace, "podName", pod.Name, "containerID", containerID) - return err - } - - return nil -} - -func init() { - router.Register("podchaos", &v1alpha1.PodChaos{}, func(obj runtime.Object) bool { - chaos, ok := obj.(*v1alpha1.PodChaos) - if !ok { - return false - } - - return chaos.Spec.Action == v1alpha1.ContainerKillAction - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/podchaos/podfailure/podfailure_suite_test.go b/controllers/podchaos/podfailure/podfailure_suite_test.go deleted file mode 100644 index 8f65351ec0..0000000000 --- a/controllers/podchaos/podfailure/podfailure_suite_test.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package podfailure - -import ( - "context" - "testing" - - "k8s.io/client-go/kubernetes/scheme" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/tools/record" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - . "github.com/chaos-mesh/chaos-mesh/controllers/test" - "github.com/chaos-mesh/chaos-mesh/pkg/mock" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" -) - -func TestPodFailure(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "PodFailure Suite", - []Reporter{envtest.NewlineReporter{}}) -} - -var _ = BeforeSuite(func(done Done) { - logf.SetLogger(zap.LoggerTo(GinkgoWriter, true)) - - Expect(v1.AddToScheme(scheme.Scheme)).To(Succeed()) - Expect(v1alpha1.AddToScheme(scheme.Scheme)).To(Succeed()) - - close(done) -}, 60) - -var _ = AfterSuite(func() { -}) - -var _ = Describe("PodChaos", func() { - Context("PodFailure", func() { - objs, pods := GenerateNPods("p", 1, PodArg{ContainerStatus: v1.ContainerStatus{ - ContainerID: "fake-container-id", - Name: "container-name", - }}) - - podChaos := v1alpha1.PodChaos{ - TypeMeta: metav1.TypeMeta{ - Kind: "PodChaos", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "podchaos-name", - }, - Spec: v1alpha1.PodChaosSpec{ - Selector: v1alpha1.SelectorSpec{Namespaces: []string{metav1.NamespaceDefault}}, - Mode: v1alpha1.OnePodMode, - ContainerName: "container-name", - Scheduler: &v1alpha1.SchedulerSpec{Cron: "@hourly"}, - }, - } - - r := endpoint{ - Context: ctx.Context{ - Client: fake.NewFakeClientWithScheme(scheme.Scheme, objs...), - EventRecorder: &record.FakeRecorder{}, - Log: ctrl.Log.WithName("controllers").WithName("PodChaos"), - }, - } - - It("PodFailure Action", func() { - defer mock.With("MockChaosDaemonClient", &MockChaosDaemonClient{})() - defer mock.With("MockSelectAndFilterPods", func() []v1.Pod { - return pods - })() - - var err error - - err = r.Apply(context.TODO(), ctrl.Request{}, &podChaos) - Expect(err).ToNot(HaveOccurred()) - - err = r.Recover(context.TODO(), ctrl.Request{}, &podChaos) - Expect(err).ToNot(HaveOccurred()) - }) - - }) -}) diff --git a/controllers/podchaos/podfailure/types.go b/controllers/podchaos/podfailure/types.go deleted file mode 100644 index de076c2b65..0000000000 --- a/controllers/podchaos/podfailure/types.go +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package podfailure - -import ( - "context" - "errors" - "fmt" - - "github.com/go-logr/logr" - "golang.org/x/sync/errgroup" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/cache" - "k8s.io/client-go/util/retry" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/config" - "github.com/chaos-mesh/chaos-mesh/controllers/recover" - "github.com/chaos-mesh/chaos-mesh/pkg/annotation" - "github.com/chaos-mesh/chaos-mesh/pkg/events" - "github.com/chaos-mesh/chaos-mesh/pkg/finalizer" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" -) - -const ( - - // Always fails a container - pauseImage = "gcr.io/google-containers/pause:latest" - - podFailureActionMsg = "pod failure duration %s" -) - -var ( - errNotOperatedChaos = errors.New("the pod not operated by podChaos") -) - -type endpoint struct { - ctx.Context -} - -type recoverer struct { - client.Client - Log logr.Logger -} - -// Object implements the reconciler.InnerReconciler.Object -func (r *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.PodChaos{} -} - -// Apply implements the reconciler.InnerReconciler.Apply -func (r *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - - podchaos, ok := chaos.(*v1alpha1.PodChaos) - if !ok { - err := errors.New("chaos is not PodChaos") - r.Log.Error(err, "chaos is not PodChaos", "chaos", chaos) - return err - } - - pods, err := selector.SelectAndFilterPods(ctx, r.Client, r.Reader, &podchaos.Spec, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) - if err != nil { - r.Log.Error(err, "failed to select and filter pods") - return err - } - err = r.failAllPods(ctx, pods, podchaos) - if err != nil { - return err - } - - podchaos.Status.Experiment.PodRecords = make([]v1alpha1.PodStatus, 0, len(pods)) - for _, pod := range pods { - ps := v1alpha1.PodStatus{ - Namespace: pod.Namespace, - Name: pod.Name, - HostIP: pod.Status.HostIP, - PodIP: pod.Status.PodIP, - Action: string(podchaos.Spec.Action), - } - if podchaos.Spec.Duration != nil { - ps.Message = fmt.Sprintf(podFailureActionMsg, *podchaos.Spec.Duration) - } - podchaos.Status.Experiment.PodRecords = append(podchaos.Status.Experiment.PodRecords, ps) - } - r.Event(podchaos, v1.EventTypeNormal, events.ChaosInjected, "") - return nil -} - -// Recover means the reconciler recovers the chaos action -func (r *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - podchaos, ok := chaos.(*v1alpha1.PodChaos) - if !ok { - err := errors.New("chaos is not PodChaos") - r.Log.Error(err, "chaos is not PodChaos", "chaos", chaos) - return err - } - - rd := recover.Delegate{Client: r.Client, Log: r.Log, RecoverIntf: &recoverer{r.Client, r.Log}} - - finalizers, err := rd.CleanFinalizersAndRecover(ctx, chaos, podchaos.Finalizers, podchaos.Annotations) - if err != nil { - return err - } - podchaos.Finalizers = finalizers - - r.Event(podchaos, v1.EventTypeNormal, events.ChaosRecovered, "") - return nil -} - -func (r *recoverer) RecoverPod(ctx context.Context, pod *v1.Pod, somechaos v1alpha1.InnerObject) error { - // judged type in `Recover` already so no need to judge again - chaos, _ := somechaos.(*v1alpha1.PodChaos) - r.Log.Info("Recovering", "namespace", pod.Namespace, "name", pod.Name) - - containerChaosCount := 0 - for index := range pod.Spec.Containers { - name := pod.Spec.Containers[index].Name - key := annotation.GenKeyForImage(chaos, name) - - if pod.Annotations == nil { - pod.Annotations = make(map[string]string) - } - // check annotation - if _, ok := pod.Annotations[key]; ok { - containerChaosCount++ - } - } - if containerChaosCount == 0 { - r.Log.Error(errNotOperatedChaos, "the pod not operated by podChaos", "namespace", pod.Namespace, "name", pod.Name) - return nil - } - // chaos-mesh don't support - return r.Delete(ctx, pod, &client.DeleteOptions{ - GracePeriodSeconds: new(int64), // PeriodSeconds has to be set specifically - }) -} - -func (r *endpoint) failAllPods(ctx context.Context, pods []v1.Pod, podchaos *v1alpha1.PodChaos) error { - g := errgroup.Group{} - for index := range pods { - pod := &pods[index] - - key, err := cache.MetaNamespaceKeyFunc(pod) - if err != nil { - return err - } - podchaos.Finalizers = finalizer.InsertFinalizer(podchaos.Finalizers, key) - - g.Go(func() error { - return r.failPod(ctx, pod, podchaos) - }) - } - - return g.Wait() -} - -func (r *endpoint) failPod(ctx context.Context, pod *v1.Pod, podchaos *v1alpha1.PodChaos) error { - r.Log.Info("Try to inject pod-failure", "namespace", pod.Namespace, "name", pod.Name) - - // TODO: check the annotations or others in case that this pod is used by other chaos - for index := range pod.Spec.InitContainers { - originImage := pod.Spec.InitContainers[index].Image - name := pod.Spec.InitContainers[index].Name - - key := annotation.GenKeyForImage(podchaos, name) - if pod.Annotations == nil { - pod.Annotations = make(map[string]string) - } - - // If the annotation is already existed, we could skip the reconcile for this container - if _, ok := pod.Annotations[key]; ok { - continue - } - pod.Annotations[key] = originImage - pod.Spec.InitContainers[index].Image = pauseImage - } - - for index := range pod.Spec.Containers { - originImage := pod.Spec.Containers[index].Image - name := pod.Spec.Containers[index].Name - - key := annotation.GenKeyForImage(podchaos, name) - if pod.Annotations == nil { - pod.Annotations = make(map[string]string) - } - - // If the annotation is already existed, we could skip the reconcile for this container - if _, ok := pod.Annotations[key]; ok { - continue - } - pod.Annotations[key] = originImage - pod.Spec.Containers[index].Image = pauseImage - } - updateErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { - var newPod v1.Pod - getErr := r.Client.Get(ctx, types.NamespacedName{ - Namespace: pod.Namespace, - Name: pod.Name, - }, &newPod) - if getErr != nil { - return getErr - } - newPod.Annotations = pod.Annotations - newPod.Spec.Containers = pod.Spec.Containers - newPod.Spec.InitContainers = pod.Spec.InitContainers - return r.Client.Update(ctx, &newPod) - }) - if updateErr != nil { - r.Log.Error(updateErr, "unable to use fake image on pod") - return updateErr - } - - ps := v1alpha1.PodStatus{ - Namespace: pod.Namespace, - Name: pod.Name, - HostIP: pod.Status.HostIP, - PodIP: pod.Status.PodIP, - Action: string(podchaos.Spec.Action), - } - if podchaos.Spec.Duration != nil { - ps.Message = fmt.Sprintf(podFailureActionMsg, *podchaos.Spec.Duration) - } - - podchaos.Status.Experiment.PodRecords = append(podchaos.Status.Experiment.PodRecords, ps) - - return nil -} - -func init() { - router.Register("podchaos", &v1alpha1.PodChaos{}, func(obj runtime.Object) bool { - chaos, ok := obj.(*v1alpha1.PodChaos) - if !ok { - return false - } - - return chaos.Spec.Action == v1alpha1.PodFailureAction - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/podchaos/podkill/podkill_suite_test.go b/controllers/podchaos/podkill/podkill_suite_test.go deleted file mode 100644 index cf369fe2d6..0000000000 --- a/controllers/podchaos/podkill/podkill_suite_test.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package podkill - -import ( - "context" - "testing" - - "k8s.io/client-go/kubernetes/scheme" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/tools/record" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - . "github.com/chaos-mesh/chaos-mesh/controllers/test" - "github.com/chaos-mesh/chaos-mesh/pkg/mock" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" -) - -func TestPodKill(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "PodKill Suite", - []Reporter{envtest.NewlineReporter{}}) -} - -var _ = BeforeSuite(func(done Done) { - logf.SetLogger(zap.LoggerTo(GinkgoWriter, true)) - - Expect(v1.AddToScheme(scheme.Scheme)).To(Succeed()) - Expect(v1alpha1.AddToScheme(scheme.Scheme)).To(Succeed()) - - close(done) -}, 60) - -var _ = AfterSuite(func() { -}) - -var _ = Describe("PodChaos", func() { - Context("PodKill", func() { - objs, pods := GenerateNPods("p", 1, PodArg{ContainerStatus: v1.ContainerStatus{ - ContainerID: "fake-container-id", - Name: "container-name", - }}) - - podChaos := v1alpha1.PodChaos{ - TypeMeta: metav1.TypeMeta{ - Kind: "PodChaos", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "podchaos-name", - }, - Spec: v1alpha1.PodChaosSpec{ - Selector: v1alpha1.SelectorSpec{Namespaces: []string{metav1.NamespaceDefault}}, - Mode: v1alpha1.OnePodMode, - ContainerName: "container-name", - Scheduler: &v1alpha1.SchedulerSpec{Cron: "@hourly"}, - }, - } - - r := endpoint{ - Context: ctx.Context{ - Client: fake.NewFakeClientWithScheme(scheme.Scheme, objs...), - EventRecorder: &record.FakeRecorder{}, - Log: ctrl.Log.WithName("controllers").WithName("PodChaos"), - }, - } - - It("PodKill Action", func() { - defer mock.With("MockChaosDaemonClient", &MockChaosDaemonClient{})() - defer mock.With("MockSelectAndFilterPods", func() []v1.Pod { - return pods - })() - - var err error - - err = r.Apply(context.TODO(), ctrl.Request{}, &podChaos) - Expect(err).ToNot(HaveOccurred()) - - // pod "p0" already deleted - err = r.Apply(context.TODO(), ctrl.Request{}, &podChaos) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("pods \"p0\" not found")) - - err = r.Recover(context.TODO(), ctrl.Request{}, &podChaos) - Expect(err).ToNot(HaveOccurred()) - }) - }) -}) diff --git a/controllers/podchaos/podkill/types.go b/controllers/podchaos/podkill/types.go deleted file mode 100644 index 30dd0a2286..0000000000 --- a/controllers/podchaos/podkill/types.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package podkill - -import ( - "context" - "errors" - - "golang.org/x/sync/errgroup" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/config" - "github.com/chaos-mesh/chaos-mesh/pkg/events" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" -) - -const ( - podKillActionMsg = "delete pod" -) - -type endpoint struct { - ctx.Context -} - -// Apply implements the reconciler.InnerReconciler.Apply -func (r *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - podchaos, ok := chaos.(*v1alpha1.PodChaos) - if !ok { - err := errors.New("chaos is not PodChaos") - r.Log.Error(err, "chaos is not PodChaos", "chaos", chaos) - return err - } - pods, err := selector.SelectAndFilterPods(ctx, r.Client, r.Reader, &podchaos.Spec, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) - if err != nil { - r.Log.Error(err, "fail to select and generate pods") - return err - } - - g := errgroup.Group{} - for index := range pods { - pod := &pods[index] - g.Go(func() error { - r.Log.Info("Deleting", "namespace", pod.Namespace, "name", pod.Name) - - if err := r.Delete(ctx, pod, &client.DeleteOptions{ - GracePeriodSeconds: &podchaos.Spec.GracePeriod, // PeriodSeconds has to be set specifically - }); err != nil { - r.Log.Error(err, "unable to delete pod") - return err - } - return nil - }) - } - - if err := g.Wait(); err != nil { - return err - } - podchaos.Status.Experiment.PodRecords = make([]v1alpha1.PodStatus, 0, len(pods)) - for _, pod := range pods { - ps := v1alpha1.PodStatus{ - Namespace: pod.Namespace, - Name: pod.Name, - HostIP: pod.Status.HostIP, - PodIP: pod.Status.PodIP, - Action: string(podchaos.Spec.Action), - Message: podKillActionMsg, - } - - podchaos.Status.Experiment.PodRecords = append(podchaos.Status.Experiment.PodRecords, ps) - } - - r.Event(podchaos, v1.EventTypeNormal, events.ChaosRecovered, "") - return nil -} - -// Recover implements the reconciler.InnerReconciler.Recover -func (r *endpoint) Recover(ctx context.Context, req ctrl.Request, obj v1alpha1.InnerObject) error { - return nil -} - -// Object implements the reconciler.InnerReconciler.Object -func (r *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.PodChaos{} -} - -func init() { - router.Register("podchaos", &v1alpha1.PodChaos{}, func(obj runtime.Object) bool { - chaos, ok := obj.(*v1alpha1.PodChaos) - if !ok { - return false - } - - return chaos.Spec.Action == v1alpha1.PodKillAction - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/podhttpchaos/controller.go b/controllers/podhttpchaos/controller.go new file mode 100644 index 0000000000..f554e2627e --- /dev/null +++ b/controllers/podhttpchaos/controller.go @@ -0,0 +1,249 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podhttpchaos + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/record" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/tproxyconfig" +) + +// Reconciler applys podhttpchaos +type Reconciler struct { + client.Client + + Recorder record.EventRecorder + Log logr.Logger + ChaosDaemonClientBuilder *chaosdaemon.ChaosDaemonClientBuilder +} + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + obj := &v1alpha1.PodHttpChaos{} + + if err := r.Client.Get(ctx, req.NamespacedName, obj); err != nil { + if apierrors.IsNotFound(err) { + r.Log.Info("chaos not found") + } else { + // TODO: handle this error + r.Log.Error(err, "unable to get chaos") + } + return ctrl.Result{}, nil + } + + if obj.ObjectMeta.Generation <= obj.Status.ObservedGeneration && obj.Status.FailedMessage == "" { + r.Log.Info("the target pod has been up to date", "pod", obj.Namespace+"/"+obj.Name) + return ctrl.Result{}, nil + } + + r.Log.Info("updating http chaos", "pod", obj.Namespace+"/"+obj.Name, "spec", obj.Spec) + + pod := &v1.Pod{} + + err := r.Client.Get(ctx, types.NamespacedName{ + Name: obj.Name, + Namespace: obj.Namespace, + }, pod) + if err != nil { + err = errors.Wrapf(err, "failed to apply for pod %s/%s", pod.Namespace, pod.Name) + r.Log.Error(err, "fail to find pod") + return ctrl.Result{}, nil + } + + observedGeneration := obj.ObjectMeta.Generation + pid := obj.Status.Pid + startTime := obj.Status.StartTime + + defer func() { + var failedMessage string + if err != nil { + failedMessage = err.Error() + } + + updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + obj := &v1alpha1.PodHttpChaos{} + + if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil { + r.Log.Error(err, "unable to get chaos") + return err + } + + obj.Status.FailedMessage = failedMessage + obj.Status.ObservedGeneration = observedGeneration + obj.Status.Pid = pid + obj.Status.StartTime = startTime + + return r.Client.Status().Update(context.TODO(), obj) + }) + + if updateError != nil { + updateError = errors.Wrapf(updateError, "failed to apply for pod %s/%s", pod.Namespace, pod.Name) + r.Log.Error(updateError, "fail to update") + r.Recorder.Eventf(obj, "Normal", "Failed", "Failed to update status: %s", updateError.Error()) + } + }() + + pbClient, err := r.ChaosDaemonClientBuilder.Build(ctx, pod, &types.NamespacedName{ + Namespace: obj.Namespace, + Name: obj.Name, + }) + if err != nil { + err = errors.Wrapf(err, "failed to apply for pod %s/%s", pod.Namespace, pod.Name) + r.Recorder.Event(obj, "Warning", "Failed", err.Error()) + return ctrl.Result{Requeue: true}, nil + } + defer pbClient.Close() + + if len(pod.Status.ContainerStatuses) == 0 { + err = errors.Wrapf(utils.ErrContainerNotFound, "pod %s/%s has empty container status", pod.Namespace, pod.Name) + r.Recorder.Event(obj, "Warning", "Failed", err.Error()) + return ctrl.Result{}, nil + } + + containerID := pod.Status.ContainerStatuses[0].ContainerID + + rules := make([]v1alpha1.PodHttpChaosBaseRule, 0) + proxyPortsMap := make(map[uint32]bool) + + for _, rule := range obj.Spec.Rules { + proxyPortsMap[uint32(rule.Port)] = true + rules = append(rules, rule.PodHttpChaosBaseRule) + } + + var proxyPorts []uint32 + for port := range proxyPortsMap { + proxyPorts = append(proxyPorts, port) + } + + inputRules, err := json.Marshal(rules) + if err != nil { + err = errors.Wrapf(err, "failed to apply for pod %s/%s", pod.Namespace, pod.Name) + r.Recorder.Event(obj, "Warning", "Failed", err.Error()) + return ctrl.Result{}, nil + } + + inputTLS := []byte("") + if obj.Spec.TLS != nil { + tlsKeys := obj.Spec.TLS + secret := v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: tlsKeys.SecretName, + Namespace: tlsKeys.SecretNamespace, + }, + } + if err := r.Client.Get(context.TODO(), req.NamespacedName, &secret); err != nil { + r.Log.Error(err, "unable to get secret") + return ctrl.Result{}, nil + } + + cert, ok := secret.Data[tlsKeys.CertName] + if !ok { + err = errors.Wrapf(err, "get cert %s", tlsKeys.CertName) + r.Recorder.Event(obj, "Warning", "Failed", err.Error()) + return ctrl.Result{}, nil + } + + key, ok := secret.Data[tlsKeys.KeyName] + if !ok { + err = errors.Wrapf(err, "get key %s", tlsKeys.KeyName) + r.Recorder.Event(obj, "Warning", "Failed", err.Error()) + return ctrl.Result{}, nil + } + + var ca []byte + if tlsKeys.CAName != nil { + ca, ok = secret.Data[*tlsKeys.CAName] + if !ok { + err = errors.Wrapf(err, "get ca %s", *tlsKeys.CAName) + r.Recorder.Event(obj, "Warning", "Failed", err.Error()) + return ctrl.Result{}, nil + } + } + + tlsConfig := tproxyconfig.TLSConfig{ + CertFile: tproxyconfig.TLSConfigItem{ + Type: "Contents", + Value: cert, + }, + KeyFile: tproxyconfig.TLSConfigItem{ + Type: "Contents", + Value: key, + }, + } + + if ca != nil { + tlsConfig.CAFile = &tproxyconfig.TLSConfigItem{ + Type: "Contents", + Value: ca, + } + } + + inputTLS, err = json.Marshal(tlsConfig) + if err != nil { + err = errors.Wrapf(err, "apply for pod %s/%s", pod.Namespace, pod.Name) + r.Recorder.Event(obj, "Warning", "Failed", err.Error()) + return ctrl.Result{}, nil + } + } + + r.Log.Info("input with", "rules", string(inputRules)) + + res, err := pbClient.ApplyHttpChaos(ctx, &pb.ApplyHttpChaosRequest{ + Rules: string(inputRules), + Tls: string(inputTLS), + ProxyPorts: proxyPorts, + ContainerId: containerID, + + Instance: obj.Status.Pid, + StartTime: obj.Status.StartTime, + EnterNS: true, + }) + if err != nil { + err = errors.Wrapf(err, "failed to apply for pod %s/%s", pod.Namespace, pod.Name) + r.Recorder.Event(obj, "Warning", "Failed", err.Error()) + return ctrl.Result{Requeue: true}, nil + } + + if res.StatusCode != http.StatusOK { + err = errors.Wrapf(fmt.Errorf("%s", res.Error), + "failed to apply for pod %s/%s, status(%d)", + pod.Namespace, pod.Name, res.StatusCode) + r.Recorder.Event(obj, "Warning", "Failed", err.Error()) + return ctrl.Result{Requeue: true}, nil + } + + pid = res.Instance + startTime = res.StartTime + + return ctrl.Result{}, nil +} diff --git a/controllers/podhttpchaos/fx.go b/controllers/podhttpchaos/fx.go new file mode 100644 index 0000000000..d23e0165af --- /dev/null +++ b/controllers/podhttpchaos/fx.go @@ -0,0 +1,55 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podhttpchaos + +import ( + "reflect" + + "github.com/go-logr/logr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/builder" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon" +) + +func Bootstrap(mgr ctrl.Manager, client client.Client, logger logr.Logger, b *chaosdaemon.ChaosDaemonClientBuilder) error { + if !config.ShouldSpawnController("podhttpchaos") { + return nil + } + + return builder.Default(mgr). + For(&v1alpha1.PodHttpChaos{}). + Named("podhttpchaos"). + WithEventFilter(predicate.Funcs{ + UpdateFunc: func(e event.UpdateEvent) bool { + oldObj := e.ObjectOld.(*v1alpha1.PodHttpChaos) + newObj := e.ObjectNew.(*v1alpha1.PodHttpChaos) + + return !reflect.DeepEqual(oldObj.Spec, newObj.Spec) + }, + }). + Complete(&Reconciler{ + Client: client, + Log: logger.WithName("podhttpchaos"), + Recorder: mgr.GetEventRecorderFor("podhttpchaos"), + ChaosDaemonClientBuilder: b, + }) +} diff --git a/controllers/podiochaos/controller.go b/controllers/podiochaos/controller.go new file mode 100644 index 0000000000..3844199956 --- /dev/null +++ b/controllers/podiochaos/controller.go @@ -0,0 +1,170 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podiochaos + +import ( + "context" + "encoding/json" + "strings" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/record" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" +) + +// Reconciler applys podioworkchaos +type Reconciler struct { + client.Client + Recorder record.EventRecorder + + Log logr.Logger + ChaosDaemonClientBuilder *chaosdaemon.ChaosDaemonClientBuilder +} + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + obj := &v1alpha1.PodIOChaos{} + + if err := r.Client.Get(ctx, req.NamespacedName, obj); err != nil { + if apierrors.IsNotFound(err) { + r.Log.Info("chaos not found") + } else { + // TODO: handle this error + r.Log.Error(err, "unable to get chaos") + } + return ctrl.Result{}, nil + } + + if obj.ObjectMeta.Generation <= obj.Status.ObservedGeneration && obj.Status.FailedMessage == "" { + r.Log.Info("the target pod has been up to date", "pod", obj.Namespace+"/"+obj.Name) + return ctrl.Result{}, nil + } + + r.Log.Info("updating io chaos", "pod", obj.Namespace+"/"+obj.Name, "spec", obj.Spec) + + pod := &v1.Pod{} + + err := r.Client.Get(ctx, types.NamespacedName{ + Name: obj.Name, + Namespace: obj.Namespace, + }, pod) + if err != nil { + r.Log.Error(err, "fail to find pod") + return ctrl.Result{}, nil + } + + failedMessage := "" + observedGeneration := obj.ObjectMeta.Generation + pid := obj.Status.Pid + startTime := obj.Status.StartTime + defer func() { + if err != nil { + failedMessage = err.Error() + } + + updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + obj := &v1alpha1.PodIOChaos{} + + if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil { + r.Log.Error(err, "unable to get chaos") + return err + } + + obj.Status.FailedMessage = failedMessage + obj.Status.ObservedGeneration = observedGeneration + obj.Status.Pid = pid + obj.Status.StartTime = startTime + + return r.Client.Status().Update(context.TODO(), obj) + }) + + if updateError != nil { + r.Log.Error(updateError, "fail to update") + r.Recorder.Eventf(obj, "Normal", "Failed", "Failed to update status: %s", updateError.Error()) + } + }() + + pbClient, err := r.ChaosDaemonClientBuilder.Build(ctx, pod, &types.NamespacedName{ + Namespace: obj.Namespace, + Name: obj.Name, + }) + if err != nil { + r.Recorder.Event(obj, "Warning", "Failed", err.Error()) + return ctrl.Result{Requeue: true}, nil + } + defer pbClient.Close() + + if len(pod.Status.ContainerStatuses) == 0 { + err = errors.Wrapf(utils.ErrContainerNotFound, "pod %s/%s has empty container status", pod.Namespace, pod.Name) + r.Recorder.Event(obj, "Warning", "Failed", err.Error()) + return ctrl.Result{}, nil + } + + containerID := pod.Status.ContainerStatuses[0].ContainerID + if obj.Spec.Container != nil && + len(strings.TrimSpace(*obj.Spec.Container)) != 0 { + containerID = "" + for _, container := range pod.Status.ContainerStatuses { + if container.Name == *obj.Spec.Container { + containerID = container.ContainerID + break + } + } + if len(containerID) == 0 { + err = errors.Errorf("cannot find container with name %s", *obj.Spec.Container) + r.Recorder.Event(obj, "Warning", "Failed", err.Error()) + return ctrl.Result{}, nil + } + } + + actions, err := json.Marshal(obj.Spec.Actions) + if err != nil { + r.Recorder.Event(obj, "Warning", "Failed", err.Error()) + return ctrl.Result{Requeue: true}, nil + } + input := string(actions) + r.Log.Info("input with", "config", input) + + res, err := pbClient.ApplyIOChaos(ctx, &pb.ApplyIOChaosRequest{ + Actions: input, + Volume: obj.Spec.VolumeMountPath, + ContainerId: containerID, + + Instance: obj.Status.Pid, + StartTime: obj.Status.StartTime, + EnterNS: true, + }) + if err != nil { + err = errors.Wrapf(err, "failed to apply for pod %s/%s", pod.Namespace, pod.Name) + r.Recorder.Event(obj, "Warning", "Failed", err.Error()) + return ctrl.Result{Requeue: true}, nil + } + + startTime = res.StartTime + pid = res.Instance + + return ctrl.Result{}, nil +} diff --git a/controllers/podiochaos/fx.go b/controllers/podiochaos/fx.go new file mode 100644 index 0000000000..d4d7ac1794 --- /dev/null +++ b/controllers/podiochaos/fx.go @@ -0,0 +1,55 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podiochaos + +import ( + "reflect" + + "github.com/go-logr/logr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/builder" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon" +) + +func Bootstrap(mgr ctrl.Manager, client client.Client, logger logr.Logger, b *chaosdaemon.ChaosDaemonClientBuilder) error { + if !config.ShouldSpawnController("podiochaos") { + return nil + } + + return builder.Default(mgr). + For(&v1alpha1.PodIOChaos{}). + Named("podiochaos"). + WithEventFilter(predicate.Funcs{ + UpdateFunc: func(e event.UpdateEvent) bool { + oldObj := e.ObjectOld.(*v1alpha1.PodIOChaos) + newObj := e.ObjectNew.(*v1alpha1.PodIOChaos) + + return !reflect.DeepEqual(oldObj.Spec, newObj.Spec) + }, + }). + Complete(&Reconciler{ + Client: client, + Log: logger.WithName("podiochaos"), + Recorder: mgr.GetEventRecorderFor("podiochaos"), + ChaosDaemonClientBuilder: b, + }) +} diff --git a/controllers/podiochaos/types.go b/controllers/podiochaos/types.go deleted file mode 100644 index c2ad9bd3fe..0000000000 --- a/controllers/podiochaos/types.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package podiochaos - -import ( - "context" - "encoding/json" - "fmt" - "strings" - - "github.com/go-logr/logr" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/utils" - "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" -) - -// Handler applys podiochaos -type Handler struct { - client.Client - Log logr.Logger -} - -// Apply flushes io configuration on pod -func (h *Handler) Apply(ctx context.Context, chaos *v1alpha1.PodIoChaos) error { - h.Log.Info("updating io chaos", "pod", chaos.Namespace+"/"+chaos.Name, "spec", chaos.Spec) - - pod := &v1.Pod{} - - err := h.Client.Get(ctx, types.NamespacedName{ - Name: chaos.Name, - Namespace: chaos.Namespace, - }, pod) - if err != nil { - h.Log.Error(err, "fail to find pod") - return err - } - - pbClient, err := utils.NewChaosDaemonClient(ctx, h.Client, pod) - if err != nil { - return err - } - defer pbClient.Close() - - if len(pod.Status.ContainerStatuses) == 0 { - return fmt.Errorf("%s %s can't get the state of container", pod.Namespace, pod.Name) - } - - containerID := pod.Status.ContainerStatuses[0].ContainerID - if chaos.Spec.Container != nil && - len(strings.TrimSpace(*chaos.Spec.Container)) != 0 { - containerID = "" - for _, container := range pod.Status.ContainerStatuses { - if container.Name == *chaos.Spec.Container { - containerID = container.ContainerID - break - } - } - if len(containerID) == 0 { - return fmt.Errorf("cannot find container with name %s", *chaos.Spec.Container) - } - } - - actions, err := json.Marshal(chaos.Spec.Actions) - if err != nil { - return err - } - input := string(actions) - h.Log.Info("input with", "config", input) - - res, err := pbClient.ApplyIoChaos(ctx, &pb.ApplyIoChaosRequest{ - Actions: input, - Volume: chaos.Spec.VolumeMountPath, - ContainerId: containerID, - - Instance: chaos.Spec.Pid, - StartTime: chaos.Spec.StartTime, - EnterNS: true, - }) - if err != nil { - return err - } - - chaos.Spec.Pid = res.Instance - chaos.Spec.StartTime = res.StartTime - chaos.OwnerReferences = []metav1.OwnerReference{ - { - APIVersion: pod.APIVersion, - Kind: pod.Kind, - Name: pod.Name, - UID: pod.UID, - }, - } - - return nil -} diff --git a/controllers/podnetworkchaos/controller.go b/controllers/podnetworkchaos/controller.go new file mode 100644 index 0000000000..1c6f006217 --- /dev/null +++ b/controllers/podnetworkchaos/controller.go @@ -0,0 +1,322 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podnetworkchaos + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/ipset" + "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/iptable" + tcpkg "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/tc" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" + chaosdaemonclient "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/client" + pbutils "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/netem" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/netem" +) + +const ( + invalidNetemSpecMsg = "invalid spec for netem action, at least one is required from delay, loss, duplicate, corrupt" +) + +// Reconciler applys podnetworkchaos +type Reconciler struct { + client.Client + Recorder recorder.ChaosRecorder + + Log logr.Logger + AllowHostNetworkTesting bool + ChaosDaemonClientBuilder *chaosdaemon.ChaosDaemonClientBuilder +} + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + obj := &v1alpha1.PodNetworkChaos{} + + if err := r.Client.Get(ctx, req.NamespacedName, obj); err != nil { + if apierrors.IsNotFound(err) { + r.Log.Info("chaos not found") + } else { + // TODO: handle this error + r.Log.Error(err, "unable to get chaos") + } + return ctrl.Result{}, nil + } + + if obj.ObjectMeta.Generation <= obj.Status.ObservedGeneration && obj.Status.FailedMessage == "" { + r.Log.Info("the target pod has been up to date", "pod", obj.Namespace+"/"+obj.Name) + return ctrl.Result{}, nil + } + + r.Log.Info("updating podnetworkchaos", "pod", obj.Namespace+"/"+obj.Name, "spec", obj.Spec) + + pod := &corev1.Pod{} + + err := r.Client.Get(ctx, types.NamespacedName{ + Name: obj.Name, + Namespace: obj.Namespace, + }, pod) + if err != nil { + r.Log.Error(err, "fail to find pod") + return ctrl.Result{}, nil + } + + failedMessage := "" + observedGeneration := obj.ObjectMeta.Generation + defer func() { + if err != nil { + failedMessage = err.Error() + } + + updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + obj := &v1alpha1.PodNetworkChaos{} + + if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil { + r.Log.Error(err, "unable to get chaos") + return err + } + + obj.Status.FailedMessage = failedMessage + obj.Status.ObservedGeneration = observedGeneration + + return r.Client.Status().Update(context.TODO(), obj) + }) + + if updateError != nil { + r.Log.Error(updateError, "fail to update") + r.Recorder.Event(obj, recorder.Failed{ + Activity: "update status", + Err: updateError.Error(), + }) + } + + r.Recorder.Event(obj, recorder.Updated{ + Field: "ObservedGeneration and FailedMessage", + }) + }() + + if !r.AllowHostNetworkTesting { + if pod.Spec.HostNetwork { + err = errors.Errorf("It's dangerous to inject network chaos on a pod(%s/%s) with `hostNetwork`", pod.Namespace, pod.Name) + r.Log.Error(err, "fail to inject network chaos") + r.Recorder.Event(obj, recorder.Failed{ + Activity: "inject network chaos", + Err: err.Error(), + }) + return ctrl.Result{}, nil + } + } + + pbClient, err := r.ChaosDaemonClientBuilder.Build(ctx, pod, &types.NamespacedName{ + Name: obj.Name, + Namespace: obj.Namespace, + }) + if err != nil { + r.Recorder.Event(obj, recorder.Failed{ + Activity: "create chaos daemon client", + Err: err.Error(), + }) + return ctrl.Result{Requeue: true}, nil + } + defer pbClient.Close() + + err = r.SetIPSets(ctx, pod, obj, pbClient) + if err != nil { + err = errors.Wrapf(err, "failed to apply for pod %s/%s", pod.Namespace, pod.Name) + r.Log.Error(err, "fail to set ipsets") + r.Recorder.Event(obj, recorder.Failed{ + Activity: "set ipsets", + Err: err.Error(), + }) + return ctrl.Result{Requeue: true}, nil + } + + err = r.SetIptables(ctx, pod, obj, pbClient) + if err != nil { + err = errors.Wrapf(err, "failed to apply for pod %s/%s", pod.Namespace, pod.Name) + r.Log.Error(err, "fail to set iptables") + r.Recorder.Event(obj, recorder.Failed{ + Activity: "set iptables", + Err: err.Error(), + }) + return ctrl.Result{Requeue: true}, nil + } + + err = r.SetTcs(ctx, pod, obj, pbClient) + if err != nil { + err = errors.Wrapf(err, "failed to apply for pod %s/%s", pod.Namespace, pod.Name) + r.Recorder.Event(obj, recorder.Failed{ + Activity: "set tc", + Err: err.Error(), + }) + return ctrl.Result{Requeue: true}, nil + } + + return ctrl.Result{}, nil +} + +// SetIPSets sets ipset on pod +func (r *Reconciler) SetIPSets(ctx context.Context, pod *corev1.Pod, chaos *v1alpha1.PodNetworkChaos, chaosdaemonClient chaosdaemonclient.ChaosDaemonClientInterface) error { + ipsets := []*pb.IPSet{} + for _, ipset := range chaos.Spec.IPSets { + cidrAndPorts := []*pb.CidrAndPort{} + for _, cidrAndPort := range ipset.CidrAndPorts { + cidrAndPorts = append(cidrAndPorts, &pb.CidrAndPort{ + Cidr: cidrAndPort.Cidr, + Port: uint32(cidrAndPort.Port), + }) + } + ipsets = append(ipsets, &pb.IPSet{ + Name: ipset.Name, + Type: string(ipset.IPSetType), + Cidrs: ipset.Cidrs, + CidrAndPorts: cidrAndPorts, + SetNames: ipset.SetNames, + }) + } + return ipset.FlushIPSets(ctx, chaosdaemonClient, pod, ipsets) +} + +// SetIptables sets iptables on pod +func (r *Reconciler) SetIptables(ctx context.Context, pod *corev1.Pod, chaos *v1alpha1.PodNetworkChaos, chaosdaemonClient chaosdaemonclient.ChaosDaemonClientInterface) error { + chains := []*pb.Chain{} + for _, chain := range chaos.Spec.Iptables { + var direction pb.Chain_Direction + if chain.Direction == v1alpha1.Input { + direction = pb.Chain_INPUT + } else if chain.Direction == v1alpha1.Output { + direction = pb.Chain_OUTPUT + } else { + err := errors.Errorf("unknown direction %s", string(chain.Direction)) + r.Log.Error(err, "unknown direction") + return err + } + chains = append(chains, &pb.Chain{ + Name: chain.Name, + Ipsets: chain.IPSets, + Direction: direction, + Target: "DROP", + Device: chain.Device, + }) + } + return iptable.SetIptablesChains(ctx, chaosdaemonClient, pod, chains) +} + +// SetTcs sets traffic control related chaos on pod +func (r *Reconciler) SetTcs(ctx context.Context, pod *corev1.Pod, chaos *v1alpha1.PodNetworkChaos, chaosdaemonClient chaosdaemonclient.ChaosDaemonClientInterface) error { + tcs := []*pb.Tc{} + for _, tc := range chaos.Spec.TrafficControls { + if tc.Type == v1alpha1.Bandwidth { + tbf, err := netem.FromBandwidth(tc.Bandwidth) + if err != nil { + return err + } + tcs = append(tcs, &pb.Tc{ + Type: pb.Tc_BANDWIDTH, + Tbf: tbf, + Ipset: tc.IPSet, + Device: tc.Device, + }) + } else if tc.Type == v1alpha1.Netem { + netem, err := mergeNetem(tc.TcParameter) + if err != nil { + return err + } + tcs = append(tcs, &pb.Tc{ + Type: pb.Tc_NETEM, + Netem: netem, + Ipset: tc.IPSet, + Device: tc.Device, + }) + } else { + return errors.New("unknown tc type") + } + } + + r.Log.Info("setting tcs", "tcs", tcs) + return tcpkg.SetTcs(ctx, chaosdaemonClient, pod, tcs) +} + +// NetemSpec defines the interface to convert to a Netem protobuf +type NetemSpec interface { + ToNetem() (*pb.Netem, error) +} + +// mergeNetem calls ToNetem on all non nil network emulation specs and merges them into one request. +func mergeNetem(spec v1alpha1.TcParameter) (*pb.Netem, error) { + // NOTE: a cleaner way like + // emSpecs = []NetemSpec{spec.Delay, spec.Loss} won't work. + // Because in the for _, spec := range emSpecs loop, + // spec != nil would always be true. + // See https://stackoverflow.com/questions/13476349/check-for-nil-and-nil-interface-in-go + // And https://groups.google.com/forum/#!topic/golang-nuts/wnH302gBa4I/discussion + // > In short: If you never store (*T)(nil) in an interface, then you can reliably use comparison against nil + var emSpecs []*pb.Netem + if spec.Delay != nil { + em, err := netem.FromDelay(spec.Delay) + if err != nil { + return nil, err + } + emSpecs = append(emSpecs, em) + } + if spec.Loss != nil { + em, err := netem.FromLoss(spec.Loss) + if err != nil { + return nil, err + } + emSpecs = append(emSpecs, em) + } + if spec.Duplicate != nil { + em, err := netem.FromDuplicate(spec.Duplicate) + if err != nil { + return nil, err + } + emSpecs = append(emSpecs, em) + } + if spec.Corrupt != nil { + em, err := netem.FromCorrupt(spec.Corrupt) + if err != nil { + return nil, err + } + emSpecs = append(emSpecs, em) + } + if spec.Rate != nil { + em, err := netem.FromRate(spec.Rate) + if err != nil { + return nil, err + } + emSpecs = append(emSpecs, em) + } + if len(emSpecs) == 0 { + return nil, errors.New(invalidNetemSpecMsg) + } + + merged := &pb.Netem{} + for _, em := range emSpecs { + merged = pbutils.MergeNetem(merged, em) + } + return merged, nil +} diff --git a/controllers/podnetworkchaos/fx.go b/controllers/podnetworkchaos/fx.go new file mode 100644 index 0000000000..7f03ad7a72 --- /dev/null +++ b/controllers/podnetworkchaos/fx.go @@ -0,0 +1,59 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podnetworkchaos + +import ( + "reflect" + + "github.com/go-logr/logr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/builder" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" +) + +func Bootstrap(mgr ctrl.Manager, client client.Client, logger logr.Logger, b *chaosdaemon.ChaosDaemonClientBuilder, recorderBuilder *recorder.RecorderBuilder) error { + if !config.ShouldSpawnController("podnetworkchaos") { + return nil + } + + return builder.Default(mgr). + For(&v1alpha1.PodNetworkChaos{}). + Named("podnetworkchaos"). + WithEventFilter(predicate.Funcs{ + UpdateFunc: func(e event.UpdateEvent) bool { + oldObj := e.ObjectOld.(*v1alpha1.PodNetworkChaos) + newObj := e.ObjectNew.(*v1alpha1.PodNetworkChaos) + + return !reflect.DeepEqual(oldObj.Spec, newObj.Spec) + }, + }). + Complete(&Reconciler{ + Client: client, + Log: logger.WithName("podnetworkchaos"), + Recorder: recorderBuilder.Build("podnetworkchaos"), + + // TODO: + AllowHostNetworkTesting: config.ControllerCfg.AllowHostNetworkTesting, + ChaosDaemonClientBuilder: b, + }) +} diff --git a/controllers/podnetworkchaos/ipset/ipset.go b/controllers/podnetworkchaos/ipset/ipset.go index 4e6ff310b3..74659b879b 100644 --- a/controllers/podnetworkchaos/ipset/ipset.go +++ b/controllers/podnetworkchaos/ipset/ipset.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package ipset @@ -17,19 +19,34 @@ import ( "context" "fmt" + "github.com/pkg/errors" v1 "k8s.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/client" + ctrl "sigs.k8s.io/controller-runtime" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/netutils" - "github.com/chaos-mesh/chaos-mesh/controllers/utils" + chaosdaemonclient "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/client" pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" ) -// BuildIPSet builds an ipset with provided pod ip list -func BuildIPSet(pods []v1.Pod, externalCidrs []string, networkchaos *v1alpha1.NetworkChaos, namePostFix string, source string) v1alpha1.RawIPSet { - name := GenerateIPSetName(networkchaos, namePostFix) - cidrs := externalCidrs +var log = ctrl.Log.WithName("ipset") + +// BuildIPSets builds IP sets with provided pod ip list. +func BuildIPSets(pods []v1.Pod, externalCidrs []v1alpha1.CidrAndPort, networkchaos *v1alpha1.NetworkChaos, namePostFix string, source string) []v1alpha1.RawIPSet { + netName := GenerateIPSetName(networkchaos, "net_"+namePostFix) + netPortName := GenerateIPSetName(networkchaos, "netport_"+namePostFix) + + cidrs := []string{} + cidrAndPorts := []v1alpha1.CidrAndPort{} + + for _, cidr := range externalCidrs { + if cidr.Port == 0 { + cidrs = append(cidrs, cidr.Cidr) + } else { + cidrAndPorts = append(cidrAndPorts, cidr) + } + } for _, pod := range pods { if len(pod.Status.PodIP) > 0 { @@ -37,9 +54,39 @@ func BuildIPSet(pods []v1.Pod, externalCidrs []string, networkchaos *v1alpha1.Ne } } + return []v1alpha1.RawIPSet{ + { + Name: netName, + IPSetType: v1alpha1.NetIPSet, + Cidrs: cidrs, + RawRuleSource: v1alpha1.RawRuleSource{ + Source: source, + }, + }, + { + Name: netPortName, + IPSetType: v1alpha1.NetPortIPSet, + CidrAndPorts: cidrAndPorts, + RawRuleSource: v1alpha1.RawRuleSource{ + Source: source, + }, + }, + } +} + +// BuildSetIPSet builds list:set IP set that stores given sets +func BuildSetIPSet(sets []v1alpha1.RawIPSet, networkchaos *v1alpha1.NetworkChaos, namePostFix string, source string) v1alpha1.RawIPSet { + name := GenerateIPSetName(networkchaos, "set_"+namePostFix) + setNames := []string{} + + for _, set := range sets { + setNames = append(setNames, set.Name) + } + return v1alpha1.RawIPSet{ - Name: name, - Cidrs: cidrs, + Name: name, + IPSetType: v1alpha1.SetIPSet, + SetNames: setNames, RawRuleSource: v1alpha1.RawRuleSource{ Source: source, }, @@ -52,23 +99,32 @@ func GenerateIPSetName(networkchaos *v1alpha1.NetworkChaos, namePostFix string) } // FlushIPSets makes grpc calls to chaosdaemon to save ipset -func FlushIPSets(ctx context.Context, c client.Client, pod *v1.Pod, ipsets []*pb.IPSet) error { - pbClient, err := utils.NewChaosDaemonClient(ctx, c, pod) - if err != nil { - return err - } - defer pbClient.Close() +func FlushIPSets(ctx context.Context, pbClient chaosdaemonclient.ChaosDaemonClientInterface, pod *v1.Pod, ipsets []*pb.IPSet) error { + var err error if len(pod.Status.ContainerStatuses) == 0 { - return fmt.Errorf("%s %s can't get the state of container", pod.Namespace, pod.Name) + err = errors.Wrapf(utils.ErrContainerNotFound, "pod %s/%s has empty container status", pod.Namespace, pod.Name) + return err } - containerID := pod.Status.ContainerStatuses[0].ContainerID + log.Info("Flushing IP Sets....") + for _, containerStatus := range pod.Status.ContainerStatuses { + containerID := containerStatus.ContainerID + log.Info("attempting to flush ip set", "containerID", containerID) + + _, err = pbClient.FlushIPSets(ctx, &pb.IPSetsRequest{ + Ipsets: ipsets, + ContainerId: containerID, + EnterNS: true, + }) + + if err != nil { + log.Error(err, fmt.Sprintf("error while flushing ip sets for containerID %s", containerID)) + } else { + log.Info("Successfully flushed ip set") + return nil + } + } - _, err = pbClient.FlushIPSets(ctx, &pb.IPSetsRequest{ - Ipsets: ipsets, - ContainerId: containerID, - EnterNS: true, - }) - return err + return errors.Errorf("unable to flush ip sets for pod %s", pod.Name) } diff --git a/controllers/podnetworkchaos/ipset/ipset_test.go b/controllers/podnetworkchaos/ipset/ipset_test.go index f76bb8310d..32d00799d2 100644 --- a/controllers/podnetworkchaos/ipset/ipset_test.go +++ b/controllers/podnetworkchaos/ipset/ipset_test.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package ipset diff --git a/controllers/podnetworkchaos/iptable/iptable.go b/controllers/podnetworkchaos/iptable/iptable.go index a23cb7e3f4..424aeb03a6 100644 --- a/controllers/podnetworkchaos/iptable/iptable.go +++ b/controllers/podnetworkchaos/iptable/iptable.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package iptable @@ -17,35 +19,49 @@ import ( "context" "fmt" + "github.com/pkg/errors" v1 "k8s.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/client" + ctrl "sigs.k8s.io/controller-runtime" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/netutils" - "github.com/chaos-mesh/chaos-mesh/controllers/utils" + chaosdaemonclient "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/client" pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" ) +var log = ctrl.Log.WithName("iptable") + // SetIptablesChains makes grpc call to chaosdaemon to flush iptable -func SetIptablesChains(ctx context.Context, c client.Client, pod *v1.Pod, chains []*pb.Chain) error { - pbClient, err := utils.NewChaosDaemonClient(ctx, c, pod) - if err != nil { - return err - } - defer pbClient.Close() +func SetIptablesChains(ctx context.Context, pbClient chaosdaemonclient.ChaosDaemonClientInterface, pod *v1.Pod, chains []*pb.Chain) error { + var err error if len(pod.Status.ContainerStatuses) == 0 { - return fmt.Errorf("%s %s can't get the state of container", pod.Namespace, pod.Name) + err = errors.Wrapf(utils.ErrContainerNotFound, "pod %s/%s has empty container status", pod.Namespace, pod.Name) + + return err } - containerID := pod.Status.ContainerStatuses[0].ContainerID + log.Info("Setting IP Tables Chains...") + for _, containerStatus := range pod.Status.ContainerStatuses { + containerName := containerStatus.Name + containerID := containerStatus.ContainerID + log.Info("attempting to set ip table chains", "containerName", containerName, "containerID", containerID) + _, err = pbClient.SetIptablesChains(ctx, &pb.IptablesChainsRequest{ + Chains: chains, + ContainerId: containerID, + EnterNS: true, + }) + + if err != nil { + log.Error(err, fmt.Sprintf("error while setting ip tables chains for container %s, id %s", containerName, containerID)) + } else { + log.Info("Successfully set ip table chains") + return nil + } + } - _, err = pbClient.SetIptablesChains(ctx, &pb.IptablesChainsRequest{ - Chains: chains, - ContainerId: containerID, - EnterNS: true, - }) - return err + return errors.Errorf("unable to set ip tables chains for pod %s", pod.Name) } // GenerateName generates chain name for network chaos diff --git a/controllers/podnetworkchaos/netutils/cidr.go b/controllers/podnetworkchaos/netutils/cidr.go index a6058f65bb..6e3c005d71 100644 --- a/controllers/podnetworkchaos/netutils/cidr.go +++ b/controllers/podnetworkchaos/netutils/cidr.go @@ -1,21 +1,29 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package netutils import ( "net" + "strconv" "strings" + + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/mock" ) // IPToCidr converts from an ip to a full mask cidr @@ -25,8 +33,8 @@ func IPToCidr(ip string) string { } // ResolveCidrs converts multiple cidrs/ips/domains into cidr -func ResolveCidrs(names []string) ([]string, error) { - cidrs := []string{} +func ResolveCidrs(names []string) ([]v1alpha1.CidrAndPort, error) { + cidrs := []v1alpha1.CidrAndPort{} for _, target := range names { // TODO: resolve ip on every pods but not in controller, in case the dns server of these pods differ cidr, err := ResolveCidr(target) @@ -41,29 +49,50 @@ func ResolveCidrs(names []string) ([]string, error) { } // ResolveCidr converts cidr/ip/domain into cidr -func ResolveCidr(name string) ([]string, error) { - _, ipnet, err := net.ParseCIDR(name) +func ResolveCidr(name string) ([]v1alpha1.CidrAndPort, error) { + var toResolve string + var port uint16 + + if host, portStr, err := net.SplitHostPort(name); err == nil { + toResolve = host + port64, err := strconv.ParseUint(portStr, 10, 16) + if err != nil { + return nil, errors.Errorf("parse port %s", err) + } + port = uint16(port64) + } else { + toResolve = name + } + + _, ipnet, err := net.ParseCIDR(toResolve) if err == nil { - return []string{ipnet.String()}, nil + return []v1alpha1.CidrAndPort{{Cidr: ipnet.String(), Port: port}}, nil } - if net.ParseIP(name) != nil { - return []string{IPToCidr(name)}, nil + if net.ParseIP(toResolve) != nil { + return []v1alpha1.CidrAndPort{{Cidr: IPToCidr(toResolve), Port: port}}, nil } - addrs, err := net.LookupIP(name) + addrs, err := LookupIP(toResolve) if err != nil { return nil, err } - cidrs := []string{} + cidrs := []v1alpha1.CidrAndPort{} for _, addr := range addrs { addr := addr.String() // TODO: support IPv6 if strings.Contains(addr, ".") { - cidrs = append(cidrs, IPToCidr(addr)) + cidrs = append(cidrs, v1alpha1.CidrAndPort{Cidr: IPToCidr(addr), Port: port}) } } return cidrs, nil } + +func LookupIP(host string) ([]net.IP, error) { + if result := mock.On("LookupIP"); result != nil { + return result.([]net.IP), nil + } + return net.LookupIP(host) +} diff --git a/controllers/podnetworkchaos/netutils/cidr_test.go b/controllers/podnetworkchaos/netutils/cidr_test.go new file mode 100644 index 0000000000..8a601ebd68 --- /dev/null +++ b/controllers/podnetworkchaos/netutils/cidr_test.go @@ -0,0 +1,97 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package netutils + +import ( + "net" + "reflect" + "testing" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/mock" +) + +func TestResolveCidr(t *testing.T) { + defer mock.With("LookupIP", []net.IP{{1, 1, 1, 1}, {2, 2, 2, 2}})() + + type args struct { + name string + } + tests := []struct { + name string + args args + want []v1alpha1.CidrAndPort + wantErr bool + }{ + { + name: "ip address", + args: args{name: "1.1.1.1"}, + want: []v1alpha1.CidrAndPort{{Cidr: "1.1.1.1/32"}}, + }, + { + name: "ip address and port", + args: args{name: "1.1.1.1:80"}, + want: []v1alpha1.CidrAndPort{{Cidr: "1.1.1.1/32", Port: 80}}, + }, + { + name: "subnet", + args: args{name: "0.0.0.0/24"}, + want: []v1alpha1.CidrAndPort{{Cidr: "0.0.0.0/24"}}, + }, + { + name: "subnet and port", + args: args{name: "0.0.0.0/24:443"}, + want: []v1alpha1.CidrAndPort{{Cidr: "0.0.0.0/24", Port: 443}}, + }, + { + name: "hostname", + args: args{name: "example.com"}, + want: []v1alpha1.CidrAndPort{{Cidr: "1.1.1.1/32"}, {Cidr: "2.2.2.2/32"}}, + }, + { + name: "hostname and port", + args: args{name: "example.com:80"}, + want: []v1alpha1.CidrAndPort{{Cidr: "1.1.1.1/32", Port: 80}, {Cidr: "2.2.2.2/32", Port: 80}}, + }, + { + name: "missing port", + args: args{name: "1.1.1.1:"}, + wantErr: true, + }, + { + name: "port out of range", + args: args{name: "1.1.1.1:65536"}, + wantErr: true, + }, + { + name: "not a port", + args: args{name: "1.1.1.1:foo"}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ResolveCidr(tt.args.name) + if (err != nil) != tt.wantErr { + t.Errorf("ResolveCidr() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("ResolveCidr() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/controllers/podnetworkchaos/netutils/len.go b/controllers/podnetworkchaos/netutils/len.go index 6bd64f855c..500a9527f1 100644 --- a/controllers/podnetworkchaos/netutils/len.go +++ b/controllers/podnetworkchaos/netutils/len.go @@ -1,20 +1,22 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package netutils import ( - "crypto/sha1" + "crypto/sha256" "fmt" "log" ) @@ -39,7 +41,7 @@ func CompressName(originalName string, targetLength int, namePostFix string) (na namePrefix := originalName[0:5] nameRest := originalName[5:] - hasher := sha1.New() + hasher := sha256.New() hasher.Write([]byte(nameRest)) hashValue := fmt.Sprintf("%x", hasher.Sum(nil)) diff --git a/controllers/podnetworkchaos/netutils/len_test.go b/controllers/podnetworkchaos/netutils/len_test.go index 0df6700740..8ac98e5119 100644 --- a/controllers/podnetworkchaos/netutils/len_test.go +++ b/controllers/podnetworkchaos/netutils/len_test.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package netutils @@ -27,12 +29,12 @@ func Test_compressName(t *testing.T) { name = CompressName(name, 20, "test") - g.Expect(name).Should(Equal("Runni_a5e4631cf_test")) + g.Expect(name).Should(Equal("Runni_292d1924b_test")) name = "test executed panic(nil) or runtime.Goexit: subtest may have called FailNow on a parent test" name = CompressName(name, 13, "test") - g.Expect(name).Should(Equal("test _03_test")) + g.Expect(name).Should(Equal("test _90_test")) }) } diff --git a/controllers/podnetworkchaos/tc/tc.go b/controllers/podnetworkchaos/tc/tc.go index 3ba04b83a2..ddc781b873 100644 --- a/controllers/podnetworkchaos/tc/tc.go +++ b/controllers/podnetworkchaos/tc/tc.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package tc @@ -17,33 +19,46 @@ import ( "context" "fmt" + "github.com/pkg/errors" v1 "k8s.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/client" + ctrl "sigs.k8s.io/controller-runtime" - "github.com/chaos-mesh/chaos-mesh/controllers/utils" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" + chaosdaemonclient "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/client" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" ) +var log = ctrl.Log.WithName("tc") + // SetTcs makes grpc call to chaosdaemon to flush traffic control rules -func SetTcs(ctx context.Context, c client.Client, pod *v1.Pod, tcs []*pb.Tc) error { - pbClient, err := utils.NewChaosDaemonClient(ctx, c, pod) - if err != nil { - return err - } - defer pbClient.Close() +func SetTcs(ctx context.Context, pbClient chaosdaemonclient.ChaosDaemonClientInterface, pod *v1.Pod, tcs []*pb.Tc) error { + var err error if len(pod.Status.ContainerStatuses) == 0 { - return fmt.Errorf("%s %s can't get the state of container", pod.Namespace, pod.Name) + err = errors.Wrapf(utils.ErrContainerNotFound, "pod %s/%s has empty container status", pod.Namespace, pod.Name) + + return err } - containerID := pod.Status.ContainerStatuses[0].ContainerID + log.Info("Settings Tcs...") + for _, containerStatus := range pod.Status.ContainerStatuses { + containerName := containerStatus.Name + containerID := containerStatus.ContainerID + log.Info("attempting to set tcs", "containerName", containerName, "containerID", containerID) + + _, err = pbClient.SetTcs(ctx, &pb.TcsRequest{ + Tcs: tcs, + ContainerId: containerID, + EnterNS: true, + }) + + if err != nil { + log.Error(err, fmt.Sprintf("error while setting tcs for container %s, id %s", containerName, containerID)) + } else { + log.Info("Successfully set tcs") + return nil + } + } - _, err = pbClient.SetTcs(ctx, &pb.TcsRequest{ - Tcs: tcs, - ContainerId: containerID, - // Prevent tcs is empty, used to clean up tc rules - Device: "eth0", - EnterNS: true, - }) - return err + return errors.Errorf("unable to set tcs for pod %s", pod.Name) } diff --git a/controllers/podnetworkchaos/types.go b/controllers/podnetworkchaos/types.go deleted file mode 100644 index 58fd39fab8..0000000000 --- a/controllers/podnetworkchaos/types.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package podnetworkchaos - -import ( - "context" - "fmt" - - "github.com/pkg/errors" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/ipset" - "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/iptable" - tcpkg "github.com/chaos-mesh/chaos-mesh/controllers/podnetworkchaos/tc" - pbutils "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/netem" - "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" - "github.com/chaos-mesh/chaos-mesh/pkg/netem" - - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - invalidNetemSpecMsg = "invalid spec for netem action, at least one is required from delay, loss, duplicate, corrupt" -) - -// Handler applys podnetworkchaos -type Handler struct { - client.Client - client.Reader - Log logr.Logger - AllowHostNetworkTesting bool -} - -// Apply flushes network configuration on pod -func (h *Handler) Apply(ctx context.Context, chaos *v1alpha1.PodNetworkChaos) error { - h.Log.Info("updating network chaos", "pod", chaos.Namespace+"/"+chaos.Name, "spec", chaos.Spec) - - pod := &corev1.Pod{} - - err := h.Client.Get(ctx, types.NamespacedName{ - Name: chaos.Name, - Namespace: chaos.Namespace, - }, pod) - if err != nil { - h.Log.Error(err, "fail to find pod") - return err - } - - if !h.AllowHostNetworkTesting { - if pod.Spec.HostNetwork { - err := errors.Errorf("it's dangerous to inject network chaos on a pod(%s/%s) with `hostNetwork`", pod.Namespace, pod.Name) - return err - } - } - - err = h.SetIPSets(ctx, pod, chaos) - if err != nil { - return err - } - - err = h.SetIptables(ctx, pod, chaos) - if err != nil { - return err - } - - err = h.SetTcs(ctx, pod, chaos) - if err != nil { - return err - } - - return nil -} - -// SetIPSets sets ipset on pod -func (h *Handler) SetIPSets(ctx context.Context, pod *corev1.Pod, chaos *v1alpha1.PodNetworkChaos) error { - ipsets := []*pb.IPSet{} - for _, ipset := range chaos.Spec.IPSets { - ipsets = append(ipsets, &pb.IPSet{ - Name: ipset.Name, - Cidrs: ipset.Cidrs, - }) - } - return ipset.FlushIPSets(ctx, h.Client, pod, ipsets) -} - -// SetIptables sets iptables on pod -func (h *Handler) SetIptables(ctx context.Context, pod *corev1.Pod, chaos *v1alpha1.PodNetworkChaos) error { - chains := []*pb.Chain{} - for _, chain := range chaos.Spec.Iptables { - var direction pb.Chain_Direction - if chain.Direction == v1alpha1.Input { - direction = pb.Chain_INPUT - } else if chain.Direction == v1alpha1.Output { - direction = pb.Chain_OUTPUT - } else { - err := fmt.Errorf("unknown direction %s", string(chain.Direction)) - h.Log.Error(err, "unknown direction") - return err - } - chains = append(chains, &pb.Chain{ - Name: chain.Name, - Ipsets: chain.IPSets, - Direction: direction, - Target: "DROP", - }) - } - return iptable.SetIptablesChains(ctx, h.Client, pod, chains) -} - -// SetTcs sets traffic control related chaos on pod -func (h *Handler) SetTcs(ctx context.Context, pod *corev1.Pod, chaos *v1alpha1.PodNetworkChaos) error { - tcs := []*pb.Tc{} - for _, tc := range chaos.Spec.TrafficControls { - if tc.Type == v1alpha1.Bandwidth { - tbf, err := netem.FromBandwidth(tc.Bandwidth) - if err != nil { - return err - } - tcs = append(tcs, &pb.Tc{ - Type: pb.Tc_BANDWIDTH, - Tbf: tbf, - Ipset: tc.IPSet, - }) - } else if tc.Type == v1alpha1.Netem { - netem, err := mergeNetem(tc.TcParameter) - if err != nil { - return err - } - tcs = append(tcs, &pb.Tc{ - Type: pb.Tc_NETEM, - Netem: netem, - Ipset: tc.IPSet, - }) - } else { - return fmt.Errorf("unknown tc type") - } - } - - h.Log.Info("setting tcs", "tcs", tcs) - return tcpkg.SetTcs(ctx, h.Client, pod, tcs) -} - -// NetemSpec defines the interface to convert to a Netem protobuf -type NetemSpec interface { - ToNetem() (*pb.Netem, error) -} - -// mergeNetem calls ToNetem on all non nil network emulation specs and merges them into one request. -func mergeNetem(spec v1alpha1.TcParameter) (*pb.Netem, error) { - // NOTE: a cleaner way like - // emSpecs = []NetemSpec{spec.Delay, spec.Loss} won't work. - // Because in the for _, spec := range emSpecs loop, - // spec != nil would always be true. - // See https://stackoverflow.com/questions/13476349/check-for-nil-and-nil-interface-in-go - // And https://groups.google.com/forum/#!topic/golang-nuts/wnH302gBa4I/discussion - // > In short: If you never store (*T)(nil) in an interface, then you can reliably use comparison against nil - var emSpecs []*pb.Netem - if spec.Delay != nil { - em, err := netem.FromDelay(spec.Delay) - if err != nil { - return nil, err - } - emSpecs = append(emSpecs, em) - } - if spec.Loss != nil { - em, err := netem.FromLoss(spec.Loss) - if err != nil { - return nil, err - } - emSpecs = append(emSpecs, em) - } - if spec.Duplicate != nil { - em, err := netem.FromDuplicate(spec.Duplicate) - if err != nil { - return nil, err - } - emSpecs = append(emSpecs, em) - } - if spec.Corrupt != nil { - em, err := netem.FromCorrupt(spec.Corrupt) - if err != nil { - return nil, err - } - emSpecs = append(emSpecs, em) - } - if len(emSpecs) == 0 { - return nil, errors.New(invalidNetemSpecMsg) - } - - merged := &pb.Netem{} - for _, em := range emSpecs { - merged = pbutils.MergeNetem(merged, em) - } - return merged, nil -} diff --git a/controllers/podnetworkchaos/types_test.go b/controllers/podnetworkchaos/types_test.go index 5be76a674f..38bdfd9325 100644 --- a/controllers/podnetworkchaos/types_test.go +++ b/controllers/podnetworkchaos/types_test.go @@ -1,34 +1,37 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package podnetworkchaos import ( "context" - "strings" "testing" . "github.com/onsi/gomega" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/log/zap" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/cmd/chaos-controller-manager/provider" . "github.com/chaos-mesh/chaos-mesh/controllers/test" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" "github.com/chaos-mesh/chaos-mesh/pkg/mock" . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" @@ -44,64 +47,79 @@ func setHostNetwork(objs []runtime.Object) { func TestHostNetworkOption(t *testing.T) { defer mock.With("MockChaosDaemonClient", &MockChaosDaemonClient{})() + RegisterTestingT(t) testCases := []struct { name string enableHostNetworkTesting bool - errorEvaluation func(t *testing.T, err error) + errorEvaluation func(err string) }{ { name: "host networking testing disabled (default)", enableHostNetworkTesting: false, - errorEvaluation: func(t *testing.T, err error) { - if err == nil { - t.Errorf("expected failure on hostNetwork pods") - } - if err != nil && !strings.Contains(err.Error(), "it's dangerous to inject network chaos on a pod") { - t.Errorf("expected failure on hostNetwork pods, but got %v", err) - } + errorEvaluation: func(err string) { + Expect(err).To(ContainSubstring("It's dangerous to inject network chaos on a pod")) }, }, { name: "host networking testing enabled", enableHostNetworkTesting: true, - errorEvaluation: func(t *testing.T, err error) { - if err != nil { - t.Errorf("failed to apply hostNetwork chaos got %v", err) - } + errorEvaluation: func(err string) { + Expect(err).To(Equal("")) }, }, } for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - objs, _ := GenerateNPods("p", 1, PodArg{}) - setHostNetwork(objs) + objs, _ := GenerateNPods("p", 1, PodArg{}) - chaos := &v1alpha1.PodNetworkChaos{ - TypeMeta: metav1.TypeMeta{ - Kind: "PodChaos", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ + setHostNetwork(objs) + + chaos := &v1alpha1.PodNetworkChaos{ + TypeMeta: metav1.TypeMeta{ + Kind: "PodNetworkChaos", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: metav1.NamespaceDefault, + Name: "p0", + Generation: 1, + }, + Spec: v1alpha1.PodNetworkChaosSpec{}, + } + objs = append(objs, chaos) + + fakeClient := fake.NewClientBuilder(). + WithScheme(provider.NewScheme()). + WithRuntimeObjects(objs...). + WithStatusSubresource(&v1alpha1.PodNetworkChaos{}). + Build() + + recorder := recorder.NewDebugRecorder() + h := &Reconciler{ + Client: fakeClient, + Recorder: recorder, + Log: zap.New(zap.UseDevMode(true)), + AllowHostNetworkTesting: testCase.enableHostNetworkTesting, + } + + _, err := h.Reconcile( + context.TODO(), + ctrl.Request{ + NamespacedName: types.NamespacedName{ Namespace: metav1.NamespaceDefault, Name: "p0", }, - Spec: v1alpha1.PodNetworkChaosSpec{}, - } + }) + Expect(err).To(BeNil()) - var r client.Reader - h := &Handler{ - Client: fake.NewFakeClientWithScheme(scheme.Scheme, objs...), - Reader: r, - Log: zap.New(zap.UseDevMode(true)), - AllowHostNetworkTesting: testCase.enableHostNetworkTesting, - } - - testCase.errorEvaluation(t, h.Apply(context.TODO(), chaos)) - }) + fakeClient.Get(context.Background(), types.NamespacedName{ + Namespace: metav1.NamespaceDefault, + Name: "p0", + }, chaos) + testCase.errorEvaluation(chaos.Status.FailedMessage) } } @@ -117,7 +135,7 @@ func TestMergenetem(t *testing.T) { } }) - t.Run("delay loss", func(t *testing.T) { + t.Run("delay loss rate", func(t *testing.T) { g := NewGomegaWithT(t) spec := v1alpha1.TcParameter{ @@ -130,6 +148,9 @@ func TestMergenetem(t *testing.T) { Loss: "25", Correlation: "25", }, + Rate: &v1alpha1.RateSpec{ + Rate: "25mbps", + }, } m, err := mergeNetem(spec) g.Expect(err).ShouldNot(HaveOccurred()) @@ -139,6 +160,7 @@ func TestMergenetem(t *testing.T) { DelayCorr: 25, Loss: 25, LossCorr: 25, + Rate: "25mbps", } g.Expect(m).Should(Equal(em)) }) diff --git a/controllers/reconciler/types.go b/controllers/reconciler/types.go deleted file mode 100644 index 63ae8da65e..0000000000 --- a/controllers/reconciler/types.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package reconciler - -import ( - "context" - - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -// InnerReconciler is interface for reconciler -type InnerReconciler interface { - // Apply means the reconciler perform the chaos action - Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error - - // Recover means the reconciler recovers the chaos action - Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error - - // Object would return the instance of chaos - Object() v1alpha1.InnerObject -} diff --git a/controllers/recover/recover.go b/controllers/recover/recover.go deleted file mode 100644 index e74ad26a18..0000000000 --- a/controllers/recover/recover.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package recover - -import ( - "context" - - "github.com/go-logr/logr" - "github.com/hashicorp/go-multierror" - v1 "k8s.io/api/core/v1" - k8serror "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/cache" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/common" - "github.com/chaos-mesh/chaos-mesh/pkg/finalizer" -) - -type Delegate struct { - client.Client - Log logr.Logger - RecoverIntf -} - -type RecoverIntf interface { - RecoverPod(context.Context, *v1.Pod, v1alpha1.InnerObject) error -} - -func (r *Delegate) CleanFinalizersAndRecover(ctx context.Context, chaos v1alpha1.InnerObject, finalizers []string, annotations map[string]string) ([]string, error) { - var result error - - for _, key := range finalizers { - ns, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - result = multierror.Append(result, err) - continue - } - - var pod v1.Pod - err = r.Client.Get(ctx, types.NamespacedName{ - Namespace: ns, - Name: name, - }, &pod) - - if err != nil { - if !k8serror.IsNotFound(err) { - result = multierror.Append(result, err) - continue - } - - r.Log.Info("Pod not found", "namespace", ns, "name", name) - finalizers = finalizer.RemoveFromFinalizer(finalizers, key) - continue - } - - err = r.RecoverPod(ctx, &pod, chaos) - if err != nil { - result = multierror.Append(result, err) - continue - } - - finalizers = finalizer.RemoveFromFinalizer(finalizers, key) - } - - if annotations[common.AnnotationCleanFinalizer] == common.AnnotationCleanFinalizerForced { - r.Log.Info("Force cleanup all finalizers", "chaos", chaos) - finalizers = finalizers[:0] - return finalizers, nil - } - - return finalizers, result -} diff --git a/controllers/schedule/active/controller.go b/controllers/schedule/active/controller.go new file mode 100644 index 0000000000..34aa012f3a --- /dev/null +++ b/controllers/schedule/active/controller.go @@ -0,0 +1,149 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package active + +import ( + "context" + "reflect" + "sort" + + "github.com/go-logr/logr" + "go.uber.org/fx" + v1 "k8s.io/api/core/v1" + k8sError "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/reference" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/schedule/utils" + "github.com/chaos-mesh/chaos-mesh/controllers/types" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/builder" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" +) + +type Reconciler struct { + scheme *runtime.Scheme + + client.Client + Log logr.Logger + + ActiveLister *utils.ActiveLister + + Recorder recorder.ChaosRecorder +} + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + schedule := &v1alpha1.Schedule{} + err := r.Get(ctx, req.NamespacedName, schedule) + if err != nil { + if !k8sError.IsNotFound(err) { + r.Log.Error(err, "unable to get chaos") + } + return ctrl.Result{}, nil + } + + list, err := r.ActiveLister.ListActiveJobs(ctx, schedule) + if err != nil { + r.Recorder.Event(schedule, recorder.Failed{ + Activity: "list active jobs", + Err: err.Error(), + }) + return ctrl.Result{}, nil + } + + active := []v1.ObjectReference{} + items := reflect.ValueOf(list).Elem().FieldByName("Items") + for i := 0; i < items.Len(); i++ { + item := items.Index(i).Addr().Interface().(runtime.Object) + + ref, err := reference.GetReference(r.scheme, item) + if err != nil { + r.Log.Error(err, "fail to get reference") + r.Recorder.Event(schedule, recorder.Failed{ + Activity: "get reference from object", + Err: err.Error(), + }) + return ctrl.Result{}, nil + } + + active = append(active, *ref) + } + sort.Slice(active, func(i, j int) bool { + return active[i].Name < active[j].Name + }) + if reflect.DeepEqual(active, schedule.Status.Active) { + r.Log.Info("don't need to update active") + return ctrl.Result{}, nil + } + + updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + r.Log.Info("updating active", "active", active) + schedule = schedule.DeepCopyObject().(*v1alpha1.Schedule) + + if err := r.Client.Get(ctx, req.NamespacedName, schedule); err != nil { + r.Log.Error(err, "unable to get schedule") + return err + } + + schedule.Status.Active = active + return r.Client.Update(ctx, schedule) + }) + if updateError != nil { + r.Log.Error(updateError, "fail to update") + r.Recorder.Event(schedule, recorder.Failed{ + Activity: "update active", + Err: updateError.Error(), + }) + return ctrl.Result{}, nil + } + + return ctrl.Result{}, nil +} + +type Objs struct { + fx.In + + Objs []types.Object `group:"objs"` +} + +const controllerName = "schedule-active" + +func Bootstrap(mgr ctrl.Manager, client client.Client, log logr.Logger, objs Objs, scheme *runtime.Scheme, lister *utils.ActiveLister, recorderBuilder *recorder.RecorderBuilder) error { + if !config.ShouldSpawnController(controllerName) { + return nil + } + builder := builder.Default(mgr). + For(&v1alpha1.Schedule{}). + Named(controllerName) + + for _, obj := range objs.Objs { + // TODO: support workflow + builder = builder.Owns(obj.Object) + } + builder = builder.Owns(&v1alpha1.Workflow{}) + + return builder.Complete(&Reconciler{ + scheme, + client, + log.WithName(controllerName), + lister, + recorderBuilder.Build(controllerName), + }) +} diff --git a/controllers/schedule/cron/controller.go b/controllers/schedule/cron/controller.go new file mode 100644 index 0000000000..06880a9278 --- /dev/null +++ b/controllers/schedule/cron/controller.go @@ -0,0 +1,213 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package cron + +import ( + "context" + "reflect" + "time" + + "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apiserver/pkg/storage/names" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/schedule/utils" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/builder" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" + "github.com/chaos-mesh/chaos-mesh/pkg/workflow/controllers" +) + +type Reconciler struct { + client.Client + Log logr.Logger + ActiveLister *utils.ActiveLister + + Recorder recorder.ChaosRecorder +} + +var t = true + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + schedule := &v1alpha1.Schedule{} + err := r.Get(ctx, req.NamespacedName, schedule) + if err != nil { + r.Log.Error(err, "unable to get chaos") + return ctrl.Result{}, nil + } + + if schedule.IsPaused() { + r.Log.Info("not starting chaos as it is paused") + return ctrl.Result{}, nil + } + + now := time.Now() + shouldSpawn := false + r.Log.Info("calculate schedule time", "schedule", schedule.Spec.Schedule, "lastScheduleTime", schedule.Status.LastScheduleTime, "now", now) + missedRun, nextRun, err := getRecentUnmetScheduleTime(schedule, now) + if err != nil { + r.Recorder.Event(schedule, recorder.Failed{ + Activity: "get run time", + Err: err.Error(), + }) + return ctrl.Result{}, nil + } + if missedRun == nil { + r.Log.Info("requeue later to reconcile the schedule", "requeue-after", nextRun.Sub(now)) + return ctrl.Result{RequeueAfter: nextRun.Sub(now)}, nil + } + + if schedule.Spec.StartingDeadlineSeconds != nil { + if missedRun.Add(time.Second * time.Duration(*schedule.Spec.StartingDeadlineSeconds)).Before(now) { + r.Recorder.Event(schedule, recorder.MissedSchedule{ + MissedRun: *missedRun, + }) + return ctrl.Result{}, nil + } + } + + r.Log.Info("schedule to spawn new chaos", "missedRun", missedRun, "nextRun", nextRun) + shouldSpawn = true + + if shouldSpawn && schedule.Spec.ConcurrencyPolicy.IsForbid() { + list, err := r.ActiveLister.ListActiveJobs(ctx, schedule) + if err != nil { + r.Recorder.Event(schedule, recorder.Failed{ + Activity: "list active jobs", + Err: err.Error(), + }) + return ctrl.Result{}, nil + } + + items := reflect.ValueOf(list).Elem().FieldByName("Items") + for i := 0; i < items.Len(); i++ { + if schedule.Spec.Type != v1alpha1.ScheduleTypeWorkflow { + item := items.Index(i).Addr().Interface().(v1alpha1.InnerObject) + if !controller.IsChaosFinished(item, now) { + shouldSpawn = false + r.Recorder.Event(schedule, recorder.ScheduleForbid{ + RunningName: item.GetName(), + }) + r.Log.Info("forbid to spawn new chaos", "running", item.GetName()) + break + } + } else { + workflow := items.Index(i).Addr().Interface().(*v1alpha1.Workflow) + if !controllers.WorkflowConditionEqualsTo(workflow.Status, v1alpha1.WorkflowConditionAccomplished, corev1.ConditionTrue) { + shouldSpawn = false + r.Recorder.Event(schedule, recorder.ScheduleForbid{ + RunningName: workflow.GetObjectMeta().Name, + }) + r.Log.Info("forbid to spawn new workflow", "running", workflow.GetName()) + break + } + } + } + } + + if shouldSpawn { + newObj, err := schedule.Spec.ScheduleItem.SpawnNewObject(schedule.Spec.Type) + if err != nil { + r.Recorder.Event(schedule, recorder.Failed{ + Activity: "generate new object", + Err: err.Error(), + }) + return ctrl.Result{}, nil + } + + newObj.SetOwnerReferences([]metav1.OwnerReference{ + { + APIVersion: schedule.APIVersion, + Kind: schedule.Kind, + Name: schedule.Name, + UID: schedule.UID, + Controller: &t, + BlockOwnerDeletion: &t, + }, + }) + newObj.SetLabels(map[string]string{ + v1alpha1.LabelManagedBy: schedule.Name, + }) + newObj.SetNamespace(schedule.Namespace) + newObj.SetName(names.SimpleNameGenerator.GenerateName(schedule.Name + "-")) + + err = r.Create(ctx, newObj) + if err != nil { + r.Recorder.Event(schedule, recorder.Failed{ + Activity: "create new object", + Err: err.Error(), + }) + r.Log.Error(err, "fail to create new object", "obj", newObj) + return ctrl.Result{}, nil + } + r.Recorder.Event(schedule, recorder.ScheduleSpawn{ + Name: newObj.GetName(), + }) + r.Log.Info("create new object", "namespace", newObj.GetNamespace(), "name", newObj.GetName()) + + lastScheduleTime := now + updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + r.Log.Info("updating lastScheduleTime", "time", lastScheduleTime) + schedule = schedule.DeepCopyObject().(*v1alpha1.Schedule) + + if err := r.Client.Get(ctx, req.NamespacedName, schedule); err != nil { + r.Log.Error(err, "unable to get schedule") + return err + } + + schedule.Status.LastScheduleTime.Time = lastScheduleTime + return r.Client.Update(ctx, schedule) + }) + if updateError != nil { + r.Log.Error(updateError, "fail to update") + r.Recorder.Event(schedule, recorder.Failed{ + Activity: "update lastScheduleTime", + Err: updateError.Error(), + }) + return ctrl.Result{}, nil + } + + r.Recorder.Event(schedule, recorder.Updated{ + Field: "lastScheduleTime", + }) + } + + return ctrl.Result{}, nil +} + +const controllerName = "schedule-cron" + +func Bootstrap(mgr ctrl.Manager, client client.Client, log logr.Logger, lister *utils.ActiveLister, recorderBuilder *recorder.RecorderBuilder) error { + if !config.ShouldSpawnController(controllerName) { + return nil + } + + return builder.Default(mgr). + For(&v1alpha1.Schedule{}). + Named(controllerName). + Complete(&Reconciler{ + client, + log.WithName(controllerName), + lister, + recorderBuilder.Build(controllerName), + }) +} diff --git a/controllers/schedule/cron/utils.go b/controllers/schedule/cron/utils.go new file mode 100644 index 0000000000..af10980c5c --- /dev/null +++ b/controllers/schedule/cron/utils.go @@ -0,0 +1,71 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package cron + +import ( + "time" + + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +// Get this function from Kubernetes + +// getRecentUnmetScheduleTime gets the most recent time that have passed when a Job should have started but did not. +// +// If there are too many (>100) unstarted times, just give up and return a nil. +func getRecentUnmetScheduleTime(schedule *v1alpha1.Schedule, now time.Time) (*time.Time, *time.Time, error) { + sched, err := v1alpha1.StandardCronParser.Parse(schedule.Spec.Schedule) + if err != nil { + return nil, nil, errors.Errorf("unparseable schedule: %s : %s", schedule.Spec.Schedule, err) + } + + var earliestTime time.Time + if !schedule.Status.LastScheduleTime.UTC().IsZero() { + earliestTime = schedule.Status.LastScheduleTime.Time + } else { + earliestTime = schedule.ObjectMeta.CreationTimestamp.Time + } + if schedule.Spec.StartingDeadlineSeconds != nil { + schedulingDeadline := now.Add(-time.Second * time.Duration(*schedule.Spec.StartingDeadlineSeconds)) + + if schedulingDeadline.After(earliestTime) { + earliestTime = schedulingDeadline + } + } + if earliestTime.After(now) { + return nil, nil, errors.Errorf("earliestTime is later than now: earliestTime: %v, now: %v", earliestTime, now) + } + + iterateTime := 0 + var missedRun *time.Time + nextRun := sched.Next(earliestTime) + for t := sched.Next(earliestTime); !t.After(now); t = sched.Next(t) { + t := t + + missedRun = &t + nextRun = sched.Next(*missedRun) + + iterateTime++ + if iterateTime > 100 { + // We can't get the most recent times so just return an empty slice + return nil, nil, errors.New("too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew") + } + } + + return missedRun, &nextRun, nil +} diff --git a/controllers/schedule/cron/utils_test.go b/controllers/schedule/cron/utils_test.go new file mode 100644 index 0000000000..b3d7cd6caf --- /dev/null +++ b/controllers/schedule/cron/utils_test.go @@ -0,0 +1,136 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package cron + +import ( + "testing" + "time" + + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +func TestGetRecentUnmetScheduleTime(t *testing.T) { + g := NewGomegaWithT(t) + + type testCase struct { + now string + lastScheduleTime string + creationTimeStamp string + schedule string + missedRun *string + nextRun *string + err error + } + + zeroTime := "0001-01-01T00:00:00.000Z" + testCases := []testCase{ + { + now: "2021-04-28T05:59:43.5Z", + lastScheduleTime: "2021-04-28T05:59:38.0Z", + creationTimeStamp: zeroTime, + schedule: "@every 5s", + missedRun: pointer.StringPtr("2021-04-28T05:59:43.0Z"), + nextRun: pointer.StringPtr("2021-04-28T05:59:48.0Z"), + err: nil, + }, + { + now: "2021-04-28T06:49:35.079Z", + lastScheduleTime: "2021-04-28T06:49:35.000Z", + creationTimeStamp: zeroTime, + schedule: "@every 5s", + missedRun: nil, + nextRun: pointer.StringPtr("2021-04-28T06:49:40.000Z"), + err: nil, + }, + { + now: "2021-04-28T06:49:35.079Z", + lastScheduleTime: zeroTime, + creationTimeStamp: "2021-04-28T06:49:35.000Z", + schedule: "@every 5s", + missedRun: nil, + nextRun: pointer.StringPtr("2021-04-28T06:49:40.000Z"), + err: nil, + }, + { + now: "2021-04-28T06:49:38.079Z", + lastScheduleTime: zeroTime, + creationTimeStamp: "2021-04-28T06:49:35.000Z", + schedule: "@every 5s", + missedRun: nil, + nextRun: pointer.StringPtr("2021-04-28T06:49:40.000Z"), + err: nil, + }, + { + now: "2021-04-28T06:49:40.079Z", + lastScheduleTime: zeroTime, + creationTimeStamp: "2021-04-28T06:49:35.000Z", + schedule: "@every 5s", + missedRun: pointer.StringPtr("2021-04-28T06:49:40.000Z"), + nextRun: pointer.StringPtr("2021-04-28T06:49:45.000Z"), + err: nil, + }, + } + for _, t := range testCases { + now, err := time.Parse(time.RFC3339, t.now) + g.Expect(err).To(BeNil()) + lastScheduleTime, err := time.Parse(time.RFC3339, t.lastScheduleTime) + g.Expect(err).To(BeNil()) + createTimeStamp, err := time.Parse(time.RFC3339, t.creationTimeStamp) + g.Expect(err).To(BeNil()) + + schedule := v1alpha1.Schedule{ + ObjectMeta: metav1.ObjectMeta{ + CreationTimestamp: metav1.Time{ + Time: createTimeStamp, + }, + }, + Spec: v1alpha1.ScheduleSpec{ + Schedule: t.schedule, + }, + Status: v1alpha1.ScheduleStatus{ + LastScheduleTime: metav1.Time{ + Time: lastScheduleTime, + }, + }, + } + missedRun, nextRun, err := getRecentUnmetScheduleTime(&schedule, now) + + expectedMissedRun := BeNil() + expectedNextRun := BeNil() + expectedErr := BeNil() + if t.missedRun != nil { + missedRun, err := time.Parse(time.RFC3339, *t.missedRun) + g.Expect(err).To(BeNil()) + expectedMissedRun = Equal(&missedRun) + } + if t.nextRun != nil { + nextRun, err := time.Parse(time.RFC3339, *t.nextRun) + g.Expect(err).To(BeNil()) + expectedNextRun = Equal(&nextRun) + } + if t.err != nil { + expectedErr = Equal(t.err) + } + + g.Expect(err).To(expectedErr) + g.Expect(missedRun).To(expectedMissedRun) + g.Expect(nextRun).To(expectedNextRun) + } +} diff --git a/controllers/schedule/fx.go b/controllers/schedule/fx.go new file mode 100644 index 0000000000..f0643c155f --- /dev/null +++ b/controllers/schedule/fx.go @@ -0,0 +1,35 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package schedule + +import ( + "go.uber.org/fx" + + "github.com/chaos-mesh/chaos-mesh/controllers/schedule/active" + "github.com/chaos-mesh/chaos-mesh/controllers/schedule/cron" + "github.com/chaos-mesh/chaos-mesh/controllers/schedule/gc" + "github.com/chaos-mesh/chaos-mesh/controllers/schedule/pause" + "github.com/chaos-mesh/chaos-mesh/controllers/schedule/utils" +) + +var Module = fx.Options( + fx.Invoke(cron.Bootstrap), + fx.Invoke(active.Bootstrap), + fx.Invoke(gc.Bootstrap), + fx.Invoke(pause.Bootstrap), + + fx.Provide(utils.NewActiveLister), +) diff --git a/controllers/schedule/gc/controller.go b/controllers/schedule/gc/controller.go new file mode 100644 index 0000000000..212b528820 --- /dev/null +++ b/controllers/schedule/gc/controller.go @@ -0,0 +1,160 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gc + +import ( + "context" + "fmt" + "reflect" + "sort" + "time" + + "github.com/go-logr/logr" + "go.uber.org/fx" + corev1 "k8s.io/api/core/v1" + k8sError "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/schedule/utils" + "github.com/chaos-mesh/chaos-mesh/controllers/types" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/builder" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" + "github.com/chaos-mesh/chaos-mesh/pkg/workflow/controllers" +) + +type Reconciler struct { + client.Client + Log logr.Logger + Recorder recorder.ChaosRecorder + + ActiveLister *utils.ActiveLister +} + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + // In this controller, schedule could be out of date, as the reconcilation may be not caused by + // an update on Schedule, but by a *Chaos. + schedule := &v1alpha1.Schedule{} + err := r.Get(ctx, req.NamespacedName, schedule) + if err != nil { + if !k8sError.IsNotFound(err) { + r.Log.Error(err, "unable to get schedule chaos") + } + return ctrl.Result{}, nil + } + + list, err := r.ActiveLister.ListActiveJobs(ctx, schedule) + if err != nil { + r.Recorder.Event(schedule, recorder.Failed{ + Activity: "list active jobs", + Err: err.Error(), + }) + return ctrl.Result{}, nil + } + + items := reflect.ValueOf(list).Elem().FieldByName("Items") + metaItems := []client.Object{} + for i := 0; i < items.Len(); i++ { + item := items.Index(i).Addr().Interface().(client.Object) + metaItems = append(metaItems, item) + } + + sort.Slice(metaItems, func(x, y int) bool { + return metaItems[x].GetCreationTimestamp().Time.Before(metaItems[y].GetCreationTimestamp().Time) + }) + + exceededHistory := len(metaItems) - schedule.Spec.HistoryLimit + + requeuAfter := time.Duration(0) + if exceededHistory > 0 { + for _, obj := range metaItems[0:exceededHistory] { + innerObj, ok := obj.(v1alpha1.InnerObject) + if ok { // This is a chaos + finished, untilStop := controller.IsChaosFinishedWithUntilStop(innerObj, time.Now()) + + if !finished { + if untilStop != 0 { + if requeuAfter == 0 || requeuAfter > untilStop { + requeuAfter = untilStop + } + continue + } + + // hasn't finished, but untilStop is 0 + r.Log.Info("untilStop is 0 when the chaos has not finished") + } + } else { // A workflow + if schedule.Spec.Type == v1alpha1.ScheduleTypeWorkflow { + workflow, ok := obj.(*v1alpha1.Workflow) + if ok { + finished := controllers.WorkflowConditionEqualsTo(workflow.Status, v1alpha1.WorkflowConditionAccomplished, corev1.ConditionTrue) + + if !finished { + continue + } + } + } + } + err := r.Client.Delete(ctx, obj) + if err != nil && !k8sError.IsNotFound(err) { + r.Recorder.Event(schedule, recorder.Failed{ + Activity: fmt.Sprintf("delete %s/%s", obj.GetNamespace(), obj.GetName()), + Err: err.Error(), + }) + } + } + } + + return ctrl.Result{ + RequeueAfter: requeuAfter, + }, nil +} + +type Objs struct { + fx.In + + ScheduleObjs []types.Object `group:"schedule"` + Objs []types.Object `group:"objs"` +} + +const controllerName = "schedule-gc" + +func Bootstrap(mgr ctrl.Manager, client client.Client, log logr.Logger, objs Objs, scheme *runtime.Scheme, lister *utils.ActiveLister, recorderBuilder *recorder.RecorderBuilder) error { + if !config.ShouldSpawnController(controllerName) { + return nil + } + builder := builder.Default(mgr). + For(&v1alpha1.Schedule{}). + Named(controllerName) + + for _, obj := range objs.Objs { + // TODO: support workflow + builder.Owns(obj.Object) + } + + builder = builder.Owns(&v1alpha1.Workflow{}) + + return builder.Complete(&Reconciler{ + client, + log.WithName(controllerName), + recorderBuilder.Build(controllerName), + lister, + }) +} diff --git a/controllers/schedule/pause/controller.go b/controllers/schedule/pause/controller.go new file mode 100644 index 0000000000..5644719809 --- /dev/null +++ b/controllers/schedule/pause/controller.go @@ -0,0 +1,129 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package pause + +import ( + "context" + "fmt" + "reflect" + "strconv" + + "github.com/go-logr/logr" + k8sError "k8s.io/apimachinery/pkg/api/errors" + k8sTypes "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/schedule/utils" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/builder" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" +) + +type Reconciler struct { + client.Client + Log logr.Logger + ActiveLister *utils.ActiveLister + + Recorder recorder.ChaosRecorder +} + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + schedule := &v1alpha1.Schedule{} + err := r.Get(ctx, req.NamespacedName, schedule) + if err != nil { + if !k8sError.IsNotFound(err) { + r.Log.Error(err, "unable to get chaos") + } + return ctrl.Result{}, nil + } + + if schedule.Spec.Type == v1alpha1.ScheduleTypeWorkflow { + if schedule.IsPaused() { + r.Recorder.Event(schedule, recorder.NotSupported{ + Activity: "pausing a workflow schedule", + }) + } + return ctrl.Result{}, nil + } + + list, err := r.ActiveLister.ListActiveJobs(ctx, schedule) + if err != nil { + r.Recorder.Event(schedule, recorder.Failed{ + Activity: "list active jobs", + Err: err.Error(), + }) + return ctrl.Result{}, nil + } + + items := reflect.ValueOf(list).Elem().FieldByName("Items") + for i := 0; i < items.Len(); i++ { + item := items.Index(i).Addr().Interface().(v1alpha1.InnerObject) + if item.IsPaused() != schedule.IsPaused() { + key := k8sTypes.NamespacedName{ + Namespace: item.GetNamespace(), + Name: item.GetName(), + } + pause := strconv.FormatBool(schedule.IsPaused()) + + updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + r.Log.Info("updating object", "pause", schedule.IsPaused()) + + if err := r.Client.Get(ctx, key, item); err != nil { + r.Log.Error(err, "unable to get schedule") + return err + } + annotations := item.GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + annotations[v1alpha1.PauseAnnotationKey] = pause + item.SetAnnotations(annotations) + + return r.Client.Update(ctx, item) + }) + if updateError != nil { + r.Log.Error(updateError, "fail to update") + r.Recorder.Event(schedule, recorder.Failed{ + Activity: fmt.Sprintf("set pause to %s for %s", pause, key), + Err: updateError.Error(), + }) + return ctrl.Result{}, nil + } + } + } + + return ctrl.Result{}, nil +} + +const controllerName = "schedule-pause" + +func Bootstrap(mgr ctrl.Manager, client client.Client, log logr.Logger, lister *utils.ActiveLister, recorderBuilder *recorder.RecorderBuilder) error { + if !config.ShouldSpawnController(controllerName) { + return nil + } + return builder.Default(mgr). + For(&v1alpha1.Schedule{}). + Named(controllerName). + Complete(&Reconciler{ + client, + log.WithName(controllerName), + lister, + recorderBuilder.Build(controllerName), + }) +} diff --git a/controllers/schedule/schedule_test.go b/controllers/schedule/schedule_test.go new file mode 100644 index 0000000000..84b0585f63 --- /dev/null +++ b/controllers/schedule/schedule_test.go @@ -0,0 +1,407 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package schedule + +import ( + "context" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var _ = Describe("Schedule", func() { + + BeforeEach(func() { + // Add any setup steps that needs to be executed before each test + }) + + AfterEach(func() { + // Add any teardown steps that needs to be executed after each test + }) + + Context(("Schedule basic"), func() { + It(("Should be created and deleted successfully"), func() { + key := types.NamespacedName{ + Name: "foo0", + Namespace: "default", + } + duration := "100m" + schedule := &v1alpha1.Schedule{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo0", + Namespace: "default", + }, + Spec: v1alpha1.ScheduleSpec{ + Schedule: "@every 10s", + ScheduleItem: v1alpha1.ScheduleItem{ + EmbedChaos: v1alpha1.EmbedChaos{TimeChaos: &v1alpha1.TimeChaosSpec{ + TimeOffset: "100ms", + ClockIds: []string{"CLOCK_REALTIME"}, + Duration: &duration, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Mode: v1alpha1.OneMode, + }, + }, + }}, + }, + ConcurrencyPolicy: v1alpha1.ForbidConcurrent, + HistoryLimit: 5, + Type: v1alpha1.ScheduleTypeTimeChaos, + }, + Status: v1alpha1.ScheduleStatus{ + LastScheduleTime: metav1.NewTime(time.Time{}), + }, + } + + By("creating an API obj") + Expect(k8sClient.Create(context.TODO(), schedule)).To(Succeed()) + + fetched := &v1alpha1.Schedule{} + Expect(k8sClient.Get(context.TODO(), key, fetched)).To(Succeed()) + Expect(fetched).To(Equal(schedule)) + + By("deleting the created object") + Expect(k8sClient.Delete(context.TODO(), schedule)).To(Succeed()) + Expect(k8sClient.Get(context.TODO(), key, schedule)).ToNot(Succeed()) + }) + }) + + Context("Schedule cron", func() { + It("should create non-concurrent chaos", func() { + key := types.NamespacedName{ + Name: "foo1", + Namespace: "default", + } + duration := "100s" + schedule := &v1alpha1.Schedule{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo1", + Namespace: "default", + }, + Spec: v1alpha1.ScheduleSpec{ + Schedule: "@every 1s", + ScheduleItem: v1alpha1.ScheduleItem{ + EmbedChaos: v1alpha1.EmbedChaos{TimeChaos: &v1alpha1.TimeChaosSpec{ + TimeOffset: "100ms", + ClockIds: []string{"CLOCK_REALTIME"}, + Duration: &duration, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Mode: v1alpha1.OneMode, + }, + }, + }}, + }, + ConcurrencyPolicy: v1alpha1.ForbidConcurrent, + HistoryLimit: 2, + Type: v1alpha1.ScheduleTypeTimeChaos, + }, + Status: v1alpha1.ScheduleStatus{ + LastScheduleTime: metav1.NewTime(time.Now()), + }, + } + + By("creating a schedule obj") + { + Expect(k8sClient.Create(context.TODO(), schedule)).To(Succeed()) + } + + By("Reconciling the created schedule obj") + { + err := wait.Poll(time.Second*1, time.Minute*1, func() (ok bool, err error) { + err = k8sClient.Get(context.TODO(), key, schedule) + if err != nil { + return false, err + } + return len(schedule.Status.Active) > 0, nil + }) + Expect(err).ToNot(HaveOccurred()) + } + + By("Disallow concurrency") + { + time.Sleep(5 * time.Second) + err := k8sClient.Get(context.TODO(), key, schedule) + Expect(err).ToNot(HaveOccurred()) + Expect(len(schedule.Status.Active)).To(Equal(1)) + } + + By("deleting the created object") + { + Expect(k8sClient.Delete(context.TODO(), schedule)).To(Succeed()) + Expect(k8sClient.Get(context.TODO(), key, schedule)).ToNot(Succeed()) + } + }) + It("should create concurrent chaos", func() { + key := types.NamespacedName{ + Name: "foo2", + Namespace: "default", + } + duration := "100s" + schedule := &v1alpha1.Schedule{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo2", + Namespace: "default", + }, + Spec: v1alpha1.ScheduleSpec{ + Schedule: "@every 2s", + ScheduleItem: v1alpha1.ScheduleItem{ + EmbedChaos: v1alpha1.EmbedChaos{TimeChaos: &v1alpha1.TimeChaosSpec{ + TimeOffset: "100ms", + ClockIds: []string{"CLOCK_REALTIME"}, + Duration: &duration, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Mode: v1alpha1.OneMode, + }, + }, + }}, + }, + ConcurrencyPolicy: v1alpha1.AllowConcurrent, + HistoryLimit: 2, + Type: v1alpha1.ScheduleTypeTimeChaos, + }, + Status: v1alpha1.ScheduleStatus{ + LastScheduleTime: metav1.NewTime(time.Now()), + }, + } + + By("creating a schedule obj") + { + Expect(k8sClient.Create(context.TODO(), schedule)).To(Succeed()) + } + + By("Allowing concurrency and skip deleting running chaos") + { + err := wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { + err = k8sClient.Get(context.TODO(), key, schedule) + if err != nil { + return false, err + } + ctrl.Log.Info("active chaos", "size", len(schedule.Status.Active)) + return len(schedule.Status.Active) >= 4, nil + }) + Expect(err).ToNot(HaveOccurred()) + } + + By("deleting the created object") + { + Expect(k8sClient.Delete(context.TODO(), schedule)).To(Succeed()) + Expect(k8sClient.Get(context.TODO(), key, schedule)).ToNot(Succeed()) + } + }) + It("should collect garbage", func() { + key := types.NamespacedName{ + Name: "foo3", + Namespace: "default", + } + duration := "1s" + schedule := &v1alpha1.Schedule{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo3", + Namespace: "default", + }, + Spec: v1alpha1.ScheduleSpec{ + Schedule: "@every 3s", + ScheduleItem: v1alpha1.ScheduleItem{ + EmbedChaos: v1alpha1.EmbedChaos{TimeChaos: &v1alpha1.TimeChaosSpec{ + TimeOffset: "100ms", + ClockIds: []string{"CLOCK_REALTIME"}, + Duration: &duration, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Mode: v1alpha1.OneMode, + }, + }, + }}, + }, + ConcurrencyPolicy: v1alpha1.AllowConcurrent, + HistoryLimit: 2, + Type: v1alpha1.ScheduleTypeTimeChaos, + }, + Status: v1alpha1.ScheduleStatus{ + LastScheduleTime: metav1.NewTime(time.Now()), + }, + } + + By("creating a schedule obj") + { + Expect(k8sClient.Create(context.TODO(), schedule)).To(Succeed()) + } + + By("deleting outdated chaos") + { + time.Sleep(time.Second * 10) + err := wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { + err = k8sClient.Get(context.TODO(), key, schedule) + if err != nil { + return false, err + } + ctrl.Log.Info("active chaos", "size", len(schedule.Status.Active)) + return len(schedule.Status.Active) == 2, nil + }) + Expect(err).ToNot(HaveOccurred()) + } + + By("deleting the created object") + { + Expect(k8sClient.Delete(context.TODO(), schedule)).To(Succeed()) + Expect(k8sClient.Get(context.TODO(), key, schedule)).ToNot(Succeed()) + } + }) + }) + + Context(("Schedule workflow"), func() { + It(("Should forbid concurrent"), func() { + key := types.NamespacedName{ + Name: "foo10", + Namespace: "default", + } + duration := "10000s" + schedule := &v1alpha1.Schedule{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo10", + Namespace: "default", + }, + Spec: v1alpha1.ScheduleSpec{ + Schedule: "@every 3s", + ScheduleItem: v1alpha1.ScheduleItem{ + Workflow: &v1alpha1.WorkflowSpec{ + Entry: "the-entry", + Templates: []v1alpha1.Template{ + { + Name: "the-entry", + Type: v1alpha1.TypeSerial, + Deadline: &duration, + Children: []string{"hardwork"}, + }, + { + Name: "hardwork", + Type: v1alpha1.TypeSuspend, + Deadline: &duration, + Children: nil, + }, + }, + }, + }, + ConcurrencyPolicy: v1alpha1.ForbidConcurrent, + HistoryLimit: 2, + Type: v1alpha1.ScheduleTypeWorkflow, + }, + Status: v1alpha1.ScheduleStatus{ + LastScheduleTime: metav1.NewTime(time.Time{}), + }, + } + + By("creating a schedule obj") + { + Expect(k8sClient.Create(context.TODO(), schedule)).To(Succeed()) + } + + By("disallowing concurrent") + { + time.Sleep(time.Second * 10) + err := wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { + err = k8sClient.Get(context.TODO(), key, schedule) + if err != nil { + return false, err + } + ctrl.Log.Info("active chaos", "size", len(schedule.Status.Active)) + return len(schedule.Status.Active) == 1, nil + }) + Expect(err).ToNot(HaveOccurred()) + } + + By("deleting the created object") + { + Expect(k8sClient.Delete(context.TODO(), schedule)).To(Succeed()) + Expect(k8sClient.Get(context.TODO(), key, schedule)).ToNot(Succeed()) + } + }) + + It(("Should be garbage collected successfully"), func() { + key := types.NamespacedName{ + Name: "foo11", + Namespace: "default", + } + duration := "1s" + schedule := &v1alpha1.Schedule{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo11", + Namespace: "default", + }, + Spec: v1alpha1.ScheduleSpec{ + Schedule: "@every 3s", + ScheduleItem: v1alpha1.ScheduleItem{ + Workflow: &v1alpha1.WorkflowSpec{ + Entry: "the-entry", + Templates: []v1alpha1.Template{ + { + Name: "the-entry", + Type: v1alpha1.TypeSerial, + Deadline: &duration, + Children: nil, + }, + }, + }, + }, + ConcurrencyPolicy: v1alpha1.AllowConcurrent, + HistoryLimit: 2, + Type: v1alpha1.ScheduleTypeWorkflow, + }, + Status: v1alpha1.ScheduleStatus{ + LastScheduleTime: metav1.NewTime(time.Time{}), + }, + } + + By("creating a schedule obj") + { + Expect(k8sClient.Create(context.TODO(), schedule)).To(Succeed()) + } + + By("deleting outdated workflow") + { + time.Sleep(time.Second * 10) + err := wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { + err = k8sClient.Get(context.TODO(), key, schedule) + if err != nil { + return false, err + } + ctrl.Log.Info("active chaos", "size", len(schedule.Status.Active)) + return len(schedule.Status.Active) == 2, nil + }) + Expect(err).ToNot(HaveOccurred()) + } + + By("deleting the created object") + { + Expect(k8sClient.Delete(context.TODO(), schedule)).To(Succeed()) + Expect(k8sClient.Get(context.TODO(), key, schedule)).ToNot(Succeed()) + } + }) + }) +}) diff --git a/controllers/schedule/suite_test.go b/controllers/schedule/suite_test.go new file mode 100644 index 0000000000..8152ed2072 --- /dev/null +++ b/controllers/schedule/suite_test.go @@ -0,0 +1,139 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package schedule + +import ( + "context" + "os" + "path/filepath" + "testing" + "time" + + "github.com/go-logr/logr" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "go.uber.org/fx" + "k8s.io/client-go/rest" + "k8s.io/kubectl/pkg/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/schedule/utils" + "github.com/chaos-mesh/chaos-mesh/controllers/types" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/test" + "github.com/chaos-mesh/chaos-mesh/pkg/log" + "github.com/chaos-mesh/chaos-mesh/pkg/workflow/controllers" +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var app *fx.App +var k8sClient client.Client +var lister *utils.ActiveLister +var config *rest.Config +var testEnv *envtest.Environment +var setupLog = ctrl.Log.WithName("setup") + +func TestSchedule(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Schedule suit") +} + +var _ = BeforeSuite(func(ctx SpecContext) { + logf.SetLogger(log.NewZapLoggerWithWriter(GinkgoWriter)) + By("bootstrapping test environment") + t := true + if os.Getenv("USE_EXISTING_CLUSTER") == "true" { + testEnv = &envtest.Environment{ + UseExistingCluster: &t, + } + } else { + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, + } + } + + err := v1alpha1.SchemeBuilder.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + config, err = testEnv.Start() + Expect(err).ToNot(HaveOccurred()) + Expect(config).ToNot(BeNil()) + + k8sClient, err = client.New(config, client.Options{Scheme: scheme.Scheme}) + Expect(err).ToNot(HaveOccurred()) + Expect(k8sClient).ToNot(BeNil()) + + rootLogger, err := log.NewDefaultZapLogger() + Expect(err).ToNot(HaveOccurred()) + + app = fx.New( + fx.Options( + fx.Supply(rootLogger), + test.Module, + fx.Supply(config), + Module, + types.ChaosObjects, + ), + fx.Invoke(Run), + ) + startCtx, cancel := context.WithTimeout(context.Background(), app.StartTimeout()) + defer cancel() + + if err := app.Start(startCtx); err != nil { + setupLog.Error(err, "fail to start manager") + } + Expect(err).ToNot(HaveOccurred()) + +}, NodeTimeout(60*time.Second)) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + stopCtx, cancel := context.WithTimeout(context.Background(), app.StopTimeout()) + defer cancel() + + if err := app.Stop(stopCtx); err != nil { + setupLog.Error(err, "fail to stop manager") + } + err := testEnv.Stop() + Expect(err).ToNot(HaveOccurred()) +}) + +type RunParams struct { + fx.In + + Mgr ctrl.Manager + Logger logr.Logger + RecorderBuilder *recorder.RecorderBuilder + + Controllers []types.Controller `group:"controller"` + Objs []types.Object `group:"objs"` +} + +func Run(params RunParams) error { + lister = utils.NewActiveLister(k8sClient, params.Logger) + err := controllers.BootstrapWorkflowControllers(params.Mgr, params.Logger, params.RecorderBuilder) + if err != nil { + return err + } + return nil +} diff --git a/controllers/schedule/utils/list.go b/controllers/schedule/utils/list.go new file mode 100644 index 0000000000..09555bdc77 --- /dev/null +++ b/controllers/schedule/utils/list.go @@ -0,0 +1,56 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package utils + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type ActiveLister struct { + client.Client + Log logr.Logger +} + +// TODO: use another easy-to-used type for describing ChaosList +func (lister *ActiveLister) ListActiveJobs(ctx context.Context, schedule *v1alpha1.Schedule) (v1alpha1.GenericChaosList, error) { + kind, ok := v1alpha1.AllScheduleItemKinds()[string(schedule.Spec.Type)] + if !ok { + lister.Log.Info("unknown kind", "kind", schedule.Spec.Type) + return nil, errors.Errorf("Unknown type: %s", schedule.Spec.Type) + } + + list := kind.SpawnList() + err := lister.List(ctx, list, client.MatchingLabels{v1alpha1.LabelManagedBy: schedule.Name}) + if err != nil { + lister.Log.Error(err, "fail to list chaos") + return nil, nil + } + + return list, nil +} + +func NewActiveLister(c client.Client, logger logr.Logger) *ActiveLister { + return &ActiveLister{ + Client: c, + Log: logger.WithName("activeLister"), + } +} diff --git a/controllers/statuscheck/common_test.go b/controllers/statuscheck/common_test.go new file mode 100644 index 0000000000..07fdd06e19 --- /dev/null +++ b/controllers/statuscheck/common_test.go @@ -0,0 +1,72 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package statuscheck + +import ( + "time" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +// fakeHTTPExecutor +type fakeHTTPExecutor struct { + logger logr.Logger + + httpStatusCheck v1alpha1.HTTPStatusCheck + timeoutSeconds int +} + +func (e *fakeHTTPExecutor) Do() (bool, string, error) { + return e.handle() +} + +func (e *fakeHTTPExecutor) Type() string { + return "Fake-HTTP" +} + +func newFakeExecutor(logger logr.Logger, statusCheck v1alpha1.StatusCheck) (Executor, error) { + var executor Executor + switch statusCheck.Spec.Type { + case v1alpha1.TypeHTTP: + if statusCheck.Spec.EmbedStatusCheck == nil || statusCheck.Spec.HTTPStatusCheck == nil { + // this should not happen, if the webhook works as expected + return nil, errors.New("illegal status check, http should not be empty") + } + executor = &fakeHTTPExecutor{ + logger: logger.WithName("fake-http-executor"), + httpStatusCheck: *statusCheck.Spec.HTTPStatusCheck, + timeoutSeconds: statusCheck.Spec.TimeoutSeconds, + } + default: + return nil, errors.New("unsupported type") + } + return executor, nil +} + +func (e *fakeHTTPExecutor) handle() (bool, string, error) { + switch e.httpStatusCheck.RequestBody { + case "failure": + return false, "failure", nil + case "timeout": + time.Sleep(time.Duration(e.timeoutSeconds) * time.Second) + return false, "timeout", nil + default: + return true, "", nil + } +} diff --git a/controllers/statuscheck/conditions.go b/controllers/statuscheck/conditions.go new file mode 100644 index 0000000000..ea80fdbb29 --- /dev/null +++ b/controllers/statuscheck/conditions.go @@ -0,0 +1,158 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package statuscheck + +import ( + "time" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type conditionMap map[v1alpha1.StatusCheckConditionType]v1alpha1.StatusCheckCondition + +func toConditionMap(conditions []v1alpha1.StatusCheckCondition) conditionMap { + result := make(map[v1alpha1.StatusCheckConditionType]v1alpha1.StatusCheckCondition) + for _, condition := range conditions { + condition := condition + result[condition.Type] = condition + } + return result +} + +func toConditionList(conditions conditionMap) []v1alpha1.StatusCheckCondition { + result := make([]v1alpha1.StatusCheckCondition, 0, len(conditions)) + for _, condition := range conditions { + condition := condition + result = append(result, condition) + } + return result +} + +func (in conditionMap) setCondition( + t v1alpha1.StatusCheckConditionType, + status corev1.ConditionStatus, + reason v1alpha1.StatusCheckReason) { + condition, ok := in[t] + now := &metav1.Time{Time: time.Now()} + if !ok { + in[t] = v1alpha1.StatusCheckCondition{ + Type: t, + Status: status, + Reason: reason, + LastProbeTime: now, + LastTransitionTime: now, + } + } else { + condition.LastProbeTime = now + condition.Reason = reason + if status != condition.Status { + condition.Status = status + condition.LastTransitionTime = now + } + in[t] = condition + } +} + +func (in conditionMap) isCompleted() bool { + cond, ok := in[v1alpha1.StatusCheckConditionCompleted] + return ok && cond.Status == corev1.ConditionTrue +} + +func (in conditionMap) isDurationExceed() bool { + cond, ok := in[v1alpha1.StatusCheckConditionDurationExceed] + return ok && cond.Status == corev1.ConditionTrue +} + +func (in conditionMap) isFailureThresholdExceed() bool { + cond, ok := in[v1alpha1.StatusCheckConditionFailureThresholdExceed] + return ok && cond.Status == corev1.ConditionTrue +} + +func (in conditionMap) isSuccessThresholdExceed() bool { + cond, ok := in[v1alpha1.StatusCheckConditionSuccessThresholdExceed] + return ok && cond.Status == corev1.ConditionTrue +} + +func setDurationExceedCondition(statusCheck v1alpha1.StatusCheck, conditions conditionMap) error { + now := time.Now() + ok, _, err := statusCheck.DurationExceed(now) + if err != nil { + return err + } + if !ok { + conditions.setCondition(v1alpha1.StatusCheckConditionDurationExceed, corev1.ConditionFalse, "") + } else { + conditions.setCondition(v1alpha1.StatusCheckConditionDurationExceed, corev1.ConditionTrue, "") + } + return nil +} + +// setFailureThresholdExceedCondition check if the failure threshold is exceeded, and then set the condition into conditionMap +// Notice: the method `execute` of `worker` struct in `controllers/statuscheck/worker.go` checks the failure threshold, +// so if you want to modify the logic here, don't forget to modify that function as well. +func setFailureThresholdExceedCondition(statusCheck v1alpha1.StatusCheck, conditions conditionMap) { + if isThresholdExceed(statusCheck.Status.Records, v1alpha1.StatusCheckOutcomeFailure, statusCheck.Spec.FailureThreshold) { + conditions.setCondition(v1alpha1.StatusCheckConditionFailureThresholdExceed, corev1.ConditionTrue, "") + } else { + conditions.setCondition(v1alpha1.StatusCheckConditionFailureThresholdExceed, corev1.ConditionFalse, "") + } +} + +// setSuccessThresholdExceedCondition check if the success threshold is exceeded, and then set the condition into conditionMap +// Notice: the method `execute` of `worker` struct in `controllers/statuscheck/worker.go` checks the success threshold, +// so if you want to modify the logic here, don't forget to modify that function as well. +func setSuccessThresholdExceedCondition(statusCheck v1alpha1.StatusCheck, conditions conditionMap) { + if isThresholdExceed(statusCheck.Status.Records, v1alpha1.StatusCheckOutcomeSuccess, statusCheck.Spec.SuccessThreshold) { + conditions.setCondition(v1alpha1.StatusCheckConditionSuccessThresholdExceed, corev1.ConditionTrue, "") + } else { + conditions.setCondition(v1alpha1.StatusCheckConditionSuccessThresholdExceed, corev1.ConditionFalse, "") + } +} + +func setCompletedCondition(statusCheck v1alpha1.StatusCheck, conditions conditionMap) { + if conditions.isDurationExceed() { + conditions.setCondition(v1alpha1.StatusCheckConditionCompleted, corev1.ConditionTrue, v1alpha1.StatusCheckDurationExceed) + return + } + if conditions.isFailureThresholdExceed() { + conditions.setCondition(v1alpha1.StatusCheckConditionCompleted, corev1.ConditionTrue, v1alpha1.StatusCheckFailureThresholdExceed) + return + } + if statusCheck.Spec.Mode == v1alpha1.StatusCheckSynchronous { + if conditions.isSuccessThresholdExceed() { + conditions.setCondition(v1alpha1.StatusCheckConditionCompleted, corev1.ConditionTrue, v1alpha1.StatusCheckSuccessThresholdExceed) + return + } + } + conditions.setCondition(v1alpha1.StatusCheckConditionCompleted, corev1.ConditionFalse, "") +} + +func isThresholdExceed(records []v1alpha1.StatusCheckRecord, outcome v1alpha1.StatusCheckOutcome, threshold int) bool { + count := 0 + for i := len(records) - 1; i >= 0; i-- { + if records[i].Outcome != outcome { + return false + } + count++ + if count >= threshold { + return true + } + } + return false +} diff --git a/controllers/statuscheck/conditions_test.go b/controllers/statuscheck/conditions_test.go new file mode 100644 index 0000000000..b36809078b --- /dev/null +++ b/controllers/statuscheck/conditions_test.go @@ -0,0 +1,92 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package statuscheck + +import ( + "testing" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +func Test_isThresholdExceed(t *testing.T) { + type args struct { + records []v1alpha1.StatusCheckRecord + outcome v1alpha1.StatusCheckOutcome + threshold int + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "not exceed", + args: args{ + records: []v1alpha1.StatusCheckRecord{ + {Outcome: v1alpha1.StatusCheckOutcomeFailure}, + {Outcome: v1alpha1.StatusCheckOutcomeSuccess}, + {Outcome: v1alpha1.StatusCheckOutcomeFailure}, + }, + outcome: v1alpha1.StatusCheckOutcomeFailure, + threshold: 2, + }, + want: false, + }, + { + name: "exceed", + args: args{ + records: []v1alpha1.StatusCheckRecord{ + {Outcome: v1alpha1.StatusCheckOutcomeFailure}, + }, + outcome: v1alpha1.StatusCheckOutcomeFailure, + threshold: 1, + }, + want: true, + }, + { + name: "exceed", + args: args{ + records: []v1alpha1.StatusCheckRecord{ + {Outcome: v1alpha1.StatusCheckOutcomeSuccess}, + {Outcome: v1alpha1.StatusCheckOutcomeFailure}, + {Outcome: v1alpha1.StatusCheckOutcomeFailure}, + }, + outcome: v1alpha1.StatusCheckOutcomeFailure, + threshold: 2, + }, + want: true, + }, + { + name: "threshold is bigger than the length of record", + args: args{ + records: []v1alpha1.StatusCheckRecord{ + {Outcome: v1alpha1.StatusCheckOutcomeFailure}, + {Outcome: v1alpha1.StatusCheckOutcomeFailure}, + }, + outcome: v1alpha1.StatusCheckOutcomeFailure, + threshold: 3, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := isThresholdExceed(tt.args.records, tt.args.outcome, tt.args.threshold); got != tt.want { + t.Errorf("isThresholdExceed() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/controllers/statuscheck/controller.go b/controllers/statuscheck/controller.go new file mode 100644 index 0000000000..9fd73b54d6 --- /dev/null +++ b/controllers/statuscheck/controller.go @@ -0,0 +1,141 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package statuscheck + +import ( + "context" + "fmt" + "time" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" +) + +type Reconciler struct { + logger logr.Logger + kubeClient client.Client + eventRecorder recorder.ChaosRecorder + manager Manager +} + +func NewReconciler(logger logr.Logger, kubeClient client.Client, eventRecorder recorder.ChaosRecorder, manager Manager) *Reconciler { + return &Reconciler{ + kubeClient: kubeClient, + eventRecorder: eventRecorder, + logger: logger, + manager: manager, + } +} + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + startTime := time.Now() + obj := &v1alpha1.StatusCheck{} + if err := r.kubeClient.Get(ctx, req.NamespacedName, obj); err != nil { + if apierrors.IsNotFound(err) { + r.logger.Info("status check is deleted", "statuscheck", req.NamespacedName) + // the StatusCheck is deleted, remove it from manger + r.manager.Delete(req.NamespacedName) + return ctrl.Result{}, nil + } + return ctrl.Result{}, errors.Wrapf(err, "get status check '%s'", req.NamespacedName.String()) + } + + // if status check was completed previously, we don't want to redo the termination + if obj.IsCompleted() { + r.logger.V(1).Info("status check is already completed", "statuscheck", req.NamespacedName) + return ctrl.Result{}, nil + } + + result, ok := r.manager.Get(*obj) + if !ok { + // if nil, add status check to manager + err := r.manager.Add(*obj) + if err != nil { + return ctrl.Result{}, errors.Wrapf(err, "add status check '%s' to manager", req.NamespacedName.String()) + } + result, _ = r.manager.Get(*obj) + } + + updateError := retry.RetryOnConflict(retry.DefaultBackoff, r.updateStatus(ctx, req, result, startTime)) + + return ctrl.Result{RequeueAfter: time.Duration(obj.Spec.IntervalSeconds) * time.Second}, client.IgnoreNotFound(updateError) +} + +func (r *Reconciler) updateStatus(ctx context.Context, req ctrl.Request, result Result, startTime time.Time) func() error { + return func() error { + statusCheck := &v1alpha1.StatusCheck{} + if err := r.kubeClient.Get(ctx, req.NamespacedName, statusCheck); err != nil { + return errors.Wrapf(err, "get status check '%s'", req.NamespacedName.String()) + } + + if statusCheck.Status.StartTime == nil { + statusCheck.Status.StartTime = &metav1.Time{Time: startTime} + } + statusCheck.Status.Count = result.Count + statusCheck.Status.Records = result.Records + + conditions, err := r.generateConditions(*statusCheck) + if err != nil { + return errors.Wrapf(err, "generate conditions for status check '%s'", req.NamespacedName.String()) + } + + if conditions.isCompleted() { + if statusCheck.Status.CompletionTime == nil { + statusCheck.Status.CompletionTime = &metav1.Time{Time: time.Now()} + } + r.manager.Complete(*statusCheck) + r.eventRecorder.Event(statusCheck, recorder.StatusCheckCompleted{Msg: conditions[v1alpha1.StatusCheckConditionCompleted].Reason}) + r.logger.Info("status check is completed", "statuscheck", req.NamespacedName) + } + if conditions.isDurationExceed() { + r.eventRecorder.Event(statusCheck, recorder.StatusCheckDurationExceed{}) + } + if conditions.isSuccessThresholdExceed() { + r.eventRecorder.Event(statusCheck, recorder.StatusCheckSuccessThresholdExceed{}) + } + if conditions.isFailureThresholdExceed() { + r.eventRecorder.Event(statusCheck, recorder.StatusCheckFailureThresholdExceed{}) + } + + statusCheck.Status.Conditions = toConditionList(conditions) + + r.logger.V(1).Info("update status of status check", "statuscheck", req.NamespacedName) + return r.kubeClient.Status().Update(ctx, statusCheck) + } +} + +func (r *Reconciler) generateConditions(statusCheck v1alpha1.StatusCheck) (conditionMap, error) { + conditions := toConditionMap(statusCheck.Status.Conditions) + + if err := setDurationExceedCondition(statusCheck, conditions); err != nil { + return nil, errors.Wrapf(err, "set duration exceed condition for status check '%s'", fmt.Sprintf("%s/%s", statusCheck.Namespace, statusCheck.Name)) + } + setFailureThresholdExceedCondition(statusCheck, conditions) + setSuccessThresholdExceedCondition(statusCheck, conditions) + + // this condition must be placed after the above three conditions + setCompletedCondition(statusCheck, conditions) + + return conditions, nil +} diff --git a/controllers/statuscheck/controller_test.go b/controllers/statuscheck/controller_test.go new file mode 100644 index 0000000000..c42643a1ff --- /dev/null +++ b/controllers/statuscheck/controller_test.go @@ -0,0 +1,500 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package statuscheck + +import ( + "context" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gstruct" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var _ = Describe("StatusCheck", func() { + + BeforeEach(func() { + // Add any setup steps that needs to be executed before each test + }) + + AfterEach(func() { + // Add any teardown steps that needs to be executed after each test + }) + + Context("Reconcile Synchronous StatusCheck", func() { + It("success threshold exceed", func() { + key := types.NamespacedName{ + Name: "foo1", + Namespace: "default", + } + statusCheck := &v1alpha1.StatusCheck{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo1", + Namespace: "default", + }, + Spec: v1alpha1.StatusCheckSpec{ + Mode: v1alpha1.StatusCheckSynchronous, + Type: v1alpha1.TypeHTTP, + IntervalSeconds: 1, + TimeoutSeconds: 1, + FailureThreshold: 3, + SuccessThreshold: 1, + RecordsHistoryLimit: 10, + EmbedStatusCheck: &v1alpha1.EmbedStatusCheck{ + HTTPStatusCheck: &v1alpha1.HTTPStatusCheck{ + RequestUrl: "http://123.123.123.123", + RequestBody: "success", + Criteria: v1alpha1.HTTPCriteria{ + StatusCode: "200", + }, + }, + }, + }, + } + + By("creating a status check") + { + Expect(k8sClient.Create(context.TODO(), statusCheck)).To(Succeed()) + } + + By("reconciling status check") + { + Eventually(func() ([]v1alpha1.StatusCheckCondition, error) { + err := k8sClient.Get(context.TODO(), key, statusCheck) + if err != nil { + return nil, err + } + return statusCheck.Status.Conditions, nil + }, 5*time.Second, time.Second).Should( + ConsistOf( + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionCompleted), + "Status": Equal(corev1.ConditionTrue), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionSuccessThresholdExceed), + "Status": Equal(corev1.ConditionTrue), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionFailureThresholdExceed), + "Status": Equal(corev1.ConditionFalse), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionDurationExceed), + "Status": Equal(corev1.ConditionFalse), + }), + )) + } + + By("deleting the created object") + { + Expect(k8sClient.Delete(context.TODO(), statusCheck)).To(Succeed()) + } + }) + It("failure threshold exceed", func() { + key := types.NamespacedName{ + Name: "foo1", + Namespace: "default", + } + statusCheck := &v1alpha1.StatusCheck{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo1", + Namespace: "default", + }, + Spec: v1alpha1.StatusCheckSpec{ + Mode: v1alpha1.StatusCheckSynchronous, + Type: v1alpha1.TypeHTTP, + IntervalSeconds: 1, + TimeoutSeconds: 1, + FailureThreshold: 3, + SuccessThreshold: 1, + RecordsHistoryLimit: 10, + EmbedStatusCheck: &v1alpha1.EmbedStatusCheck{ + HTTPStatusCheck: &v1alpha1.HTTPStatusCheck{ + RequestUrl: "http://123.123.123.123", + RequestBody: "failure", + Criteria: v1alpha1.HTTPCriteria{ + StatusCode: "200", + }, + }, + }, + }, + } + + By("creating a status check") + { + Expect(k8sClient.Create(context.TODO(), statusCheck)).To(Succeed()) + } + + By("reconciling status check") + { + Eventually(func() ([]v1alpha1.StatusCheckCondition, error) { + err := k8sClient.Get(context.TODO(), key, statusCheck) + if err != nil { + return nil, err + } + return statusCheck.Status.Conditions, nil + }, 10*time.Second, time.Second).Should( + ConsistOf( + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionCompleted), + "Status": Equal(corev1.ConditionTrue), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionSuccessThresholdExceed), + "Status": Equal(corev1.ConditionFalse), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionFailureThresholdExceed), + "Status": Equal(corev1.ConditionTrue), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionDurationExceed), + "Status": Equal(corev1.ConditionFalse), + }), + )) + } + + By("deleting the created object") + { + Expect(k8sClient.Delete(context.TODO(), statusCheck)).To(Succeed()) + } + }) + It("duration exceed", func() { + key := types.NamespacedName{ + Name: "foo1", + Namespace: "default", + } + duration := "100ms" + statusCheck := &v1alpha1.StatusCheck{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo1", + Namespace: "default", + }, + Spec: v1alpha1.StatusCheckSpec{ + Mode: v1alpha1.StatusCheckSynchronous, + Type: v1alpha1.TypeHTTP, + IntervalSeconds: 1, + TimeoutSeconds: 1, + FailureThreshold: 3, + SuccessThreshold: 3, + RecordsHistoryLimit: 10, + Duration: &duration, + EmbedStatusCheck: &v1alpha1.EmbedStatusCheck{ + HTTPStatusCheck: &v1alpha1.HTTPStatusCheck{ + RequestUrl: "http://123.123.123.123", + RequestBody: "success", + Criteria: v1alpha1.HTTPCriteria{ + StatusCode: "200", + }, + }, + }, + }, + } + + By("creating a status check") + { + Expect(k8sClient.Create(context.TODO(), statusCheck)).To(Succeed()) + } + + By("reconciling status check") + { + Eventually(func() ([]v1alpha1.StatusCheckCondition, error) { + err := k8sClient.Get(context.TODO(), key, statusCheck) + if err != nil { + return nil, err + } + return statusCheck.Status.Conditions, nil + }, 10*time.Second, time.Second).Should( + ConsistOf( + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionCompleted), + "Status": Equal(corev1.ConditionTrue), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionSuccessThresholdExceed), + "Status": Equal(corev1.ConditionFalse), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionFailureThresholdExceed), + "Status": Equal(corev1.ConditionFalse), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionDurationExceed), + "Status": Equal(corev1.ConditionTrue), + }), + )) + } + + By("deleting the created object") + { + Expect(k8sClient.Delete(context.TODO(), statusCheck)).To(Succeed()) + } + }) + It("failure threshold exceed, execution timeout", func() { + key := types.NamespacedName{ + Name: "foo1", + Namespace: "default", + } + statusCheck := &v1alpha1.StatusCheck{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo1", + Namespace: "default", + }, + Spec: v1alpha1.StatusCheckSpec{ + Mode: v1alpha1.StatusCheckSynchronous, + Type: v1alpha1.TypeHTTP, + IntervalSeconds: 1, + TimeoutSeconds: 1, + FailureThreshold: 3, + SuccessThreshold: 1, + RecordsHistoryLimit: 10, + EmbedStatusCheck: &v1alpha1.EmbedStatusCheck{ + HTTPStatusCheck: &v1alpha1.HTTPStatusCheck{ + RequestUrl: "http://123.123.123.123", + RequestBody: "timeout", + Criteria: v1alpha1.HTTPCriteria{ + StatusCode: "200", + }, + }, + }, + }, + } + + By("creating a status check") + { + Expect(k8sClient.Create(context.TODO(), statusCheck)).To(Succeed()) + } + + By("reconciling status check") + { + Eventually(func() ([]v1alpha1.StatusCheckCondition, error) { + err := k8sClient.Get(context.TODO(), key, statusCheck) + if err != nil { + return nil, err + } + return statusCheck.Status.Conditions, nil + }, 10*time.Second, time.Second).Should( + ConsistOf( + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionCompleted), + "Status": Equal(corev1.ConditionTrue), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionSuccessThresholdExceed), + "Status": Equal(corev1.ConditionFalse), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionFailureThresholdExceed), + "Status": Equal(corev1.ConditionTrue), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionDurationExceed), + "Status": Equal(corev1.ConditionFalse), + }), + )) + } + + By("deleting the created object") + { + Expect(k8sClient.Delete(context.TODO(), statusCheck)).To(Succeed()) + } + }) + + Context("Reconcile Continuous StatusCheck", func() { + It("success threshold exceed", func() { + key := types.NamespacedName{ + Name: "foo1", + Namespace: "default", + } + duration := "10s" + statusCheck := &v1alpha1.StatusCheck{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo1", + Namespace: "default", + }, + Spec: v1alpha1.StatusCheckSpec{ + Mode: v1alpha1.StatusCheckContinuous, + Type: v1alpha1.TypeHTTP, + Duration: &duration, + IntervalSeconds: 1, + TimeoutSeconds: 1, + FailureThreshold: 3, + SuccessThreshold: 1, + RecordsHistoryLimit: 10, + EmbedStatusCheck: &v1alpha1.EmbedStatusCheck{ + HTTPStatusCheck: &v1alpha1.HTTPStatusCheck{ + RequestUrl: "http://123.123.123.123", + RequestBody: "success", + Criteria: v1alpha1.HTTPCriteria{ + StatusCode: "200", + }, + }, + }, + }, + } + + By("creating a status check") + { + Expect(k8sClient.Create(context.TODO(), statusCheck)).To(Succeed()) + } + + By("reconciling status check, success threshold exceed but not completed") + { + Eventually(func() ([]v1alpha1.StatusCheckCondition, error) { + err := k8sClient.Get(context.TODO(), key, statusCheck) + if err != nil { + return nil, err + } + return statusCheck.Status.Conditions, nil + }, 5*time.Second, time.Second).Should( + ConsistOf( + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionCompleted), + "Status": Equal(corev1.ConditionFalse), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionSuccessThresholdExceed), + "Status": Equal(corev1.ConditionTrue), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionFailureThresholdExceed), + "Status": Equal(corev1.ConditionFalse), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionDurationExceed), + "Status": Equal(corev1.ConditionFalse), + }), + )) + } + + By("reconciling status check, duration exceed and completed") + { + Eventually(func() ([]v1alpha1.StatusCheckCondition, error) { + err := k8sClient.Get(context.TODO(), key, statusCheck) + if err != nil { + return nil, err + } + return statusCheck.Status.Conditions, nil + }, 10*time.Second, time.Second).Should( + ConsistOf( + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionCompleted), + "Status": Equal(corev1.ConditionTrue), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionSuccessThresholdExceed), + "Status": Equal(corev1.ConditionTrue), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionFailureThresholdExceed), + "Status": Equal(corev1.ConditionFalse), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionDurationExceed), + "Status": Equal(corev1.ConditionTrue), + }), + )) + } + + By("deleting the created object") + { + Expect(k8sClient.Delete(context.TODO(), statusCheck)).To(Succeed()) + } + }) + + It("failure threshold exceed", func() { + key := types.NamespacedName{ + Name: "foo1", + Namespace: "default", + } + duration := "10s" + statusCheck := &v1alpha1.StatusCheck{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo1", + Namespace: "default", + }, + Spec: v1alpha1.StatusCheckSpec{ + Mode: v1alpha1.StatusCheckContinuous, + Type: v1alpha1.TypeHTTP, + Duration: &duration, + IntervalSeconds: 1, + TimeoutSeconds: 1, + FailureThreshold: 3, + SuccessThreshold: 1, + RecordsHistoryLimit: 10, + EmbedStatusCheck: &v1alpha1.EmbedStatusCheck{ + HTTPStatusCheck: &v1alpha1.HTTPStatusCheck{ + RequestUrl: "http://123.123.123.123", + RequestBody: "failure", + Criteria: v1alpha1.HTTPCriteria{ + StatusCode: "200", + }, + }, + }, + }, + } + + By("creating a status check") + { + Expect(k8sClient.Create(context.TODO(), statusCheck)).To(Succeed()) + } + + By("reconciling status check, failure threshold exceed and completed (duration not exceed)") + { + Eventually(func() ([]v1alpha1.StatusCheckCondition, error) { + err := k8sClient.Get(context.TODO(), key, statusCheck) + if err != nil { + return nil, err + } + return statusCheck.Status.Conditions, nil + }, 5*time.Second, time.Second).Should( + ConsistOf( + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionCompleted), + "Status": Equal(corev1.ConditionTrue), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionSuccessThresholdExceed), + "Status": Equal(corev1.ConditionFalse), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionFailureThresholdExceed), + "Status": Equal(corev1.ConditionTrue), + }), + MatchFields(IgnoreExtras, Fields{ + "Type": Equal(v1alpha1.StatusCheckConditionDurationExceed), + "Status": Equal(corev1.ConditionFalse), + }), + )) + } + + By("deleting the created object") + { + Expect(k8sClient.Delete(context.TODO(), statusCheck)).To(Succeed()) + } + }) + }) + }) +}) diff --git a/controllers/statuscheck/fx.go b/controllers/statuscheck/fx.go new file mode 100644 index 0000000000..afd7744801 --- /dev/null +++ b/controllers/statuscheck/fx.go @@ -0,0 +1,40 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package statuscheck + +import ( + "github.com/go-logr/logr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/builder" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" +) + +func Bootstrap(mgr ctrl.Manager, client client.Client, logger logr.Logger, recorderBuilder *recorder.RecorderBuilder) error { + if !config.ShouldSpawnController("statuscheck") { + return nil + } + eventRecorder := recorderBuilder.Build("statuscheck") + manager := NewManager(logger.WithName("statuscheck-manager"), eventRecorder, newExecutor) + + return builder.Default(mgr). + For(&v1alpha1.StatusCheck{}). + Named("statuscheck"). + Complete(NewReconciler(logger.WithName("statuscheck-reconciler"), client, eventRecorder, manager)) +} diff --git a/controllers/statuscheck/http/http.go b/controllers/statuscheck/http/http.go new file mode 100644 index 0000000000..3b96d3a7ac --- /dev/null +++ b/controllers/statuscheck/http/http.go @@ -0,0 +1,124 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package http + +import ( + "bytes" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "time" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type httpExecutor struct { + logger logr.Logger + + timeoutSeconds int + httpStatusCheck v1alpha1.HTTPStatusCheck +} + +func NewExecutor(logger logr.Logger, timeoutSeconds int, httpStatusCheck v1alpha1.HTTPStatusCheck) *httpExecutor { + return &httpExecutor{logger: logger, timeoutSeconds: timeoutSeconds, httpStatusCheck: httpStatusCheck} +} + +type response struct { + statusCode int + body string +} + +func (e *httpExecutor) Type() string { + return "HTTP" +} + +func (e *httpExecutor) Do() (bool, string, error) { + client := &http.Client{ + Timeout: time.Duration(e.timeoutSeconds) * time.Second, + } + + httpStatusCheck := e.httpStatusCheck + return e.DoHTTPRequest(client, + httpStatusCheck.RequestUrl, + string(httpStatusCheck.RequestMethod), + httpStatusCheck.RequestHeaders, + []byte(httpStatusCheck.RequestBody), + httpStatusCheck.Criteria) +} + +func (e *httpExecutor) DoHTTPRequest(client *http.Client, url, method string, + headers http.Header, body []byte, criteria v1alpha1.HTTPCriteria) (bool, string, error) { + req, err := http.NewRequest(method, url, bytes.NewReader(body)) + if err != nil { + return false, errors.Wrap(err, "new http request").Error(), nil + } + req.Header = headers + resp, err := client.Do(req) + if err != nil { + return false, errors.Wrap(err, "do http request").Error(), nil + } + defer resp.Body.Close() + + responseBody, err := io.ReadAll(resp.Body) + if err != nil { + return false, "", errors.Wrap(err, "read response body") + } + + return validate(e.logger.WithValues("url", url), + criteria, response{statusCode: resp.StatusCode, body: string(responseBody)}) +} + +func validate(logger logr.Logger, criteria v1alpha1.HTTPCriteria, resp response) (bool, string, error) { + ok := validateStatusCode(criteria.StatusCode, resp) + if !ok { + logger.Info("validate status code failed", + "criteria", criteria.StatusCode, + "statusCode", resp.statusCode) + return false, fmt.Sprintf("unexpected status code: %d", resp.statusCode), nil + } + return ok, "", nil +} + +// validateStatusCode validate whether the result is as expected. +// A criteria(statusCode) string could be a single code (e.g. 200), or +// an inclusive range (e.g. 200-400, both `200` and `400` are included). +// The format of the criteria field will be validated in webhook. +func validateStatusCode(criteria string, resp response) bool { + if code, err := strconv.Atoi(criteria); err == nil { + return code == resp.statusCode + } + index := strings.Index(criteria, "-") + if index == -1 { + return false + } + start := criteria[:index] + end := criteria[index+1:] + startStatusCode, err := strconv.Atoi(start) + if err != nil { + return false + } + endStatusCode, err := strconv.Atoi(end) + if err != nil { + return false + } + return resp.statusCode >= startStatusCode && + resp.statusCode <= endStatusCode +} diff --git a/controllers/statuscheck/http/http_test.go b/controllers/statuscheck/http/http_test.go new file mode 100644 index 0000000000..cdd6302a6c --- /dev/null +++ b/controllers/statuscheck/http/http_test.go @@ -0,0 +1,73 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package http + +import "testing" + +func Test_validateStatusCode(t *testing.T) { + tcs := []struct { + name string + criteria string + result int + expect bool + }{ + { + name: "single code, correct result", + criteria: "200", + result: 200, + expect: true, + }, { + name: "single code, wrong result", + criteria: "200", + result: 201, + expect: false, + }, { + name: "code range, correct result", + criteria: "200-200", + result: 200, + expect: true, + }, { + name: "code range, correct result", + criteria: "200-400", + result: 400, + expect: true, + }, { + name: "code range, wrong result", + criteria: "200-400", + result: 500, + expect: false, + }, { + name: "illegal criteria", + criteria: "200.400", + result: 500, + expect: false, + }, { + name: "illegal criteria", + criteria: "200-x", + result: 500, + expect: false, + }, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + ok := validateStatusCode(tc.criteria, response{statusCode: tc.result}) + if ok != tc.expect { + t.Errorf("criteria: %s result: %d expect: %t", tc.criteria, tc.result, tc.expect) + } + }) + } +} diff --git a/controllers/statuscheck/manager.go b/controllers/statuscheck/manager.go new file mode 100644 index 0000000000..3bfddc3fd9 --- /dev/null +++ b/controllers/statuscheck/manager.go @@ -0,0 +1,210 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package statuscheck + +import ( + "sync" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/types" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/statuscheck/http" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" +) + +type Manager interface { + // Add creates new workers for every status check. + Add(statusCheck v1alpha1.StatusCheck) error + // Get returns the cached results about the status check. + Get(statusCheck v1alpha1.StatusCheck) (Result, bool) + // Delete handles cleaning up the removed status check state, including terminating workers and + // deleting cached results. + // This should be called when StatusCheck is deleted. + Delete(key types.NamespacedName) + // Complete handles terminating workers, but not deleting cached results. + // This should be called when StatusCheck is completed. + Complete(statusCheck v1alpha1.StatusCheck) +} + +type manager struct { + logger logr.Logger + eventRecorder recorder.ChaosRecorder + + workers workerCache + results resultCache + newExecutor newExecutorFunc +} + +type newExecutorFunc func(logger logr.Logger, statusCheck v1alpha1.StatusCheck) (Executor, error) + +func NewManager(logger logr.Logger, eventRecorder recorder.ChaosRecorder, newExecutorFunc newExecutorFunc) Manager { + return &manager{ + logger: logger, + eventRecorder: eventRecorder, + workers: workerCache{workers: sync.Map{}}, + results: resultCache{results: make(map[types.NamespacedName]Result)}, + newExecutor: newExecutorFunc, + } +} + +func (m *manager) Add(statusCheck v1alpha1.StatusCheck) error { + key := types.NamespacedName{Namespace: statusCheck.Namespace, Name: statusCheck.Name} + if _, ok := m.results.get(key); ok { + return nil + } + m.results.init(key, statusCheck.Status.Records, statusCheck.Status.Count, uint(statusCheck.Spec.RecordsHistoryLimit)) + + if statusCheck.IsCompleted() { + // if status check is completed, there is no need to create a worker + return errors.New("status check is completed") + } + + executor, err := m.newExecutor(m.logger, statusCheck) + if err != nil { + return errors.Wrap(err, "new executor") + } + worker := newWorker(m.logger.WithName("worker").WithValues("statuscheck", key), m.eventRecorder, m, statusCheck, executor) + m.workers.add(key, worker) + return nil +} + +func (m *manager) Get(statusCheck v1alpha1.StatusCheck) (Result, bool) { + key := types.NamespacedName{Namespace: statusCheck.Namespace, Name: statusCheck.Name} + result, ok := m.results.get(key) + if !ok { + return Result{}, false + } + return result, true +} + +func (m *manager) Delete(key types.NamespacedName) { + m.results.delete(key) + m.workers.delete(key) +} + +func (m *manager) Complete(statusCheck v1alpha1.StatusCheck) { + key := types.NamespacedName{Namespace: statusCheck.Namespace, Name: statusCheck.Name} + m.workers.delete(key) +} + +// workerCache provides cached workers. +type workerCache struct { + // Map of NamespacedName of StatusCheck -> *worker + workers sync.Map +} + +func (c *workerCache) add(key types.NamespacedName, worker *worker) { + _, ok := c.workers.LoadOrStore(key, worker) + if !ok { + go worker.run() + } +} + +func (c *workerCache) delete(key types.NamespacedName) { + obj, ok := c.workers.LoadAndDelete(key) + if !ok { + return + } + worker := obj.(*worker) + worker.stop() +} + +// resultCache provides cached status check results. +type resultCache struct { + // Map of NamespacedName of StatusCheck -> *result + results map[types.NamespacedName]Result + lock sync.RWMutex +} + +type Result struct { + Records []v1alpha1.StatusCheckRecord + Count int64 + // recordsHistoryLimit defines the number of record to retain. + recordsHistoryLimit uint +} + +// init should only be called when adding a new worker. +func (c *resultCache) init(key types.NamespacedName, obj []v1alpha1.StatusCheckRecord, count int64, limit uint) { + c.lock.Lock() + defer c.lock.Unlock() + + if _, ok := c.results[key]; ok { + return + } + if len(obj) == 0 { + obj = make([]v1alpha1.StatusCheckRecord, 0) + count = 0 + } + c.results[key] = Result{ + Records: limitRecords(obj, limit), + Count: count, + recordsHistoryLimit: limit, + } +} + +// append will append the record to the cache. +// It should be only called by worker +func (c *resultCache) append(key types.NamespacedName, obj v1alpha1.StatusCheckRecord) { + c.lock.Lock() + defer c.lock.Unlock() + + result := c.results[key] + result.Records = append(result.Records, obj) + result.Records = limitRecords(result.Records, result.recordsHistoryLimit) + result.Count++ + c.results[key] = result +} + +func (c *resultCache) delete(key types.NamespacedName) { + c.lock.Lock() + defer c.lock.Unlock() + + delete(c.results, key) +} + +func (c *resultCache) get(key types.NamespacedName) (Result, bool) { + c.lock.RLock() + defer c.lock.RUnlock() + result, ok := c.results[key] + return result, ok +} + +func limitRecords(records []v1alpha1.StatusCheckRecord, limit uint) []v1alpha1.StatusCheckRecord { + length := len(records) + if length < int(limit) { + return records + } + return records[length-int(limit):] +} + +func newExecutor(logger logr.Logger, statusCheck v1alpha1.StatusCheck) (Executor, error) { + var executor Executor + switch statusCheck.Spec.Type { + case v1alpha1.TypeHTTP: + if statusCheck.Spec.EmbedStatusCheck == nil || statusCheck.Spec.HTTPStatusCheck == nil { + // this should not happen, if the webhook works as expected + return nil, errors.New("illegal status check, http should not be empty") + } + executor = http.NewExecutor( + logger.WithName("http-executor").WithValues("url", statusCheck.Spec.HTTPStatusCheck.RequestUrl), + statusCheck.Spec.TimeoutSeconds, *statusCheck.Spec.HTTPStatusCheck) + default: + return nil, errors.Errorf("unsupported type '%s'", statusCheck.Spec.Type) + } + return executor, nil +} diff --git a/controllers/statuscheck/manager_test.go b/controllers/statuscheck/manager_test.go new file mode 100644 index 0000000000..a5846ea906 --- /dev/null +++ b/controllers/statuscheck/manager_test.go @@ -0,0 +1,249 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package statuscheck + +import ( + "reflect" + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +var ( + key = types.NamespacedName{ + Namespace: "default", + Name: "result-cache-test", + } + record1 = v1alpha1.StatusCheckRecord{ + StartTime: &metav1.Time{Time: time.Now()}, + Outcome: v1alpha1.StatusCheckOutcomeFailure, + } + record2 = v1alpha1.StatusCheckRecord{ + StartTime: &metav1.Time{Time: time.Now().Add(5 * time.Second)}, + Outcome: v1alpha1.StatusCheckOutcomeSuccess, + } +) + +func Test_limitRecords(t *testing.T) { + type args struct { + records []v1alpha1.StatusCheckRecord + limit uint + } + tests := []struct { + name string + args args + want []v1alpha1.StatusCheckRecord + }{ + { + name: "not exceeded", + args: args{ + records: []v1alpha1.StatusCheckRecord{record1}, + limit: 2, + }, + want: []v1alpha1.StatusCheckRecord{record1}, + }, + { + name: "exceeded", + args: args{ + records: []v1alpha1.StatusCheckRecord{record1, record2}, + limit: 1, + }, + want: []v1alpha1.StatusCheckRecord{record2}, + }, + { + name: "empty", + args: args{ + records: []v1alpha1.StatusCheckRecord{}, + limit: 1, + }, + want: []v1alpha1.StatusCheckRecord{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := limitRecords(tt.args.records, tt.args.limit); !reflect.DeepEqual(got, tt.want) { + t.Errorf("limitRecords() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_resultCache_get(t *testing.T) { + type fields struct { + results map[types.NamespacedName]Result + } + type args struct { + key types.NamespacedName + } + tests := []struct { + name string + fields fields + args args + want Result + want1 bool + }{ + { + name: "found", + fields: fields{ + results: map[types.NamespacedName]Result{ + key: { + Records: []v1alpha1.StatusCheckRecord{record1}, + Count: 1, + recordsHistoryLimit: 1, + }, + }, + }, + args: args{key: key}, + want: Result{ + Records: []v1alpha1.StatusCheckRecord{record1}, + Count: 1, + recordsHistoryLimit: 1, + }, + want1: true, + }, + { + name: "not found", + fields: fields{ + results: map[types.NamespacedName]Result{ + key: { + Records: []v1alpha1.StatusCheckRecord{record1}, + Count: 1, + recordsHistoryLimit: 1, + }, + }, + }, + args: args{key: types.NamespacedName{ + Namespace: "default", + Name: "cache-test", + }}, + want: Result{}, + want1: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &resultCache{ + results: tt.fields.results, + } + got, got1 := c.get(tt.args.key) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("get() got = %v, want %v", got, tt.want) + } + if got1 != tt.want1 { + t.Errorf("get() got1 = %v, want %v", got1, tt.want1) + } + }) + } +} + +func Test_resultCache_append(t *testing.T) { + type fields struct { + results map[types.NamespacedName]Result + } + type args struct { + key types.NamespacedName + obj v1alpha1.StatusCheckRecord + } + tests := []struct { + name string + fields fields + args args + want Result + want1 bool + }{ + { + name: "append", + fields: fields{ + results: map[types.NamespacedName]Result{ + key: { + Records: []v1alpha1.StatusCheckRecord{record1}, + Count: 1, + recordsHistoryLimit: 2, + }, + }, + }, + args: args{ + key: key, + obj: record2, + }, + want: Result{ + Records: []v1alpha1.StatusCheckRecord{record1, record2}, + Count: 2, + recordsHistoryLimit: 2, + }, + want1: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &resultCache{ + results: tt.fields.results, + } + c.append(tt.args.key, tt.args.obj) + got, got1 := c.get(tt.args.key) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("append() got = %v, want %v", got, tt.want) + } + if got1 != tt.want1 { + t.Errorf("append() got1 = %v, want %v", got1, tt.want1) + } + }) + } +} + +func Test_resultCache_delete(t *testing.T) { + type fields struct { + results map[types.NamespacedName]Result + } + type args struct { + key types.NamespacedName + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "delete", + fields: fields{ + results: map[types.NamespacedName]Result{ + key: { + Records: []v1alpha1.StatusCheckRecord{record1}, + Count: 1, + recordsHistoryLimit: 1, + }, + }, + }, + args: args{key: key}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &resultCache{ + results: tt.fields.results, + } + c.delete(tt.args.key) + _, ok := c.get(tt.args.key) + if ok { + t.Errorf("object exists after delete it") + } + }) + } +} diff --git a/controllers/statuscheck/suite_test.go b/controllers/statuscheck/suite_test.go new file mode 100644 index 0000000000..26e92e30e4 --- /dev/null +++ b/controllers/statuscheck/suite_test.go @@ -0,0 +1,140 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package statuscheck + +import ( + "context" + "os" + "path/filepath" + "reflect" + "testing" + "time" + + "github.com/go-logr/logr" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "go.uber.org/fx" + "k8s.io/client-go/rest" + "k8s.io/kubectl/pkg/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/event" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/builder" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/test" + "github.com/chaos-mesh/chaos-mesh/pkg/log" +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var app *fx.App +var k8sClient client.Client +var cfg *rest.Config +var testEnv *envtest.Environment +var setupLog = ctrl.Log.WithName("setup") + +func TestStatusCheck(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Status Check Suite") +} + +var _ = BeforeSuite(func(ctx SpecContext) { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + By("bootstrapping test environment") + t := true + if os.Getenv("USE_EXISTING_CLUSTER") == "true" { + testEnv = &envtest.Environment{ + UseExistingCluster: &t, + } + } else { + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, + } + } + + err := v1alpha1.SchemeBuilder.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + cfg, err = testEnv.Start() + Expect(err).ToNot(HaveOccurred()) + Expect(cfg).ToNot(BeNil()) + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + Expect(err).ToNot(HaveOccurred()) + Expect(k8sClient).ToNot(BeNil()) + + rootLogger, err := log.NewDefaultZapLogger() + Expect(err).ToNot(HaveOccurred()) + By("start application") + app = fx.New( + fx.Options( + fx.Supply(rootLogger), + test.Module, + fx.Supply(cfg), + ), + fx.Invoke(testBootstrap), + ) + startCtx, cancel := context.WithTimeout(context.Background(), app.StartTimeout()) + defer cancel() + + if err := app.Start(startCtx); err != nil { + setupLog.Error(err, "fail to start manager") + } + Expect(err).ToNot(HaveOccurred()) + +}, NodeTimeout(60*time.Second)) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + stopCtx, cancel := context.WithTimeout(context.Background(), app.StopTimeout()) + defer cancel() + + if err := app.Stop(stopCtx); err != nil { + setupLog.Error(err, "fail to stop manager") + } + err := testEnv.Stop() + Expect(err).ToNot(HaveOccurred()) +}) + +func testBootstrap(mgr ctrl.Manager, client client.Client, logger logr.Logger, recorderBuilder *recorder.RecorderBuilder) error { + if !config.ShouldSpawnController("statuscheck") { + return nil + } + eventRecorder := recorderBuilder.Build("statuscheck") + manager := NewManager(logger.WithName("statuscheck-manager"), eventRecorder, newFakeExecutor) + + return builder.Default(mgr). + For(&v1alpha1.StatusCheck{}). + Named("statuscheck"). + WithEventFilter(predicate.Funcs{ + UpdateFunc: func(e event.UpdateEvent) bool { + oldObj := e.ObjectOld.(*v1alpha1.StatusCheck) + newObj := e.ObjectNew.(*v1alpha1.StatusCheck) + + return !reflect.DeepEqual(oldObj.Spec, newObj.Spec) + }, + }). + Complete(NewReconciler(logger.WithName("statuscheck-reconciler"), client, eventRecorder, manager)) +} diff --git a/controllers/statuscheck/worker.go b/controllers/statuscheck/worker.go new file mode 100644 index 0000000000..2de7436dbb --- /dev/null +++ b/controllers/statuscheck/worker.go @@ -0,0 +1,160 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package statuscheck + +import ( + "sync" + "time" + + "github.com/go-logr/logr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" +) + +type Executor interface { + // Do will execute according to the status check configuration, + // returns: + // 1. the result status (true for success, false for failure). + // 2. output of execution. + // 3. errors if any, it will lead to throw away the result of the execution. + Do() (bool, string, error) + // Type provides the type of executor + Type() string +} + +type worker struct { + logger logr.Logger + eventRecorder recorder.ChaosRecorder + + // stopCh is a channel for stopping the worker. + stopCh chan struct{} + once sync.Once + + manager *manager + // Describes the status check configuration (read-only) + statusCheck v1alpha1.StatusCheck + executor Executor + + lastResult bool + sameResultCount int +} + +func newWorker(logger logr.Logger, eventRecorder recorder.ChaosRecorder, + manager *manager, statusCheck v1alpha1.StatusCheck, executor Executor) *worker { + return &worker{ + logger: logger, + eventRecorder: eventRecorder, + manager: manager, + statusCheck: statusCheck, + executor: executor, + stopCh: make(chan struct{}, 1), // non-blocking + } +} + +// run periodically execute the status check. +func (w *worker) run() { + w.logger.V(1).Info("worker start") + interval := time.Duration(w.statusCheck.Spec.IntervalSeconds) * time.Second + ticker := time.NewTicker(interval) + defer func() { + w.logger.V(1).Info("worker stop") + ticker.Stop() + key := types.NamespacedName{Namespace: w.statusCheck.Namespace, Name: w.statusCheck.Name} + // delete worker from manager cache + w.manager.workers.delete(key) + }() + + for { + select { + case <-ticker.C: + if !w.execute() { + return + } + case <-w.stopCh: + return + } + } +} + +// stop stops the worker, it is safe to call stop multiple times. +func (w *worker) stop() { + w.once.Do(func() { + close(w.stopCh) + }) +} + +// execute the status check once and records the result. +// Returns whether the worker should continue. +func (w *worker) execute() bool { + startTime := time.Now() + result, output, err := w.executor.Do() + if err != nil { + // executor error, throw away the result. + w.logger.Error(err, "executor internal error") + return true + } + + if w.lastResult == result { + w.sameResultCount++ + } else { + w.lastResult = result + w.sameResultCount = 1 + } + + key := types.NamespacedName{Namespace: w.statusCheck.Namespace, Name: w.statusCheck.Name} + if result { + w.logger.V(1).Info("status check execution succeed", "msg", output) + w.eventRecorder.Event(&w.statusCheck, recorder.StatusCheckExecutionSucceed{ExecutorType: w.executor.Type()}) + w.manager.results.append(key, v1alpha1.StatusCheckRecord{ + StartTime: &metav1.Time{Time: startTime}, + Outcome: v1alpha1.StatusCheckOutcomeSuccess, + }) + + // check if the success threshold is exceeded + // Notice: the function `setSuccessThresholdExceedCondition` in `controllers/statuscheck/conditions.go` + // also checks the success threshold, so if you want to modify the logic here, don't forget to modify that + // function as well. + if w.statusCheck.Spec.Mode == v1alpha1.StatusCheckSynchronous && + w.sameResultCount >= w.statusCheck.Spec.SuccessThreshold { + w.logger.Info("exceed the success threshold") + // if status check mode is Synchronous, and it exceeds the SuccessThreshold, + // then stop the worker + return false + } + } else { + w.logger.Info("status check execution failed", "msg", output) + w.eventRecorder.Event(&w.statusCheck, recorder.StatusCheckExecutionFailed{ExecutorType: w.executor.Type(), Msg: output}) + w.manager.results.append(key, v1alpha1.StatusCheckRecord{ + StartTime: &metav1.Time{Time: startTime}, + Outcome: v1alpha1.StatusCheckOutcomeFailure, + }) + + // check if the failure threshold is exceeded + // Notice: the function `setFailureThresholdExceedCondition` in `controllers/statuscheck/conditions.go` + // also checks the failure threshold, so if you want to modify the logic here, don't forget to modify that + // function as well. + if w.sameResultCount >= w.statusCheck.Spec.FailureThreshold { + w.logger.Info("exceed the failure threshold") + // if it exceeds the FailureThreshold, stop the worker + return false + } + } + + return true +} diff --git a/controllers/stresschaos/types.go b/controllers/stresschaos/types.go deleted file mode 100644 index 43f5390c08..0000000000 --- a/controllers/stresschaos/types.go +++ /dev/null @@ -1,240 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package stresschaos - -import ( - "context" - "errors" - "fmt" - "strings" - "sync" - "time" - - "github.com/go-logr/logr" - "golang.org/x/sync/errgroup" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/tools/cache" - ctrl "sigs.k8s.io/controller-runtime" - kubeclient "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/config" - "github.com/chaos-mesh/chaos-mesh/controllers/recover" - "github.com/chaos-mesh/chaos-mesh/controllers/utils" - pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" - "github.com/chaos-mesh/chaos-mesh/pkg/events" - "github.com/chaos-mesh/chaos-mesh/pkg/finalizer" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" -) - -const stressChaosMsg = "stress out pod" - -// endpoint is stresschaos reconciler -type endpoint struct { - ctx.Context -} - -type recoverer struct { - kubeclient.Client - Log logr.Logger -} - -// Apply applies stress-chaos -func (r *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - stresschaos, ok := chaos.(*v1alpha1.StressChaos) - if !ok { - err := errors.New("chaos is not stresschaos") - r.Log.Error(err, "chaos is not StressChaos", "chaos", chaos) - return err - } - - pods, err := selector.SelectAndFilterPods(ctx, r.Client, r.Reader, &stresschaos.Spec, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) - if err != nil { - r.Log.Error(err, "failed to select and generate pods") - return err - } - - stresschaos.Status.Instances = make(map[string]v1alpha1.StressInstance, len(pods)) - if err = r.applyAllPods(ctx, pods, stresschaos); err != nil { - r.Log.Error(err, "failed to apply chaos on all pods") - return err - } - - stresschaos.Status.Experiment.PodRecords = make([]v1alpha1.PodStatus, 0, len(pods)) - for _, pod := range pods { - ps := v1alpha1.PodStatus{ - Namespace: pod.Namespace, - Name: pod.Name, - HostIP: pod.Status.HostIP, - PodIP: pod.Status.PodIP, - Message: stressChaosMsg, - } - - stresschaos.Status.Experiment.PodRecords = append(stresschaos.Status.Experiment.PodRecords, ps) - } - r.Event(stresschaos, v1.EventTypeNormal, events.ChaosInjected, "") - return nil -} - -// Recover means the reconciler recovers the chaos action -func (r *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - stresschaos, ok := chaos.(*v1alpha1.StressChaos) - if !ok { - err := errors.New("chaos is not StressChaos") - r.Log.Error(err, "chaos is not StressChaos", "chaos", chaos) - return err - } - - rd := recover.Delegate{Client: r.Client, Log: r.Log, RecoverIntf: &recoverer{r.Client, r.Log}} - - finalizers, err := rd.CleanFinalizersAndRecover(ctx, chaos, stresschaos.Finalizers, stresschaos.Annotations) - if err != nil { - return err - } - stresschaos.Finalizers = finalizers - r.Event(stresschaos, v1.EventTypeNormal, events.ChaosRecovered, "") - - return nil -} - -func (r *recoverer) RecoverPod(ctx context.Context, pod *v1.Pod, somechaos v1alpha1.InnerObject) error { - // judged type in `Recover` already so no need to judge again - chaos, _ := somechaos.(*v1alpha1.StressChaos) - r.Log.Info("Try to recover pod", "namespace", pod.Namespace, "name", pod.Name) - daemonClient, err := utils.NewChaosDaemonClient(ctx, r.Client, pod) - if err != nil { - return err - } - defer daemonClient.Close() - if len(pod.Status.ContainerStatuses) == 0 { - return fmt.Errorf("%s/%s can't get the state of container", pod.Namespace, pod.Name) - } - instance, ok := chaos.Status.Instances[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] - if !ok { - r.Log.Info("Pod seems already recovered", "pod", pod.UID) - return nil - } - if _, err = daemonClient.CancelStressors(ctx, &pb.CancelStressRequest{ - Instance: instance.UID, - StartTime: instance.StartTime.UnixNano() / int64(time.Millisecond), - }); err != nil { - return err - } - delete(chaos.Status.Instances, fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)) - return nil -} - -// Object would return the instance of chaos -func (r *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.StressChaos{} -} - -func (r *endpoint) applyAllPods(ctx context.Context, pods []v1.Pod, chaos *v1alpha1.StressChaos) error { - g := errgroup.Group{} - - instancesLock := &sync.RWMutex{} - for index := range pods { - pod := &pods[index] - - key, err := cache.MetaNamespaceKeyFunc(pod) - if err != nil { - return err - } - chaos.Finalizers = finalizer.InsertFinalizer(chaos.Finalizers, key) - - g.Go(func() error { - return r.applyPod(ctx, pod, chaos, instancesLock) - }) - } - return g.Wait() -} - -func (r *endpoint) applyPod(ctx context.Context, pod *v1.Pod, chaos *v1alpha1.StressChaos, instancesLock *sync.RWMutex) error { - r.Log.Info("Try to apply stress chaos", "namespace", - pod.Namespace, "name", pod.Name) - daemonClient, err := utils.NewChaosDaemonClient(ctx, r.Client, pod) - if err != nil { - return err - } - defer daemonClient.Close() - - key := fmt.Sprintf("%s/%s", pod.Namespace, pod.Name) - instancesLock.RLock() - _, ok := chaos.Status.Instances[key] - instancesLock.RUnlock() - if ok { - r.Log.Info("an stress-ng instance is running for this pod") - return nil - } - - if len(pod.Status.ContainerStatuses) == 0 { - return fmt.Errorf("%s %s can't get the state of container", pod.Namespace, pod.Name) - } - target := pod.Status.ContainerStatuses[0].ContainerID - if chaos.Spec.ContainerName != nil && - len(strings.TrimSpace(*chaos.Spec.ContainerName)) != 0 { - target = "" - for _, container := range pod.Status.ContainerStatuses { - if container.Name == *chaos.Spec.ContainerName { - target = container.ContainerID - break - } - } - if len(target) == 0 { - return fmt.Errorf("cannot find container with name %s", *chaos.Spec.ContainerName) - } - } - - stressors := chaos.Spec.StressngStressors - if len(stressors) == 0 { - stressors, err = chaos.Spec.Stressors.Normalize() - if err != nil { - return err - } - } - res, err := daemonClient.ExecStressors(ctx, &pb.ExecStressRequest{ - Scope: pb.ExecStressRequest_CONTAINER, - Target: target, - Stressors: stressors, - EnterNS: true, - }) - if err != nil { - return err - } - - instancesLock.Lock() - chaos.Status.Instances[key] = v1alpha1.StressInstance{ - UID: res.Instance, - StartTime: &metav1.Time{ - Time: time.Unix(res.StartTime/1000, (res.StartTime%1000)*int64(time.Millisecond)), - }, - } - instancesLock.Unlock() - return nil -} - -func init() { - router.Register("stresschaos", &v1alpha1.StressChaos{}, func(obj runtime.Object) bool { - return true - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/test/types.go b/controllers/test/types.go index 3b5b1e594f..c300b2a7e1 100644 --- a/controllers/test/types.go +++ b/controllers/test/types.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package test @@ -20,10 +22,9 @@ import ( "github.com/golang/protobuf/ptypes/empty" "google.golang.org/grpc" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/client" chaosdaemon "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" "github.com/chaos-mesh/chaos-mesh/pkg/mock" - - "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/client" ) // Assert *MockChaosDaemonClient implements chaosdaemon.ChaosDaemonClientInterface. @@ -76,8 +77,12 @@ func (c *MockChaosDaemonClient) ContainerKill(ctx context.Context, in *chaosdaem return nil, mockError("ContainerKill") } -func (c *MockChaosDaemonClient) ApplyIoChaos(ctx context.Context, in *chaosdaemon.ApplyIoChaosRequest, opts ...grpc.CallOption) (*chaosdaemon.ApplyIoChaosResponse, error) { - return nil, mockError("ApplyIoChaos") +func (c *MockChaosDaemonClient) ApplyIOChaos(ctx context.Context, in *chaosdaemon.ApplyIOChaosRequest, opts ...grpc.CallOption) (*chaosdaemon.ApplyIOChaosResponse, error) { + return nil, mockError("ApplyIOChaos") +} + +func (c *MockChaosDaemonClient) ApplyHttpChaos(ctx context.Context, in *chaosdaemon.ApplyHttpChaosRequest, opts ...grpc.CallOption) (*chaosdaemon.ApplyHttpChaosResponse, error) { + return nil, mockError("ApplyHttpChaos") } func (c *MockChaosDaemonClient) SetDNSServer(ctx context.Context, in *chaosdaemon.SetDNSServerRequest, opts ...grpc.CallOption) (*empty.Empty, error) { @@ -91,3 +96,19 @@ func (c *MockChaosDaemonClient) SetTcs(ctx context.Context, in *chaosdaemon.TcsR func (c *MockChaosDaemonClient) Close() error { return mockError("CloseChaosDaemonClient") } + +func (c *MockChaosDaemonClient) InstallJVMRules(ctx context.Context, in *chaosdaemon.InstallJVMRulesRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + return nil, mockError("InstallJVMRules") +} + +func (c *MockChaosDaemonClient) UninstallJVMRules(ctx context.Context, in *chaosdaemon.UninstallJVMRulesRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + return nil, mockError("UninstallJVMRules") +} + +func (c *MockChaosDaemonClient) ApplyBlockChaos(ctx context.Context, req *chaosdaemon.ApplyBlockChaosRequest, opts ...grpc.CallOption) (*chaosdaemon.ApplyBlockChaosResponse, error) { + return nil, mockError("ApplyBlockChaosRequest") +} + +func (c *MockChaosDaemonClient) RecoverBlockChaos(ctx context.Context, req *chaosdaemon.RecoverBlockChaosRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + return &empty.Empty{}, nil +} diff --git a/controllers/timechaos/timechaos_suite_test.go b/controllers/timechaos/timechaos_suite_test.go deleted file mode 100644 index 80278fac42..0000000000 --- a/controllers/timechaos/timechaos_suite_test.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package timechaos - -import ( - "context" - "errors" - "testing" - - "k8s.io/client-go/kubernetes/scheme" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/tools/record" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - . "github.com/chaos-mesh/chaos-mesh/controllers/test" - "github.com/chaos-mesh/chaos-mesh/pkg/mock" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" -) - -func TestTimechaos(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "TimeChaos Suite", - []Reporter{envtest.NewlineReporter{}}) -} - -var _ = BeforeSuite(func(done Done) { - logf.SetLogger(zap.LoggerTo(GinkgoWriter, true)) - - Expect(v1.AddToScheme(scheme.Scheme)).To(Succeed()) - - close(done) -}, 60) - -var _ = AfterSuite(func() { -}) - -var _ = Describe("TimeChaos", func() { - Context("TimeChaos", func() { - podObjects, pods := GenerateNPods("p", 1, PodArg{}) - - duration := "invalid_duration" - - timechaos := v1alpha1.TimeChaos{ - TypeMeta: metav1.TypeMeta{ - Kind: "TimeChaos", - APIVersion: "v1", - }, - Spec: v1alpha1.TimeChaosSpec{ - Mode: v1alpha1.AllPodMode, - Value: "0", - Selector: v1alpha1.SelectorSpec{Namespaces: []string{metav1.NamespaceDefault}}, - TimeOffset: "0s0ns", - Duration: &duration, - Scheduler: nil, - }, - } - - r := endpoint{ - Context: ctx.Context{ - Client: fake.NewFakeClientWithScheme(scheme.Scheme, podObjects...), - EventRecorder: &record.FakeRecorder{}, - Log: ctrl.Log.WithName("controllers").WithName("TimeChaos"), - }, - } - - It("TimeChaos Apply", func() { - defer mock.With("MockSelectAndFilterPods", func() []v1.Pod { - return pods - })() - defer mock.With("MockChaosDaemonClient", &MockChaosDaemonClient{})() - - err := r.Apply(context.TODO(), ctrl.Request{}, &timechaos) - - Expect(err).ToNot(HaveOccurred()) - }) - - It("TimeChaos Apply Error", func() { - defer mock.With("MockSelectAndFilterPods", func() []v1.Pod { - return pods - })() - defer mock.With("MockChaosDaemonClient", &MockChaosDaemonClient{})() - defer mock.With("MockSetTimeOffsetError", errors.New("SetTimeOffsetError"))() - - err := r.Apply(context.TODO(), ctrl.Request{}, &timechaos) - - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("SetTimeOffsetError")) - - }) - - It("TimeChaos Recover", func() { - defer mock.With("MockSelectAndFilterPods", func() []v1.Pod { - return pods - })() - defer mock.With("MockChaosDaemonClient", &MockChaosDaemonClient{})() - - err := r.Recover(context.TODO(), ctrl.Request{}, &timechaos) - Expect(err).ToNot(HaveOccurred()) - }) - - It("TimeChaos Recover Error", func() { - defer mock.With("MockSelectAndFilterPods", func() []v1.Pod { - return pods - })() - defer mock.With("MockChaosDaemonClient", &MockChaosDaemonClient{})() - defer mock.With("MockRecoverTimeOffsetError", errors.New("RecoverTimeOffsetError"))() - - err := r.Apply(context.TODO(), ctrl.Request{}, &timechaos) - Expect(err).ToNot(HaveOccurred()) - - err = r.Recover(context.TODO(), ctrl.Request{}, &timechaos) - - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("RecoverTimeOffsetError")) - }) - }) -}) diff --git a/controllers/timechaos/types.go b/controllers/timechaos/types.go deleted file mode 100644 index 2d9e99719b..0000000000 --- a/controllers/timechaos/types.go +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package timechaos - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/go-logr/logr" - "golang.org/x/sync/errgroup" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/tools/cache" - ctrl "sigs.k8s.io/controller-runtime" - kubeclient "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/config" - "github.com/chaos-mesh/chaos-mesh/controllers/recover" - "github.com/chaos-mesh/chaos-mesh/controllers/utils" - chaosdaemon "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" - "github.com/chaos-mesh/chaos-mesh/pkg/events" - "github.com/chaos-mesh/chaos-mesh/pkg/finalizer" - "github.com/chaos-mesh/chaos-mesh/pkg/router" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" - timeUtils "github.com/chaos-mesh/chaos-mesh/pkg/time/utils" -) - -const timeChaosMsg = "time is shifted with %v" - -// endpoint is time-chaos reconciler -type endpoint struct { - ctx.Context -} - -type recoverer struct { - kubeclient.Client - Log logr.Logger -} - -// Apply applies time-chaos -func (r *endpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - timechaos, ok := chaos.(*v1alpha1.TimeChaos) - if !ok { - err := errors.New("chaos is not timechaos") - r.Log.Error(err, "chaos is not TimeChaos", "chaos", chaos) - return err - } - - timechaos.SetDefaultValue() - - pods, err := selector.SelectAndFilterPods(ctx, r.Client, r.Reader, &timechaos.Spec, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) - - if err != nil { - r.Log.Error(err, "failed to select and filter pods") - return err - } - - if err = r.applyAllPods(ctx, pods, timechaos); err != nil { - r.Log.Error(err, "failed to apply chaos on all pods") - return err - } - - timechaos.Status.Experiment.PodRecords = make([]v1alpha1.PodStatus, 0, len(pods)) - for _, pod := range pods { - ps := v1alpha1.PodStatus{ - Namespace: pod.Namespace, - Name: pod.Name, - HostIP: pod.Status.HostIP, - PodIP: pod.Status.PodIP, - Message: fmt.Sprintf(timeChaosMsg, timechaos.Spec.TimeOffset), - } - - timechaos.Status.Experiment.PodRecords = append(timechaos.Status.Experiment.PodRecords, ps) - } - r.Event(timechaos, v1.EventTypeNormal, events.ChaosInjected, "") - return nil -} - -// Recover means the reconciler recovers the chaos action -func (r *endpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - timechaos, ok := chaos.(*v1alpha1.TimeChaos) - if !ok { - err := errors.New("chaos is not TimeChaos") - r.Log.Error(err, "chaos is not TimeChaos", "chaos", chaos) - return err - } - - rd := recover.Delegate{Client: r.Client, Log: r.Log, RecoverIntf: &recoverer{r.Client, r.Log}} - - finalizers, err := rd.CleanFinalizersAndRecover(ctx, chaos, timechaos.Finalizers, timechaos.Annotations) - if err != nil { - return err - } - timechaos.Finalizers = finalizers - r.Event(timechaos, v1.EventTypeNormal, events.ChaosRecovered, "") - - return nil -} - -func (r *recoverer) RecoverPod(ctx context.Context, pod *v1.Pod, somechaos v1alpha1.InnerObject) error { - // judged type in `Recover` already so no need to judge again - chaos, _ := somechaos.(*v1alpha1.TimeChaos) - r.Log.Info("Try to recover pod", "namespace", pod.Namespace, "name", pod.Name) - - pbClient, err := utils.NewChaosDaemonClient(ctx, r.Client, pod) - if err != nil { - return err - } - defer pbClient.Close() - - if len(pod.Status.ContainerStatuses) == 0 { - return fmt.Errorf("%s %s can't get the state of container", pod.Namespace, pod.Name) - } - - g := errgroup.Group{} - expectedNames := make(map[string]bool) - for _, name := range chaos.Spec.ContainerNames { - expectedNames[name] = true - } - for index := range pod.Status.ContainerStatuses { - container := pod.Status.ContainerStatuses[index] - - if len(expectedNames) == 0 || expectedNames[container.Name] { - g.Go(func() error { - err := r.recoverContainer(ctx, pbClient, container.ContainerID) - - if err != nil { - r.Log.Error(err, "recover pod error", "namespace", pod.Namespace, "name", pod.Name) - } else { - r.Log.Info("Recover pod finished", "namespace", pod.Namespace, "name", pod.Name) - } - - return err - }) - } - } - - return g.Wait() -} - -func (r *recoverer) recoverContainer(ctx context.Context, client chaosdaemon.ChaosDaemonClient, containerID string) error { - r.Log.Info("Try to recover time on container", "id", containerID) - - _, err := client.RecoverTimeOffset(ctx, &chaosdaemon.TimeRequest{ - ContainerId: containerID, - }) - - return err -} - -// Object would return the instance of chaos -func (r *endpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.TimeChaos{} -} - -func (r *endpoint) applyAllPods(ctx context.Context, pods []v1.Pod, chaos *v1alpha1.TimeChaos) error { - g := errgroup.Group{} - for index := range pods { - pod := &pods[index] - - key, err := cache.MetaNamespaceKeyFunc(pod) - if err != nil { - return err - } - chaos.Finalizers = finalizer.InsertFinalizer(chaos.Finalizers, key) - - g.Go(func() error { - return r.applyPod(ctx, pod, chaos) - }) - } - - return g.Wait() -} - -func (r *endpoint) applyPod(ctx context.Context, pod *v1.Pod, chaos *v1alpha1.TimeChaos) error { - r.Log.Info("Try to shift time on pod", "namespace", pod.Namespace, "name", pod.Name) - - pbClient, err := utils.NewChaosDaemonClient(ctx, r.Client, pod) - if err != nil { - return err - } - defer pbClient.Close() - - if len(pod.Status.ContainerStatuses) == 0 { - return fmt.Errorf("%s %s can't get the state of container", pod.Namespace, pod.Name) - } - - g := errgroup.Group{} - expectedNames := make(map[string]bool) - for _, name := range chaos.Spec.ContainerNames { - expectedNames[name] = true - } - for index := range pod.Status.ContainerStatuses { - container := pod.Status.ContainerStatuses[index] - - if len(expectedNames) == 0 || expectedNames[container.Name] { - g.Go(func() error { - return r.applyContainer(ctx, pbClient, container.ContainerID, chaos) - }) - } - } - - return g.Wait() -} - -func (r *endpoint) applyContainer(ctx context.Context, client chaosdaemon.ChaosDaemonClient, containerID string, chaos *v1alpha1.TimeChaos) error { - r.Log.Info("Try to shift time on container", "id", containerID) - - mask, err := timeUtils.EncodeClkIds(chaos.Spec.ClockIds) - if err != nil { - return err - } - - duration, err := time.ParseDuration(chaos.Spec.TimeOffset) - if err != nil { - return err - } - - sec, nsec := secAndNSecFromDuration(duration) - - r.Log.Info("setting time shift", "mask", mask, "sec", sec, "nsec", nsec) - _, err = client.SetTimeOffset(ctx, &chaosdaemon.TimeRequest{ - ContainerId: containerID, - Sec: sec, - Nsec: nsec, - ClkIdsMask: mask, - }) - - return err -} - -func secAndNSecFromDuration(duration time.Duration) (sec int64, nsec int64) { - sec = duration.Nanoseconds() / 1e9 - nsec = duration.Nanoseconds() - (sec * 1e9) - - return -} - -func init() { - router.Register("timechaos", &v1alpha1.TimeChaos{}, func(obj runtime.Object) bool { - return true - }, func(ctx ctx.Context) end.Endpoint { - return &endpoint{ - Context: ctx, - } - }) -} diff --git a/controllers/timechaos/util_test.go b/controllers/timechaos/util_test.go deleted file mode 100644 index 0d1e162a0f..0000000000 --- a/controllers/timechaos/util_test.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package timechaos - -import ( - "testing" - "time" - - . "github.com/onsi/gomega" -) - -type SecAndNSecFromDurationTestCase struct { - Duration time.Duration - Sec int64 - NSec int64 -} - -func TestSecAndNSecFromDuration(t *testing.T) { - g := NewGomegaWithT(t) - cases := []SecAndNSecFromDurationTestCase{ - {time.Second * 100, 100, 0}, - {time.Second * -100, -100, 0}, - {time.Second*-100 + time.Microsecond*-20, -100, -20000}, - {time.Second*-100 + time.Microsecond*20, -99, -999980000}, - {time.Second*100 + time.Microsecond*20, 100, 20000}, - {time.Second*100 + time.Microsecond*-20, 99, 999980000}, - } - - for _, c := range cases { - sec, nsec := secAndNSecFromDuration(c.Duration) - g.Expect(sec).Should(Equal(c.Sec)) - g.Expect(nsec).Should(Equal(c.NSec)) - } -} diff --git a/controllers/twophase/state_machine.go b/controllers/twophase/state_machine.go deleted file mode 100644 index e088a9cc87..0000000000 --- a/controllers/twophase/state_machine.go +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package twophase - -import ( - "context" - "strings" - "time" - - "github.com/pkg/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/util/retry" - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -const iterMax = 1e4 - -type chaosStateMachine struct { - Chaos v1alpha1.InnerSchedulerObject - Req ctrl.Request - *Reconciler -} - -func unexpected(ctx context.Context, m *chaosStateMachine, targetPhase v1alpha1.ExperimentPhase, now time.Time) (bool, error) { - currentPhase := m.Chaos.GetStatus().Experiment.Phase - - return true, errors.Errorf("turn from %s into %s is unexpected", currentPhase, targetPhase) -} - -func noop(ctx context.Context, m *chaosStateMachine, targetPhase v1alpha1.ExperimentPhase, now time.Time) (bool, error) { - updated := false - currentPhase := m.Chaos.GetStatus().Experiment.Phase - - if currentPhase != targetPhase { - m.Chaos.GetStatus().Experiment.Phase = targetPhase - updated = true - } - return updated, nil -} - -func apply(ctx context.Context, m *chaosStateMachine, targetPhase v1alpha1.ExperimentPhase, startTime time.Time) (bool, error) { - duration, err := m.Chaos.GetDuration() - if err != nil { - m.Log.Error(err, "failed to get chaos duration") - return false, err - } - if duration == nil { - zero := time.Duration(0) - duration = &zero - } - - currentPhase := m.Chaos.GetStatus().Experiment.Phase - status := m.Chaos.GetStatus() - - m.Log.Info("applying", "current phase", currentPhase, "target phase", targetPhase) - err = m.Apply(ctx, m.Req, m.Chaos) - if err != nil { - m.Log.Error(err, "fail to apply") - - status.Experiment.Phase = v1alpha1.ExperimentPhaseFailed - status.FailedMessage = err.Error() - - return true, err - } - // reset failed message - status.FailedMessage = emptyString - status.Experiment.Phase = targetPhase - - nextStart, nextRecover, err := m.IterateNextTime(startTime, *duration) - if err != nil { - m.Log.Error(err, "failed to get the next start time and recover time") - return true, err - } - - m.Chaos.SetNextStart(*nextStart) - m.Chaos.SetNextRecover(*nextRecover) - - status.Experiment.StartTime = &metav1.Time{Time: startTime} - status.Experiment.EndTime = nil - status.Experiment.Duration = duration.String() - - return true, nil -} - -func recover(ctx context.Context, m *chaosStateMachine, targetPhase v1alpha1.ExperimentPhase, now time.Time) (bool, error) { - duration, err := m.Chaos.GetDuration() - if err != nil { - m.Log.Error(err, "failed to get chaos duration") - return false, err - } - if duration == nil { - zero := time.Duration(0) - duration = &zero - } - - currentPhase := m.Chaos.GetStatus().Experiment.Phase - status := m.Chaos.GetStatus() - - m.Log.Info("recovering", "current phase", currentPhase, "target phase", targetPhase) - if err := m.Recover(ctx, m.Req, m.Chaos); err != nil { - status.FailedMessage = err.Error() - - m.Log.Error(err, "fail to recover") - return true, err - } - - status.Experiment.Phase = targetPhase - status.Experiment.EndTime = &metav1.Time{ - Time: now, - } - - if status.Experiment.StartTime != nil { - status.Experiment.Duration = now.Sub(status.Experiment.StartTime.Time).String() - } - - // If this recover action is not called by pause action, reset recover time - if !now.Before(m.Chaos.GetNextRecover()) { - m.Chaos.SetNextRecover(m.Chaos.GetNextStart().Add(*duration)) - } - - return true, nil -} - -func resume(ctx context.Context, m *chaosStateMachine, _ v1alpha1.ExperimentPhase, now time.Time) (bool, error) { - startTime := now - duration, err := m.Chaos.GetDuration() - if err != nil { - m.Log.Error(err, "failed to get chaos duration") - return false, err - } - if duration == nil { - zero := time.Duration(0) - duration = &zero - } - status := m.Chaos.GetStatus() - - nextStart := m.Chaos.GetNextStart() - nextRecover := m.Chaos.GetNextRecover() - var lastStart time.Time - if status.Experiment.StartTime == nil { - // in this condition, the experiment has never executed - nextStart = now - lastStart = now - } else { - lastStart = status.Experiment.StartTime.Time - } - - defer func() { - m.Chaos.SetNextStart(nextStart) - m.Chaos.SetNextRecover(nextRecover) - }() - - counter := 0 - for { - if nextRecover.After(now) && nextRecover.Before(nextStart) { - startTime = lastStart - - return apply(ctx, m, v1alpha1.ExperimentPhaseRunning, startTime) - } - - if nextStart.After(now) { - return noop(ctx, m, v1alpha1.ExperimentPhaseWaiting, now) - } - - lastStart = nextStart - start, recover, err := m.IterateNextTime(nextStart, *duration) - if err != nil { - m.Log.Error(err, "failed to get the next start time and recover time") - - return false, err - } - - nextStart = *start - nextRecover = *recover - - counter++ - if counter > iterMax { - // If counter > iterMax, it means that chaos has been suspended for a long time, - // then directly restart chaos and set startTime to now. - startTime = now - start, recover, err = m.IterateNextTime(startTime, *duration) - if err != nil { - m.Log.Error(err, "failed to get the next start time and recover time") - return false, err - } - nextStart = *start - nextRecover = *recover - - return apply(ctx, m, v1alpha1.ExperimentPhaseRunning, startTime) - } - } -} - -// This method changes the phase of an object and do some side effects -// There are 6 different phases, so there could be 6 * 6 = 36 branches -func (m *chaosStateMachine) run(ctx context.Context, targetPhase v1alpha1.ExperimentPhase, now time.Time) (bool, error) { - currentPhase := m.Chaos.GetStatus().Experiment.Phase - m.Log.Info("change phase", "current phase", currentPhase, "target phase", targetPhase) - - if phaseTransitionMap[currentPhase] == nil { - err := errors.Errorf("unexpected current phase '%s'", currentPhase) - return false, err - } - - if phaseTransitionMap[currentPhase][targetPhase] == nil { - err := errors.Errorf("unexpected target phase '%s'", targetPhase) - return false, err - } - - return phaseTransitionMap[currentPhase][targetPhase](ctx, m, targetPhase, now) -} - -func (m *chaosStateMachine) Into(ctx context.Context, targetPhase v1alpha1.ExperimentPhase, now time.Time) error { - updated, err := m.run(ctx, targetPhase, now) - if err != nil { - m.Log.Error(err, "error while executing state machine") - } - - if updated { - - updateError := m.Update(ctx, m.Chaos) - if updateError == nil { - return err - } - - if !strings.Contains(updateError.Error(), "the object has been modified; please apply your changes to the latest version and try again") { - return updateError - } - - m.Log.Error(updateError, "fail to update, and will retry on conflict") - - // avoid panic - if m.Chaos.GetChaos() == nil || m.Chaos.GetStatus() == nil { - return updateError - } - - namespacedName := types.NamespacedName{ - Namespace: m.Chaos.GetChaos().Namespace, - Name: m.Chaos.GetChaos().Name, - } - - updateError = retry.RetryOnConflict(retry.DefaultBackoff, func() error { - // Fetch the resource - _chaos := m.Object() - if err := m.Client.Get(ctx, namespacedName, _chaos); err != nil { - m.Log.Error(err, "unable to get chaos") - return err - } - chaos := _chaos.(v1alpha1.InnerSchedulerObject) - - // Make updates to the resource - status := chaos.GetStatus() - status.FailedMessage = m.Chaos.GetStatus().FailedMessage - status.Scheduler = m.Chaos.GetStatus().Scheduler - status.Experiment = m.Chaos.GetStatus().Experiment - - // Try to update - return m.Update(ctx, chaos) - }) - - if updateError != nil { - return updateError - } - } - - return err -} - -func (m *chaosStateMachine) IterateNextTime(startTime time.Time, duration time.Duration) (*time.Time, *time.Time, error) { - scheduler := m.Chaos.GetScheduler() - if scheduler == nil { - return nil, nil, errors.Errorf("misdefined scheduler") - } - m.Log.Info("iterate nextStart and nextRecover", "startTime", startTime, "duration", duration, "scheduler", scheduler) - nextStart, err := nextTime(*scheduler, startTime) - - if err != nil { - m.Log.Error(err, "failed to get the next start time") - return nil, nil, err - } - nextRecover := startTime.Add(duration) - - counter := 0 - // if the duration is too long, `nextRecover` could be after `nextStart` - // we can jump over a start to make sure `nextRecover` is before `nextStart` - for nextRecover.After(*nextStart) { - nextStart, err = nextTime(*scheduler, *nextStart) - if err != nil { - m.Log.Error(err, "failed to get the next start time") - return nil, nil, err - } - - counter++ - if counter > iterMax { - err = errors.Errorf("the number of iterations exceeded with nextRecover(%s) nextStart(%s)", nextRecover, nextStart) - return nil, nil, err - } - } - - return nextStart, &nextRecover, nil -} - -var phaseTransitionMap = map[v1alpha1.ExperimentPhase]map[v1alpha1.ExperimentPhase]func(ctx context.Context, m *chaosStateMachine, targetPhase v1alpha1.ExperimentPhase, now time.Time) (bool, error){ - v1alpha1.ExperimentPhaseUninitialized: { - v1alpha1.ExperimentPhaseUninitialized: noop, - v1alpha1.ExperimentPhaseRunning: apply, - v1alpha1.ExperimentPhaseWaiting: noop, - v1alpha1.ExperimentPhasePaused: noop, - v1alpha1.ExperimentPhaseFailed: unexpected, - v1alpha1.ExperimentPhaseFinished: noop, - }, - v1alpha1.ExperimentPhaseRunning: { - v1alpha1.ExperimentPhaseUninitialized: unexpected, - v1alpha1.ExperimentPhaseRunning: noop, - v1alpha1.ExperimentPhaseWaiting: recover, - v1alpha1.ExperimentPhasePaused: recover, - v1alpha1.ExperimentPhaseFailed: unexpected, - v1alpha1.ExperimentPhaseFinished: recover, - }, - v1alpha1.ExperimentPhaseWaiting: { - v1alpha1.ExperimentPhaseUninitialized: unexpected, - v1alpha1.ExperimentPhaseRunning: apply, - v1alpha1.ExperimentPhaseWaiting: noop, - v1alpha1.ExperimentPhasePaused: noop, - v1alpha1.ExperimentPhaseFailed: unexpected, - v1alpha1.ExperimentPhaseFinished: noop, - }, - v1alpha1.ExperimentPhasePaused: { - v1alpha1.ExperimentPhaseUninitialized: unexpected, - v1alpha1.ExperimentPhaseRunning: resume, - v1alpha1.ExperimentPhaseWaiting: resume, - v1alpha1.ExperimentPhasePaused: noop, - v1alpha1.ExperimentPhaseFailed: unexpected, - v1alpha1.ExperimentPhaseFinished: noop, - }, - v1alpha1.ExperimentPhaseFailed: { - v1alpha1.ExperimentPhaseUninitialized: unexpected, - v1alpha1.ExperimentPhaseRunning: apply, - v1alpha1.ExperimentPhaseWaiting: noop, - v1alpha1.ExperimentPhasePaused: noop, - v1alpha1.ExperimentPhaseFailed: noop, - v1alpha1.ExperimentPhaseFinished: recover, - }, - v1alpha1.ExperimentPhaseFinished: { - v1alpha1.ExperimentPhaseUninitialized: unexpected, - v1alpha1.ExperimentPhaseRunning: unexpected, - v1alpha1.ExperimentPhaseWaiting: unexpected, - v1alpha1.ExperimentPhasePaused: unexpected, - v1alpha1.ExperimentPhaseFailed: unexpected, - v1alpha1.ExperimentPhaseFinished: noop, - }, -} diff --git a/controllers/twophase/state_machine_test.go b/controllers/twophase/state_machine_test.go deleted file mode 100644 index 1de91a92b5..0000000000 --- a/controllers/twophase/state_machine_test.go +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package twophase - -import ( - "context" - "errors" - "testing" - "time" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes/scheme" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/envtest" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/mock" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" -) - -func TestStateMachine(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "Twophase StateMachine Suite", - []Reporter{envtest.NewlineReporter{}}) -} - -var _ = Describe("TwoPhase StateMachine", func() { - Context("TwoPhase", func() { - - statuses := []v1alpha1.ExperimentPhase{ - v1alpha1.ExperimentPhaseFailed, - v1alpha1.ExperimentPhaseFinished, - v1alpha1.ExperimentPhasePaused, - v1alpha1.ExperimentPhaseRunning, - v1alpha1.ExperimentPhaseWaiting, - } - - It("StateMachine Target Finish", func() { - defer mock.With("MockApplyError", errors.New("ApplyError"))() - defer mock.With("MockRecoverError", errors.New("RecoverError"))() - - for _, status := range statuses { - now := time.Now() - sm := setupStateMachineWithStatus(status) - - updated, err := sm.run(context.TODO(), v1alpha1.ExperimentPhaseFinished, now) - - if status == v1alpha1.ExperimentPhaseRunning { - Expect(updated).To(Equal(true)) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("RecoverError")) - Expect(sm.Chaos.GetStatus().Experiment.Phase).To(Equal(v1alpha1.ExperimentPhaseRunning)) - Expect(sm.Chaos.GetStatus().FailedMessage).To(ContainSubstring("RecoverError")) - - return - } else if status == v1alpha1.ExperimentPhaseFinished { - Expect(updated).To(Equal(false)) - } else if status == v1alpha1.ExperimentPhaseFailed { - Expect(updated).To(Equal(true)) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("RecoverError")) - Expect(sm.Chaos.GetStatus().FailedMessage).To(ContainSubstring("RecoverError")) - - return - } else { - Expect(updated).To(Equal(true)) - } - - Expect(err).ToNot(HaveOccurred()) - } - }) - - It("StateMachine Target Paused", func() { - defer mock.With("MockApplyError", errors.New("ApplyError"))() - defer mock.With("MockRecoverError", errors.New("RecoverError"))() - - for _, status := range statuses { - now := time.Now() - sm := setupStateMachineWithStatus(status) - - updated, err := sm.run(context.TODO(), v1alpha1.ExperimentPhasePaused, now) - - if status == v1alpha1.ExperimentPhaseRunning { - Expect(updated).To(Equal(true)) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("RecoverError")) - Expect(sm.Chaos.GetStatus().Experiment.Phase).To(Equal(v1alpha1.ExperimentPhaseRunning)) - Expect(sm.Chaos.GetStatus().FailedMessage).To(ContainSubstring("RecoverError")) - - return - } else if status == v1alpha1.ExperimentPhaseFinished { - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("turn from")) - - return - } else if status != v1alpha1.ExperimentPhasePaused { - Expect(updated).To(Equal(true)) - } else { - Expect(updated).To(Equal(false)) - } - - Expect(err).ToNot(HaveOccurred()) - } - }) - - It("StateMachine Target Running", func() { - defer mock.With("MockApplyError", errors.New("ApplyError"))() - defer mock.With("MockRecoverError", errors.New("RecoverError"))() - - for _, status := range statuses { - now := time.Now() - sm := setupStateMachineWithStatus(status) - - updated, err := sm.run(context.TODO(), v1alpha1.ExperimentPhaseRunning, now) - - if status == v1alpha1.ExperimentPhaseFinished { - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("turn from")) - } else if status == v1alpha1.ExperimentPhaseRunning { - Expect(updated).To(Equal(false)) - Expect(err).ToNot(HaveOccurred()) - } else if status != v1alpha1.ExperimentPhasePaused { - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("ApplyError")) - } - } - }) - - It("Pause", func() { - // duration 15min, scheduler @every 20m - // Then it should be running in 13:10-13:25, 13:30-13:45, 13:50-14:05, 14:10-14:25 - // Pause will only erase part of it - now, err := time.Parse(time.RFC3339, "2020-12-07T13:10:00+00:00") - Expect(err).ToNot(HaveOccurred()) - sm := setupStateMachineWithStatus(v1alpha1.ExperimentPhaseUninitialized) - - updated, err := sm.run(context.TODO(), v1alpha1.ExperimentPhaseRunning, now) - Expect(err).ToNot(HaveOccurred()) - Expect(updated).To(Equal(true)) - Expect(sm.Chaos.GetStatus().Experiment.Phase).To(Equal(v1alpha1.ExperimentPhaseRunning)) - - now = now.Add(time.Minute) // 13:11 - updated, err = sm.run(context.TODO(), v1alpha1.ExperimentPhasePaused, now) - Expect(err).ToNot(HaveOccurred()) - Expect(updated).To(Equal(true)) - Expect(sm.Chaos.GetStatus().Experiment.Phase).To(Equal(v1alpha1.ExperimentPhasePaused)) - - // should apply - now, err = time.Parse(time.RFC3339, "2020-12-07T13:55:00+00:00") - Expect(err).ToNot(HaveOccurred()) - updated, err = sm.run(context.TODO(), v1alpha1.ExperimentPhaseRunning, now) - Expect(err).ToNot(HaveOccurred()) - Expect(updated).To(Equal(true)) - Expect(sm.Chaos.GetStatus().Experiment.Phase).To(Equal(v1alpha1.ExperimentPhaseRunning)) - - now = now.Add(time.Minute) // 13:56 - updated, err = sm.run(context.TODO(), v1alpha1.ExperimentPhasePaused, now) - Expect(err).ToNot(HaveOccurred()) - Expect(updated).To(Equal(true)) - Expect(sm.Chaos.GetStatus().Experiment.Phase).To(Equal(v1alpha1.ExperimentPhasePaused)) - - now, err = time.Parse(time.RFC3339, "2020-12-07T14:06:00+00:00") - Expect(err).ToNot(HaveOccurred()) - updated, err = sm.run(context.TODO(), v1alpha1.ExperimentPhaseRunning, now) - Expect(err).ToNot(HaveOccurred()) - Expect(updated).To(Equal(true)) - Expect(sm.Chaos.GetStatus().Experiment.Phase).To(Equal(v1alpha1.ExperimentPhaseWaiting)) - - now, err = time.Parse(time.RFC3339, "2020-12-07T14:11:00+00:00") - Expect(err).ToNot(HaveOccurred()) - updated, err = sm.run(context.TODO(), v1alpha1.ExperimentPhaseRunning, now) - Expect(err).ToNot(HaveOccurred()) - Expect(updated).To(Equal(true)) - Expect(sm.Chaos.GetStatus().Experiment.Phase).To(Equal(v1alpha1.ExperimentPhaseRunning)) - }) - - It("StateMachine Unexpected State", func() { - var unexpectedState v1alpha1.ExperimentPhase = "wrong-state" - now := time.Now() - - for _, status := range statuses { - sm := setupStateMachineWithStatus(status) - updated, err := sm.run(context.TODO(), unexpectedState, now) - Expect(updated).To(Equal(false)) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("unexpected target phase")) - } - - sm := setupStateMachineWithStatus(unexpectedState) - for _, status := range statuses { - updated, err := sm.run(context.TODO(), status, now) - Expect(updated).To(Equal(false)) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("unexpected current phase")) - } - }) - }) - -}) - -func setupStateMachineWithStatus(status v1alpha1.ExperimentPhase) *chaosStateMachine { - req := ctrl.Request{ - NamespacedName: types.NamespacedName{ - Name: "fakechaos-name", - Namespace: metav1.NamespaceDefault, - }, - } - typeMeta := metav1.TypeMeta{ - Kind: "PodChaos", - APIVersion: "v1", - } - objectMeta := metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "fakechaos-name", - } - - chaos := fakeTwoPhaseChaos{ - TypeMeta: typeMeta, - ObjectMeta: objectMeta, - } - - chaos.Status.Experiment.Phase = status - duration := "15m" - chaos.Duration = &duration - chaos.Scheduler = &v1alpha1.SchedulerSpec{ - Cron: "@every 20m", - } - - c := fake.NewFakeClientWithScheme(scheme.Scheme, &chaos) - - r := Reconciler{ - Endpoint: fakeEndpoint{}, - Context: ctx.Context{ - Client: c, - Log: ctrl.Log.WithName("controllers").WithName("TwoPhase"), - }, - } - - sm := chaosStateMachine{ - Chaos: &chaos, - Req: req, - Reconciler: &r, - } - - return &sm -} diff --git a/controllers/twophase/twophase_suite_test.go b/controllers/twophase/twophase_suite_test.go deleted file mode 100644 index 6ec6c74492..0000000000 --- a/controllers/twophase/twophase_suite_test.go +++ /dev/null @@ -1,517 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package twophase - -import ( - "context" - "errors" - "testing" - "time" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes/scheme" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/mock" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" -) - -func TestTwoPhase(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "TwoPhase Suite", - []Reporter{envtest.NewlineReporter{}}) -} - -var _ = BeforeSuite(func(done Done) { - logf.SetLogger(zap.LoggerTo(GinkgoWriter, true)) - - Expect(addFakeToScheme(scheme.Scheme)).To(Succeed()) - - close(done) -}, 60) - -var _ = AfterSuite(func() { -}) - -var _ end.Endpoint = (*fakeEndpoint)(nil) - -type fakeEndpoint struct{} - -func (r fakeEndpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - if err := mock.On("MockApplyError"); err != nil { - return err.(error) - } - return nil -} - -func (r fakeEndpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - if err := mock.On("MockRecoverError"); err != nil { - return err.(error) - } - return nil -} - -var _ v1alpha1.InnerSchedulerObject = (*fakeTwoPhaseChaos)(nil) - -type fakeTwoPhaseChaos struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - Status v1alpha1.ChaosStatus `json:"status,omitempty"` - - // Selector is used to select pods that are used to inject chaos action. - Selector v1alpha1.SelectorSpec `json:"selector"` - - Deleted bool `json:"deleted"` - - // Duration represents the duration of the chaos action - Duration *string `json:"duration,omitempty"` - - // Scheduler defines some schedule rules to control the running time of the chaos experiment about time. - Scheduler *v1alpha1.SchedulerSpec `json:"scheduler,omitempty"` - - // Next time when this action will be applied again - // +optional - NextStart *metav1.Time `json:"nextStart,omitempty"` - - // Next time when this action will be recovered - // +optional - NextRecover *metav1.Time `json:"nextRecover,omitempty"` -} - -func (in *fakeTwoPhaseChaos) GetStatus() *v1alpha1.ChaosStatus { - return &in.Status -} - -// IsDeleted returns whether this resource has been deleted -func (in *fakeTwoPhaseChaos) IsDeleted() bool { - return in.Deleted -} - -// IsPaused returns whether this resource has been paused -func (in *fakeTwoPhaseChaos) IsPaused() bool { - return false -} - -func (in *fakeTwoPhaseChaos) GetSpecAndMetaString() (string, error) { - return "", nil -} - -func (r fakeEndpoint) Object() v1alpha1.InnerObject { - return &fakeTwoPhaseChaos{} -} - -func (in *fakeTwoPhaseChaos) GetDuration() (*time.Duration, error) { - if in.Duration == nil { - return nil, nil - } - duration, err := time.ParseDuration(*in.Duration) - if err != nil { - return nil, err - } - return &duration, nil -} - -func (in *fakeTwoPhaseChaos) GetNextStart() time.Time { - if in.NextStart == nil { - return time.Time{} - } - return in.NextStart.Time -} - -func (in *fakeTwoPhaseChaos) SetNextStart(t time.Time) { - if t.IsZero() { - in.NextStart = nil - return - } - - if in.NextStart == nil { - in.NextStart = &metav1.Time{} - } - in.NextStart.Time = t -} - -func (in *fakeTwoPhaseChaos) GetNextRecover() time.Time { - if in.NextRecover == nil { - return time.Time{} - } - return in.NextRecover.Time -} - -func (in *fakeTwoPhaseChaos) SetNextRecover(t time.Time) { - if t.IsZero() { - in.NextRecover = nil - return - } - - if in.NextRecover == nil { - in.NextRecover = &metav1.Time{} - } - in.NextRecover.Time = t -} - -func (in *fakeTwoPhaseChaos) GetScheduler() *v1alpha1.SchedulerSpec { - return in.Scheduler -} - -func (in *fakeTwoPhaseChaos) GetChaos() *v1alpha1.ChaosInstance { - return nil -} - -func (in *fakeTwoPhaseChaos) DeepCopyInto(out *fakeTwoPhaseChaos) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - - in.Status.DeepCopyInto(&out.Status) - in.Selector.DeepCopyInto(&out.Selector) - - out.Deleted = in.Deleted - - if in.Duration != nil { - in, out := &in.Duration, &out.Duration - *out = new(string) - **out = **in - } - if in.Scheduler != nil { - in, out := &in.Scheduler, &out.Scheduler - *out = new(v1alpha1.SchedulerSpec) - **out = **in - } - if in.NextRecover != nil { - in, out := &in.NextRecover, &out.NextRecover - *out = new(metav1.Time) - **out = **in - } - if in.NextStart != nil { - in, out := &in.NextStart, &out.NextStart - *out = new(metav1.Time) - **out = **in - } -} - -func (in *fakeTwoPhaseChaos) DeepCopy() *fakeTwoPhaseChaos { - if in == nil { - return nil - } - out := new(fakeTwoPhaseChaos) - in.DeepCopyInto(out) - return out -} - -func (in *fakeTwoPhaseChaos) DeepCopyObject() runtime.Object { - return in.DeepCopy() -} - -var ( - schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) - addFakeToScheme = schemeBuilder.AddToScheme -) - -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(schema.GroupVersion{Group: "", Version: "v1"}, - &fakeTwoPhaseChaos{}, - ) - return nil -} - -var _ = Describe("TwoPhase", func() { - Context("TwoPhase", func() { - var err error - - zeroTime := time.Time{} - var _ = zeroTime - pastTime := time.Now().Add(-10 * time.Hour) - futureTime := time.Now().Add(10 * time.Hour) - - req := ctrl.Request{ - NamespacedName: types.NamespacedName{ - Name: "fakechaos-name", - Namespace: metav1.NamespaceDefault, - }, - } - - typeMeta := metav1.TypeMeta{ - Kind: "PodChaos", - APIVersion: "v1", - } - objectMeta := metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "fakechaos-name", - } - - It("TwoPhase Action", func() { - chaos := fakeTwoPhaseChaos{ - TypeMeta: typeMeta, - ObjectMeta: objectMeta, - } - - c := fake.NewFakeClientWithScheme(scheme.Scheme, &chaos) - - r := Reconciler{ - Endpoint: fakeEndpoint{}, - Context: ctx.Context{ - Client: c, - Log: ctrl.Log.WithName("controllers").WithName("TwoPhase"), - }, - } - - _, err = r.Reconcile(req) - - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("misdefined scheduler")) - }) - - It("TwoPhase Apply without Duration", func() { - chaos := fakeTwoPhaseChaos{ - TypeMeta: typeMeta, - ObjectMeta: objectMeta, - Scheduler: &v1alpha1.SchedulerSpec{Cron: "0/15 * * * *"}, - } - - c := fake.NewFakeClientWithScheme(scheme.Scheme, &chaos) - - r := Reconciler{ - Endpoint: fakeEndpoint{}, - Context: ctx.Context{ - Client: c, - Log: ctrl.Log.WithName("controllers").WithName("TwoPhase"), - }, - } - - _, err = r.Reconcile(req) - - Expect(err).ToNot(HaveOccurred()) - _chaos := r.Object() - err = r.Client.Get(context.TODO(), req.NamespacedName, _chaos) - Expect(err).ToNot(HaveOccurred()) - Expect(_chaos.(v1alpha1.InnerSchedulerObject).GetStatus().Experiment.Phase).To(Equal(v1alpha1.ExperimentPhaseWaiting)) - }) - - It("TwoPhase Delete", func() { - duration := "5m" - chaos := fakeTwoPhaseChaos{ - TypeMeta: typeMeta, - ObjectMeta: objectMeta, - Scheduler: &v1alpha1.SchedulerSpec{Cron: "@hourly"}, - Duration: &duration, - Deleted: true, - } - - c := fake.NewFakeClientWithScheme(scheme.Scheme, &chaos) - - r := Reconciler{ - Endpoint: fakeEndpoint{}, - Context: ctx.Context{ - Client: c, - Log: ctrl.Log.WithName("controllers").WithName("TwoPhase"), - }, - } - - _, err = r.Reconcile(req) - - Expect(err).ToNot(HaveOccurred()) - _chaos := r.Object() - err = r.Client.Get(context.TODO(), req.NamespacedName, _chaos) - Expect(err).ToNot(HaveOccurred()) - Expect(_chaos.(v1alpha1.InnerSchedulerObject).GetStatus().Experiment.Phase).To(Equal(v1alpha1.ExperimentPhaseFinished)) - - defer mock.With("MockRecoverError", errors.New("RecoverError"))() - - chaos.Status.Experiment.Phase = v1alpha1.ExperimentPhaseRunning - err := c.Update(context.TODO(), &chaos) - Expect(err).NotTo(HaveOccurred()) - - _, err = r.Reconcile(req) - - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("RecoverError")) - }) - - It("TwoPhase ToRecover", func() { - chaos := fakeTwoPhaseChaos{ - TypeMeta: typeMeta, - ObjectMeta: objectMeta, - Scheduler: &v1alpha1.SchedulerSpec{Cron: "@hourly"}, - } - - chaos.SetNextRecover(pastTime) - chaos.SetNextStart(futureTime) - - c := fake.NewFakeClientWithScheme(scheme.Scheme, &chaos) - - r := Reconciler{ - Endpoint: fakeEndpoint{}, - Context: ctx.Context{ - Client: c, - Log: ctrl.Log.WithName("controllers").WithName("TwoPhase"), - }, - } - - _, err = r.Reconcile(req) - - Expect(err).ToNot(HaveOccurred()) - _chaos := r.Object() - err = r.Client.Get(context.TODO(), req.NamespacedName, _chaos) - Expect(err).ToNot(HaveOccurred()) - Expect(_chaos.(v1alpha1.InnerSchedulerObject).GetStatus().Experiment.Phase).To(Equal(v1alpha1.ExperimentPhaseWaiting)) - }) - - It("TwoPhase ToRecover Error", func() { - chaos := fakeTwoPhaseChaos{ - TypeMeta: typeMeta, - ObjectMeta: objectMeta, - Scheduler: &v1alpha1.SchedulerSpec{Cron: "@hourly"}, - } - - defer mock.With("MockRecoverError", errors.New("RecoverError"))() - chaos.SetNextRecover(pastTime) - chaos.SetNextStart(futureTime) - chaos.Status.Experiment.Phase = v1alpha1.ExperimentPhaseRunning - - c := fake.NewFakeClientWithScheme(scheme.Scheme, &chaos) - - r := Reconciler{ - Endpoint: fakeEndpoint{}, - Context: ctx.Context{ - Client: c, - Log: ctrl.Log.WithName("controllers").WithName("TwoPhase"), - }, - } - - _, err = r.Reconcile(req) - - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("RecoverError")) - }) - - It("TwoPhase ToApply", func() { - chaos := fakeTwoPhaseChaos{ - TypeMeta: typeMeta, - ObjectMeta: objectMeta, - Scheduler: &v1alpha1.SchedulerSpec{Cron: "@hourly"}, - } - - chaos.SetNextRecover(futureTime) - chaos.SetNextStart(pastTime) - - c := fake.NewFakeClientWithScheme(scheme.Scheme, &chaos) - - r := Reconciler{ - Endpoint: fakeEndpoint{}, - Context: ctx.Context{ - Client: c, - Log: ctrl.Log.WithName("controllers").WithName("TwoPhase"), - }, - } - - _, err = r.Reconcile(req) - - Expect(err).ToNot(HaveOccurred()) - _chaos := r.Object() - err = r.Client.Get(context.TODO(), req.NamespacedName, _chaos) - Expect(err).ToNot(HaveOccurred()) - Expect(_chaos.(v1alpha1.InnerSchedulerObject).GetStatus().Experiment.Phase).To(Equal(v1alpha1.ExperimentPhaseRunning)) - }) - - It("TwoPhase ToApplyAgain", func() { - chaos := fakeTwoPhaseChaos{ - TypeMeta: typeMeta, - ObjectMeta: objectMeta, - Scheduler: &v1alpha1.SchedulerSpec{Cron: "@hourly"}, - } - - chaos.SetNextRecover(futureTime) - chaos.SetNextStart(pastTime) - - c := fake.NewFakeClientWithScheme(scheme.Scheme, &chaos) - - r := Reconciler{ - Endpoint: fakeEndpoint{}, - Context: ctx.Context{ - Client: c, - Log: ctrl.Log.WithName("controllers").WithName("TwoPhase"), - }, - } - - _, err = r.Reconcile(req) - - Expect(err).ToNot(HaveOccurred()) - _chaos := r.Object() - err = r.Client.Get(context.TODO(), req.NamespacedName, _chaos) - Expect(err).ToNot(HaveOccurred()) - Expect(_chaos.(v1alpha1.InnerSchedulerObject).GetStatus().Experiment.Phase).To(Equal(v1alpha1.ExperimentPhaseRunning)) - - chaos.Status.Experiment.StartTime = &metav1.Time{Time: pastTime} - chaos.Scheduler = &v1alpha1.SchedulerSpec{Cron: "@every 20h"} - chaos.SetNextStart(futureTime) - _ = c.Update(context.TODO(), &chaos) - - _, err = r.Reconcile(req) - Expect(err).ToNot(HaveOccurred()) - err = r.Client.Get(context.TODO(), req.NamespacedName, _chaos) - Expect(err).ToNot(HaveOccurred()) - Expect(_chaos.(v1alpha1.InnerSchedulerObject).GetStatus().Experiment.Phase).To(Equal(v1alpha1.ExperimentPhaseRunning)) - d, _ := time.ParseDuration("10h") - exp := time.Now().Add(d) - Expect(chaos.NextStart.Time.Year()).To(Equal(exp.Year())) - Expect(chaos.NextStart.Time.Month()).To(Equal(exp.Month())) - Expect(chaos.NextStart.Time.Day()).To(Equal(exp.Day())) - Expect(chaos.NextStart.Time.Hour()).To(Equal(exp.Hour())) - Expect(chaos.NextStart.Time.Minute()).To(Equal(exp.Minute())) - Expect(exp.Second()-chaos.NextStart.Time.Second() < 2).To(Equal(true)) - }) - - It("TwoPhase ToApply Error", func() { - chaos := fakeTwoPhaseChaos{ - TypeMeta: typeMeta, - ObjectMeta: objectMeta, - Scheduler: &v1alpha1.SchedulerSpec{Cron: "@hourly"}, - } - - chaos.SetNextRecover(futureTime) - chaos.SetNextStart(pastTime) - - c := fake.NewFakeClientWithScheme(scheme.Scheme, &chaos) - - r := Reconciler{ - Endpoint: fakeEndpoint{}, - Context: ctx.Context{ - Client: c, - Log: ctrl.Log.WithName("controllers").WithName("TwoPhase"), - }, - } - - defer mock.With("MockApplyError", errors.New("ApplyError"))() - - _, err = r.Reconcile(req) - - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("ApplyError")) - }) - }) -}) diff --git a/controllers/twophase/types.go b/controllers/twophase/types.go deleted file mode 100644 index da185b6c2f..0000000000 --- a/controllers/twophase/types.go +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package twophase - -import ( - "context" - "fmt" - "math" - "time" - - "github.com/go-logr/logr" - "github.com/pkg/errors" - "github.com/robfig/cron/v3" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" - sch "github.com/chaos-mesh/chaos-mesh/pkg/scheduler" - - ctrl "sigs.k8s.io/controller-runtime" -) - -const emptyString = "" - -// Reconciler for the twophase reconciler -type Reconciler struct { - endpoint.Endpoint - ctx.Context -} - -// NewReconciler would create reconciler for twophase controller -func NewReconciler(req ctrl.Request, e endpoint.Endpoint, ctx ctx.Context) *Reconciler { - ctx.Log = ctx.Log.WithName(req.NamespacedName.String()) - - return &Reconciler{ - Endpoint: e, - Context: ctx, - } -} - -// Reconcile is twophase reconcile implement -func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { - var err error - now := time.Now() - - r.Log.Info("Reconciling a two phase chaos", "name", req.Name, "namespace", req.Namespace, "time", time.Now()) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - _chaos := r.Object() - if err = r.Client.Get(ctx, req.NamespacedName, _chaos); err != nil { - r.Log.Error(err, "unable to get chaos") - return ctrl.Result{}, err - } - chaos := _chaos.(v1alpha1.InnerSchedulerObject) - - status := chaos.GetStatus() - - targetPhase := status.Experiment.Phase - - if !chaos.GetNextRecover().IsZero() && chaos.GetNextRecover().Before(now) { - targetPhase = v1alpha1.ExperimentPhaseWaiting - } - - if chaos.GetNextStart().Before(now) { - targetPhase = v1alpha1.ExperimentPhaseRunning - } - - // For standard cron(* * * * *), judge the phase when start - if chaos.GetNextStart().IsZero() && chaos.GetNextRecover().IsZero() { - phase, nextStart, err := ifStartAtWaitingPhase(chaos, now, r.Log) - if err != nil { - return ctrl.Result{}, err - } - if phase == v1alpha1.ExperimentPhaseWaiting { - targetPhase = phase - chaos.SetNextStart(*nextStart) - duration, err := chaos.GetDuration() - if err != nil { - return ctrl.Result{}, err - } - if duration == nil { - zero := 0 * time.Second - duration = &zero - } - chaos.SetNextRecover(nextStart.Add(*duration)) - } - } - - if chaos.IsPaused() { - targetPhase = v1alpha1.ExperimentPhasePaused - } - - // TODO: find a better way to solve the pause and resume problem. - // Or pause is a bad design for the scheduler :( - if !chaos.IsPaused() && status.Experiment.Phase == v1alpha1.ExperimentPhasePaused { - // Running and Waiting has the same logic for resuming - targetPhase = v1alpha1.ExperimentPhaseRunning - } - - if chaos.IsDeleted() { - targetPhase = v1alpha1.ExperimentPhaseFinished - } - - r.Log.Info("decide target phase", "target phase", targetPhase) - - machine := chaosStateMachine{ - Chaos: chaos, - Req: req, - Reconciler: r, - } - err = machine.Into(ctx, targetPhase, now) - if err != nil { - r.Log.Error(err, "fail to step into the phase", "target phase", targetPhase) - return ctrl.Result{}, err - } - - // the reconciliation of Finished and Paused resource shouldn't be triggered by time - if chaos.GetStatus().Experiment.Phase == v1alpha1.ExperimentPhaseFinished || - chaos.GetStatus().Experiment.Phase == v1alpha1.ExperimentPhasePaused { - return ctrl.Result{}, nil - } - - requeueAfter, err := calcRequeueAfterTime(chaos, now) - if err != nil { - r.Log.Error(err, "unexpected time", "now", now, "nextStart", chaos.GetNextStart(), "nextRecover", chaos.GetNextRecover()) - - // will not return error and retry - // because nothing will be better with retrying - return ctrl.Result{}, nil - } - - r.Log.Info("requeue", "requeue after", requeueAfter) - if requeueAfter == time.Duration(0) { - return ctrl.Result{Requeue: true}, nil - } - - return ctrl.Result{ - RequeueAfter: requeueAfter, - }, nil -} - -func calcRequeueAfterTime(chaos v1alpha1.InnerSchedulerObject, now time.Time) (time.Duration, error) { - requeueAfter := time.Duration(math.MaxInt64) - // requeueAfter = min(filter([nextRecoverAfter, nextStartAfter], >0)) - nextRecoverAfter := chaos.GetNextRecover().Sub(now) - nextStartAfter := chaos.GetNextStart().Sub(now) - - // If the `nextRecoverAfter` is less zero, we reset `nextRecoverAfter` to zero, - // which represents that the chaos action should be recovered immediately. - // `chaos.GetNextRecover()` ignores millisecond field, which will cause the `nextRecoverAfter` is less zero - // when the duration is zero or less 1 second. - if nextRecoverAfter < 0 { - nextRecoverAfter = 0 * time.Second - } - - if requeueAfter > nextRecoverAfter { - requeueAfter = nextRecoverAfter - } - - if nextStartAfter > 0 && requeueAfter > nextStartAfter { - requeueAfter = nextStartAfter - } - - var err error - if requeueAfter == math.MaxInt64 { - err = errors.Errorf("unexpected behavior, now is greater than nextRecover and nextStart") - } - - return requeueAfter, err -} - -func ifStartAtWaitingPhase(chaos v1alpha1.InnerSchedulerObject, now time.Time, log logr.Logger) (v1alpha1.ExperimentPhase, *time.Time, error) { - duration, err := chaos.GetDuration() - if err != nil { - log.Error(err, "failed to get chaos duration") - return "", nil, err - } - if duration == nil { - zero := 0 * time.Second - duration = &zero - } - - scheduler := chaos.GetScheduler() - if scheduler == nil { - log.Info("Scheduler should be defined currently") - return "", nil, fmt.Errorf("misdefined scheduler") - } - - lastStart, err := sch.LastTime(*scheduler, now) - if err != nil { - log.Error(err, "failed to get the last start time") - return "", nil, err - } - if lastStart.Add(*duration).Before(now) { - nextStart, err := nextTime(*scheduler, now) - if err != nil { - log.Error(err, "failed to get the next start time") - return "", nil, err - } - return v1alpha1.ExperimentPhaseWaiting, nextStart, nil - } - return "", nil, nil -} - -func nextTime(spec v1alpha1.SchedulerSpec, now time.Time) (*time.Time, error) { - scheduler, err := cron.ParseStandard(spec.Cron) - if err != nil { - return nil, fmt.Errorf("fail to parse runner rule %s, %v", spec.Cron, err) - } - - next := scheduler.Next(now) - return &next, nil -} diff --git a/controllers/twophase/update_scheduler.go b/controllers/twophase/update_scheduler.go deleted file mode 100644 index d4184db4bc..0000000000 --- a/controllers/twophase/update_scheduler.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package twophase - -import ( - "context" - "time" - - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" -) - -// SchedulerUpdater updates nextStart and nextRecover for resources -type SchedulerUpdater struct { - Object runtime.Object - ctx.Context -} - -// Reconcile is twophase reconcile implement -func (r *SchedulerUpdater) Reconcile(req ctrl.Request) (ctrl.Result, error) { - var err error - - r.Log.Info("Modifying scheduler for a resource", "name", req.Name, "namespace", req.Namespace, "time", time.Now()) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - _chaos := r.Object.DeepCopyObject() - if err = r.Client.Get(ctx, req.NamespacedName, _chaos); err != nil { - r.Log.Error(err, "unable to get chaos") - return ctrl.Result{}, nil - } - chaos := _chaos.(v1alpha1.InnerSchedulerObject) - - // update scheduler will start a waiting experiment - if chaos.GetStatus().Experiment.Phase == v1alpha1.ExperimentPhaseWaiting { - chaos.SetNextStart(time.Now()) - } - - if err := r.Update(ctx, chaos); err != nil { - r.Log.Error(err, "unable to update chaos") - return ctrl.Result{}, err - } - return ctrl.Result{}, nil -} diff --git a/controllers/types/types.go b/controllers/types/types.go new file mode 100644 index 0000000000..6c2c177d5e --- /dev/null +++ b/controllers/types/types.go @@ -0,0 +1,179 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package types + +import ( + "go.uber.org/fx" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type Controller string + +// Object only used for registration webhook for various Kind of chaos custom resources. +// Deprecated: use WebhookObject instead. +// TODO: migrate it to WebhookObject +type Object struct { + // Object should be the same as the kind of the chaos custom resource. + Object v1alpha1.InnerObject + // Name indicates the name of the webhook. It would be used to dedicate enabling the webhook for this Kind of + // chaos custom resource or not. + Name string +} + +// ChaosObjects is the list of all kind of chaos custom resource, following the registration pattern. +// Deprecated: use WebhookObjects instead. +var ChaosObjects = fx.Supply( + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "awschaos", + Object: &v1alpha1.AWSChaos{}, + }, + }, + + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "dnschaos", + Object: &v1alpha1.DNSChaos{}, + }, + }, + + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "httpchaos", + Object: &v1alpha1.HTTPChaos{}, + }, + }, + + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "iochaos", + Object: &v1alpha1.IOChaos{}, + }, + }, + + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "kernelchaos", + Object: &v1alpha1.KernelChaos{}, + }, + }, + + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "jvmchaos", + Object: &v1alpha1.JVMChaos{}, + }, + }, + + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "networkchaos", + Object: &v1alpha1.NetworkChaos{}, + }, + }, + + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "podchaos", + Object: &v1alpha1.PodChaos{}, + }, + }, + + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "stresschaos", + Object: &v1alpha1.StressChaos{}, + }, + }, + + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "timechaos", + Object: &v1alpha1.TimeChaos{}, + }, + }, + + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "gcpchaos", + Object: &v1alpha1.GCPChaos{}, + }, + }, + + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "physicalmachinechaos", + Object: &v1alpha1.PhysicalMachineChaos{}, + }, + }, + + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "azurechaos", + Object: &v1alpha1.AzureChaos{}, + }, + }, + + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "blockchaos", + Object: &v1alpha1.BlockChaos{}, + }, + }, +) + +// WebhookObject only used for registration the +type WebhookObject struct { + // Object should be the same as the kind of the chaos custom resource. + Object v1alpha1.WebhookObject + // Name indicates the name of the webhook. It would be used to dedicate enabling the webhook for this Kind of + // chaos custom resource or not. + Name string +} + +// WebhookObjects is the list of all kind of chaos custom resource, following the registration pattern. +// When you add a new kind of chaos custom resource, please add it to the list. +var WebhookObjects = fx.Supply( + fx.Annotated{ + Group: "webhookObjs", + Target: WebhookObject{ + Name: "physicalmachine", + Object: &v1alpha1.PhysicalMachine{}, + }, + }, + fx.Annotated{ + Group: "webhookObjs", + Target: WebhookObject{ + Name: "statuscheck", + Object: &v1alpha1.StatusCheck{}, + }, + }, +) diff --git a/controllers/utils/builder/default.go b/controllers/utils/builder/default.go new file mode 100644 index 0000000000..13fbfb91d5 --- /dev/null +++ b/controllers/utils/builder/default.go @@ -0,0 +1,33 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package builder + +import ( + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/controller" +) + +func Default(mgr ctrl.Manager) *ctrl.Builder { + return ctrl.NewControllerManagedBy(mgr). + WithOptions(controller.Options{ + // TODO: in a newer version `controller-runtime`, it would be + // possible to set a customized rate limiter. + // + // After upgrading `controller-runtime`, we could choose a better + // rate limiter for error handling + MaxConcurrentReconciles: 1, + }) +} diff --git a/controllers/utils/chaosdaemon.go b/controllers/utils/chaosdaemon.go deleted file mode 100644 index 358f3d084d..0000000000 --- a/controllers/utils/chaosdaemon.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package utils - -import ( - "context" - - "github.com/pkg/errors" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/controllers/config" - chaosdaemonclient "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/client" - grpcUtils "github.com/chaos-mesh/chaos-mesh/pkg/grpc" - "github.com/chaos-mesh/chaos-mesh/pkg/mock" -) - -var log = ctrl.Log.WithName("controller-chaos-daemon-client-utils") - -func FindDaemonIP(ctx context.Context, c client.Client, pod *v1.Pod) (string, error) { - nodeName := pod.Spec.NodeName - log.Info("Creating client to chaos-daemon", "node", nodeName) - - ns := config.ControllerCfg.Namespace - var endpoints v1.Endpoints - err := c.Get(ctx, types.NamespacedName{ - Namespace: ns, - Name: "chaos-daemon", - }, &endpoints) - if err != nil { - return "", err - } - - daemonIP := findIPOnEndpoints(&endpoints, nodeName) - if len(daemonIP) == 0 { - return "", errors.Errorf("cannot find daemonIP on node %s in related Endpoints %v", nodeName, endpoints) - } - - return daemonIP, nil -} - -func findIPOnEndpoints(e *v1.Endpoints, nodeName string) string { - for _, subset := range e.Subsets { - for _, addr := range subset.Addresses { - if addr.NodeName != nil && *addr.NodeName == nodeName { - return addr.IP - } - } - } - - return "" -} - -// NewChaosDaemonClient would create ChaosDaemonClient -func NewChaosDaemonClient(ctx context.Context, c client.Client, pod *v1.Pod) (chaosdaemonclient.ChaosDaemonClientInterface, error) { - if cli := mock.On("MockChaosDaemonClient"); cli != nil { - return cli.(chaosdaemonclient.ChaosDaemonClientInterface), nil - } - if err := mock.On("NewChaosDaemonClientError"); err != nil { - return nil, err.(error) - } - - daemonIP, err := FindDaemonIP(ctx, c, pod) - if err != nil { - return nil, err - } - - cc, err := grpcUtils.CreateGrpcConnection(daemonIP, config.ControllerCfg.ChaosDaemonPort, config.ControllerCfg.TLSConfig.ChaosMeshCACert, config.ControllerCfg.TLSConfig.ChaosDaemonClientCert, config.ControllerCfg.TLSConfig.ChaosDaemonClientKey) - if err != nil { - return nil, err - } - return chaosdaemonclient.New(cc), nil -} diff --git a/controllers/utils/chaosdaemon/chaosdaemon.go b/controllers/utils/chaosdaemon/chaosdaemon.go new file mode 100644 index 0000000000..90c784d78a --- /dev/null +++ b/controllers/utils/chaosdaemon/chaosdaemon.go @@ -0,0 +1,126 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package chaosdaemon + +import ( + "context" + "strings" + + "github.com/pkg/errors" + "go.uber.org/fx" + v1 "k8s.io/api/core/v1" + discoveryv1 "k8s.io/api/discovery/v1" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/controllers/config" + chaosdaemonclient "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/client" + grpcUtils "github.com/chaos-mesh/chaos-mesh/pkg/grpc" + "github.com/chaos-mesh/chaos-mesh/pkg/mock" +) + +var log = ctrl.Log.WithName("controller-chaos-daemon-client-utils") + +func findIPOnEndpointSlice(e *discoveryv1.EndpointSliceList, nodeName string) string { + for _, endpointSlice := range e.Items { + // Only get the endpoint slice of the current chaos-daemon pod. + if strings.HasPrefix(endpointSlice.ObjectMeta.Name, "chaos-daemon-") { + for _, ep := range endpointSlice.Endpoints { + if ep.NodeName != nil && *ep.NodeName == nodeName { + return ep.Addresses[0] + } + } + } + } + + return "" +} + +type ChaosDaemonClientBuilder struct { + client.Reader +} + +func (b *ChaosDaemonClientBuilder) FindDaemonIP(ctx context.Context, pod *v1.Pod) (string, error) { + nodeName := pod.Spec.NodeName + log.Info("Creating client to chaos-daemon", "node", nodeName) + + ns := config.ControllerCfg.Namespace + var endpointSliceList discoveryv1.EndpointSliceList + err := b.Reader.List(ctx, &endpointSliceList, client.InNamespace(ns)) + if err != nil { + return "", err + } + + daemonIP := findIPOnEndpointSlice(&endpointSliceList, nodeName) + if len(daemonIP) == 0 { + return "", errors.Errorf("cannot find daemonIP on node %s", nodeName) + } + + return daemonIP, nil +} + +// Build will construct a ChaosDaemonClient +// The `id` parameter is the namespacedName of current handling resource, +// which will be printed in the log of the chaos-daemon +func (b *ChaosDaemonClientBuilder) Build(ctx context.Context, pod *v1.Pod, id *types.NamespacedName) (chaosdaemonclient.ChaosDaemonClientInterface, error) { + if cli := mock.On("MockChaosDaemonClient"); cli != nil { + return cli.(chaosdaemonclient.ChaosDaemonClientInterface), nil + } + if err := mock.On("NewChaosDaemonClientError"); err != nil { + return nil, err.(error) + } + + daemonIP, err := b.FindDaemonIP(ctx, pod) + if err != nil { + return nil, err + } + builder := grpcUtils.Builder(daemonIP, config.ControllerCfg.ChaosDaemonPort).WithDefaultTimeout() + if config.ControllerCfg.TLSConfig.ChaosMeshCACert != "" { + builder.TLSFromFile(config.ControllerCfg.TLSConfig.ChaosMeshCACert, config.ControllerCfg.TLSConfig.ChaosDaemonClientCert, config.ControllerCfg.TLSConfig.ChaosDaemonClientKey) + } else { + builder.Insecure() + } + + if id != nil { + builder = builder.WithNamespacedName(*id) + } + + cc, err := builder.Build() + if err != nil { + return nil, err + } + return chaosdaemonclient.New(cc), nil +} + +type ChaosDaemonClientBuilderParams struct { + fx.In + + NoCacheReader client.Reader `name:"no-cache"` + ControlPlaneCacheReader client.Reader `name:"control-plane-cache" optional:"true"` +} + +func New(params ChaosDaemonClientBuilderParams) *ChaosDaemonClientBuilder { + var reader client.Reader + if params.ControlPlaneCacheReader != nil { + reader = params.ControlPlaneCacheReader + } else { + reader = params.NoCacheReader + } + return &ChaosDaemonClientBuilder{ + Reader: reader, + } +} diff --git a/controllers/utils/controller/finished.go b/controllers/utils/controller/finished.go new file mode 100644 index 0000000000..7bd82af804 --- /dev/null +++ b/controllers/utils/controller/finished.go @@ -0,0 +1,68 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controller + +import ( + "time" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +func IsChaosFinished(obj v1alpha1.InnerObject, now time.Time) bool { + finished, _ := IsChaosFinishedWithUntilStop(obj, now) + return finished +} + +func IsChaosFinishedWithUntilStop(obj v1alpha1.InnerObject, now time.Time) (bool, time.Duration) { + status := obj.GetStatus() + if obj.IsOneShot() { + finished := true + if len(status.Experiment.Records) == 0 { + finished = false + } else { + for _, record := range status.Experiment.Records { + if record.Phase != v1alpha1.Injected { + finished = false + } + } + } + // this oneshot chaos hasn't finished, retry after 1 second + return finished, time.Duration(time.Second) + } + + finished := true + + if status.Experiment.DesiredPhase == v1alpha1.RunningPhase { + finished = false + } else { + // If one of the record has not been recovered, it's not finished + for _, record := range status.Experiment.Records { + if record.Phase != v1alpha1.NotInjected { + finished = false + } + } + } + + durationExceeded, untilStop, err := obj.DurationExceeded(now) + if err != nil { + return finished, untilStop + } + if durationExceeded { + return finished, untilStop + } + + return false, untilStop +} diff --git a/controllers/utils/controller/finished_test.go b/controllers/utils/controller/finished_test.go new file mode 100644 index 0000000000..613e18d6ff --- /dev/null +++ b/controllers/utils/controller/finished_test.go @@ -0,0 +1,214 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controller + +import ( + "fmt" + "testing" + "time" + + . "github.com/onsi/gomega" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +func makeTestPodKill(creationTime time.Time, duration *string, desiredPhase v1alpha1.DesiredPhase, records []*v1alpha1.Record) v1alpha1.InnerObject { + return &v1alpha1.PodChaos{ + ObjectMeta: v1.ObjectMeta{ + CreationTimestamp: v1.Time{ + Time: creationTime, + }, + }, + Spec: v1alpha1.PodChaosSpec{ + Action: v1alpha1.PodKillAction, + Duration: duration, + }, + Status: v1alpha1.PodChaosStatus{ + ChaosStatus: v1alpha1.ChaosStatus{ + Experiment: v1alpha1.ExperimentStatus{ + DesiredPhase: desiredPhase, + Records: records, + }, + }, + }, + } +} +func makeTestNetworkChaos(creationTime time.Time, duration *string, desiredPhase v1alpha1.DesiredPhase, records []*v1alpha1.Record) v1alpha1.InnerObject { + return &v1alpha1.NetworkChaos{ + ObjectMeta: v1.ObjectMeta{ + CreationTimestamp: v1.Time{ + Time: creationTime, + }, + }, + Spec: v1alpha1.NetworkChaosSpec{ + Duration: duration, + }, + Status: v1alpha1.NetworkChaosStatus{ + ChaosStatus: v1alpha1.ChaosStatus{ + Experiment: v1alpha1.ExperimentStatus{ + DesiredPhase: desiredPhase, + Records: records, + }, + }, + }, + } +} + +func TestIsChaosFinished(t *testing.T) { + g := NewGomegaWithT(t) + + type testCase struct { + chaos v1alpha1.InnerObject + now time.Time + + expected bool + } + + beginTime := time.Now() + cases := []testCase{ + { + chaos: makeTestNetworkChaos(beginTime, pointer.StringPtr("20s"), v1alpha1.RunningPhase, []*v1alpha1.Record{ + { + Id: "some", + SelectorKey: "some", + Phase: v1alpha1.Injected, + }, + }), + now: beginTime.Add(10 * time.Second), + + expected: false, + }, + { + chaos: makeTestNetworkChaos(beginTime, pointer.StringPtr("20s"), v1alpha1.RunningPhase, []*v1alpha1.Record{ + { + Id: "some", + SelectorKey: "some", + Phase: v1alpha1.NotInjected, + }, + }), + now: beginTime.Add(10 * time.Second), + + expected: false, + }, + { + chaos: makeTestNetworkChaos(beginTime, pointer.StringPtr("20s"), v1alpha1.RunningPhase, []*v1alpha1.Record{ + { + Id: "some", + SelectorKey: "some", + Phase: v1alpha1.NotInjected, + }, + }), + now: beginTime.Add(30 * time.Second), + + expected: false, + }, + { + chaos: makeTestNetworkChaos(beginTime, pointer.StringPtr("20s"), v1alpha1.StoppedPhase, []*v1alpha1.Record{ + { + Id: "some", + SelectorKey: "some", + Phase: v1alpha1.NotInjected, + }, + }), + now: beginTime.Add(30 * time.Second), + + expected: true, + }, + { + chaos: makeTestNetworkChaos(beginTime, nil, v1alpha1.RunningPhase, []*v1alpha1.Record{ + { + Id: "some", + SelectorKey: "some", + Phase: v1alpha1.NotInjected, + }, + }), + now: beginTime.Add(30 * time.Second), + + expected: false, + }, + { + chaos: makeTestNetworkChaos(beginTime, nil, v1alpha1.RunningPhase, []*v1alpha1.Record{ + { + Id: "some", + SelectorKey: "some", + Phase: v1alpha1.Injected, + }, + }), + now: beginTime.Add(30 * time.Second), + + expected: false, + }, + // The chaos is paused, but not recovered yet + { + chaos: makeTestNetworkChaos(beginTime, nil, v1alpha1.StoppedPhase, []*v1alpha1.Record{ + { + Id: "some", + SelectorKey: "some", + Phase: v1alpha1.Injected, + }, + }), + now: beginTime.Add(30 * time.Second), + + expected: false, + }, + { + chaos: makeTestPodKill(beginTime, pointer.StringPtr("20s"), v1alpha1.StoppedPhase, []*v1alpha1.Record{ + { + Id: "some", + SelectorKey: "some", + Phase: v1alpha1.NotInjected, + }, + }), + now: beginTime.Add(30 * time.Second), + + expected: false, + }, + { + chaos: makeTestPodKill(beginTime, pointer.StringPtr("20s"), v1alpha1.StoppedPhase, []*v1alpha1.Record{ + { + Id: "some", + SelectorKey: "some", + Phase: v1alpha1.Injected, + }, + }), + now: beginTime.Add(30 * time.Second), + + expected: true, + }, + { + chaos: makeTestPodKill(beginTime, nil, v1alpha1.StoppedPhase, []*v1alpha1.Record{ + { + Id: "some", + SelectorKey: "some", + Phase: v1alpha1.Injected, + }, + }), + now: beginTime.Add(30 * time.Second), + + expected: true, + }, + } + + for index, c := range cases { + if index == 5 { + fmt.Println("some") + } + fmt.Println(index) + g.Expect(IsChaosFinished(c.chaos, c.now)).To(Equal(c.expected)) + } +} diff --git a/controllers/utils/controller/key.go b/controllers/utils/controller/key.go new file mode 100644 index 0000000000..345f406a84 --- /dev/null +++ b/controllers/utils/controller/key.go @@ -0,0 +1,73 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controller + +import ( + "strings" + + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/types" +) + +func ParseNamespacedName(namespacedName string) (types.NamespacedName, error) { + parts := strings.Split(namespacedName, "/") + if len(parts) > 1 { + return types.NamespacedName{ + Namespace: parts[0], + Name: parts[1], + }, nil + } + + return types.NamespacedName{ + Namespace: "", + Name: "", + }, errors.New("too few parts of namespacedname") + +} + +func ParseNamespacedNameContainer(namespacedName string) (types.NamespacedName, string, error) { + parts := strings.Split(namespacedName, "/") + if len(parts) > 2 { + // a lowercase RFC 1123 label must consist of lower case alphanumeric + // characters or '-', and must start and end with an alphanumeric + // character, so the container name can never have "/" + return types.NamespacedName{ + Namespace: parts[0], + Name: parts[1], + }, parts[2], nil + } + + return types.NamespacedName{ + Namespace: "", + Name: "", + }, "", errors.New("too few parts of namespacedname") + +} + +func ParseNamespacedNameContainerVolumePath(record string) (types.NamespacedName, string, string, error) { + parts := strings.Split(record, "/") + if len(parts) > 3 { + return types.NamespacedName{ + Namespace: parts[0], + Name: parts[1], + }, parts[2], strings.Join(parts[3:], "/"), nil + } + + return types.NamespacedName{ + Namespace: "", + Name: "", + }, "", "", errors.New("too few parts of namespacedname") +} diff --git a/controllers/utils/controller/ownerReferences.go b/controllers/utils/controller/ownerReferences.go new file mode 100644 index 0000000000..e6117f015b --- /dev/null +++ b/controllers/utils/controller/ownerReferences.go @@ -0,0 +1,65 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controller + +import ( + "github.com/pkg/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" +) + +func SetOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme) error { + ro, ok := owner.(runtime.Object) + if !ok { + return errors.Errorf("%T is not a runtime.Object, cannot call SetControllerReference", owner) + } + + gvk, err := apiutil.GVKForObject(ro, scheme) + if err != nil { + return err + } + + // Create a new ref + isController := false + blockOwnerDeletion := true + ref := metav1.OwnerReference{ + APIVersion: gvk.GroupVersion().String(), + Kind: gvk.Kind, + Name: owner.GetName(), + UID: owner.GetUID(), + BlockOwnerDeletion: &blockOwnerDeletion, + Controller: &isController, + } + + existingRefs := object.GetOwnerReferences() + fi := -1 + + for i, r := range existingRefs { + if ref.UID == r.UID { + fi = i + } + } + if fi == -1 { + existingRefs = append(existingRefs, ref) + } else { + existingRefs[fi] = ref + } + + // Update owner references + object.SetOwnerReferences(existingRefs) + return nil +} diff --git a/controllers/utils/recorder/annotations.go b/controllers/utils/recorder/annotations.go new file mode 100644 index 0000000000..3bd1125763 --- /dev/null +++ b/controllers/utils/recorder/annotations.go @@ -0,0 +1,124 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recorder + +import ( + "encoding" + "encoding/json" + "reflect" + "strconv" + + "github.com/iancoleman/strcase" + "github.com/pkg/errors" +) + +var ErrInvalidType = errors.New("invalid type of fields") +var ErrUknownType = errors.New("uknown type of fields") + +var annotationPrefix = "chaos-mesh.org/" + +func generateAnnotations(e ChaosEvent) (map[string]string, error) { + annotations := make(map[string]string) + + if e == nil { + return annotations, nil + } + + val := reflect.ValueOf(e) + val = reflect.Indirect(val) + for index := 0; index < val.NumField(); index++ { + fieldName := val.Type().Field(index).Name + key := annotationPrefix + strcase.ToKebab(fieldName) + field := val.Field(index) + switch field.Kind() { + case reflect.Invalid: + return nil, ErrInvalidType + case reflect.String: + annotations[key] = field.String() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + annotations[key] = strconv.Itoa(int(field.Int())) + default: + if marshaler, ok := field.Interface().(encoding.TextMarshaler); ok { + text, err := marshaler.MarshalText() + if err != nil { + return nil, err + } + + annotations[key] = string(text) + } else { + text, err := json.Marshal(field.Interface()) + if err != nil { + return nil, err + } + annotations[key] = string(text) + } + } + } + annotations[annotationPrefix+"type"] = strcase.ToKebab(val.Type().Name()) + + return annotations, nil +} + +// FromAnnotations will iterate over all the registered event, +// return `nil` if there is no suitable event. +func FromAnnotations(annotations map[string]string) (ChaosEvent, error) { + typeName := annotations[annotationPrefix+"type"] + ev := allEvents[typeName] + + if ev == nil { + return nil, ErrUknownType + } + + val := reflect.ValueOf(ev) + val = reflect.Indirect(val) + newEmptyValue := reflect.Indirect(reflect.New(val.Type())) + + for index := 0; index < newEmptyValue.NumField(); index++ { + fieldName := newEmptyValue.Type().Field(index).Name + key := annotationPrefix + strcase.ToKebab(fieldName) + field := newEmptyValue.Field(index) + switch field.Kind() { + case reflect.Invalid: + return nil, ErrInvalidType + case reflect.String: + field.SetString(annotations[key]) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + num, err := strconv.Atoi(annotations[key]) + if err != nil { + return nil, err + } + field.SetInt(int64(num)) + default: + if unmarshaler, ok := field.Interface().(encoding.TextUnmarshaler); ok { + err := unmarshaler.UnmarshalText([]byte(annotations[key])) + if err != nil { + return nil, err + } + } else if unmarshaler, ok := field.Addr().Interface().(encoding.TextUnmarshaler); ok { + err := unmarshaler.UnmarshalText([]byte(annotations[key])) + if err != nil { + return nil, err + } + } else { + err := json.Unmarshal([]byte(annotations[key]), field.Addr().Interface()) + if err != nil { + return nil, err + } + } + } + } + return newEmptyValue.Interface().(ChaosEvent), nil +} diff --git a/controllers/utils/recorder/common.go b/controllers/utils/recorder/common.go new file mode 100644 index 0000000000..002a234ef9 --- /dev/null +++ b/controllers/utils/recorder/common.go @@ -0,0 +1,72 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recorder + +import ( + "fmt" +) + +type Applied struct { + Id string +} + +func (a Applied) Type() string { + return "Normal" +} + +func (a Applied) Reason() string { + return "Applied" +} + +func (a Applied) Message() string { + return fmt.Sprintf("Successfully apply chaos for %s", a.Id) +} + +type Recovered struct { + Id string +} + +func (r Recovered) Type() string { + return "Normal" +} + +func (r Recovered) Reason() string { + return "Recovered" +} + +func (r Recovered) Message() string { + return fmt.Sprintf("Successfully recover chaos for %s", r.Id) +} + +type NotSupported struct { + Activity string +} + +func (r NotSupported) Type() string { + return "Warning" +} + +func (r NotSupported) Reason() string { + return "NotSupported" +} + +func (r NotSupported) Message() string { + return fmt.Sprintf("%s is not supported", r.Activity) +} + +func init() { + register(Applied{}, Recovered{}, NotSupported{}) +} diff --git a/controllers/utils/recorder/controller.go b/controllers/utils/recorder/controller.go new file mode 100644 index 0000000000..063c2a9641 --- /dev/null +++ b/controllers/utils/recorder/controller.go @@ -0,0 +1,40 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recorder + +import ( + "fmt" +) + +type Updated struct { + Field string +} + +func (u Updated) Type() string { + return "Normal" +} + +func (u Updated) Reason() string { + return "Updated" +} + +func (u Updated) Message() string { + return fmt.Sprintf("Successfully update %s of resource", u.Field) +} + +func init() { + register(Updated{}) +} diff --git a/controllers/utils/recorder/desiredphase.go b/controllers/utils/recorder/desiredphase.go new file mode 100644 index 0000000000..c613f5019e --- /dev/null +++ b/controllers/utils/recorder/desiredphase.go @@ -0,0 +1,80 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recorder + +type Deleted struct { +} + +func (d Deleted) Type() string { + return "Normal" +} + +func (d Deleted) Reason() string { + return "Deleted" +} + +func (d Deleted) Message() string { + return "Experiment has been deleted" +} + +type TimeUp struct { +} + +func (t TimeUp) Type() string { + return "Normal" +} + +func (t TimeUp) Reason() string { + return "TimeUp" +} + +func (t TimeUp) Message() string { + return "Time up according to the duration" +} + +type Paused struct { +} + +func (p Paused) Type() string { + return "Normal" +} + +func (p Paused) Reason() string { + return "Paused" +} + +func (p Paused) Message() string { + return "Experiment has been paused" +} + +type Started struct { +} + +func (p Started) Type() string { + return "Normal" +} + +func (p Started) Reason() string { + return "Started" +} + +func (p Started) Message() string { + return "Experiment has started" +} + +func init() { + register(Deleted{}, TimeUp{}, Paused{}, Started{}) +} diff --git a/controllers/utils/recorder/error.go b/controllers/utils/recorder/error.go new file mode 100644 index 0000000000..7991f5e690 --- /dev/null +++ b/controllers/utils/recorder/error.go @@ -0,0 +1,42 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recorder + +import ( + "fmt" +) + +type Failed struct { + Activity string + + Err string +} + +func (f Failed) Type() string { + return "Warning" +} + +func (f Failed) Reason() string { + return "Failed" +} + +func (f Failed) Message() string { + return fmt.Sprintf("Failed to %s: %s", f.Activity, f.Err) +} + +func init() { + register(Failed{}) +} diff --git a/controllers/utils/recorder/finalizer.go b/controllers/utils/recorder/finalizer.go new file mode 100644 index 0000000000..70bd954112 --- /dev/null +++ b/controllers/utils/recorder/finalizer.go @@ -0,0 +1,50 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recorder + +type FinalizerInited struct { +} + +func (p FinalizerInited) Type() string { + return "Normal" +} + +func (p FinalizerInited) Reason() string { + return "FinalizerInited" +} + +func (p FinalizerInited) Message() string { + return "Finalizer has been inited" +} + +type FinalizerRemoved struct { +} + +func (p FinalizerRemoved) Type() string { + return "Normal" +} + +func (p FinalizerRemoved) Reason() string { + return "FinalizerInited" +} + +func (p FinalizerRemoved) Message() string { + return "Finalizer has been removed" +} + +func init() { + register(FinalizerInited{}, FinalizerRemoved{}) +} diff --git a/controllers/utils/recorder/recorder.go b/controllers/utils/recorder/recorder.go new file mode 100644 index 0000000000..69bb56c3f5 --- /dev/null +++ b/controllers/utils/recorder/recorder.go @@ -0,0 +1,171 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recorder + +import ( + "context" + "fmt" + "reflect" + "time" + + "github.com/go-logr/logr" + "github.com/iancoleman/strcase" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/record/util" + ref "k8s.io/client-go/tools/reference" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/pkg/metrics" +) + +type ChaosRecorder interface { + Event(object runtime.Object, ev ChaosEvent) +} + +type chaosRecorder struct { + log logr.Logger + source v1.EventSource + client client.Client + scheme *runtime.Scheme + metricsCollector *metrics.ChaosControllerManagerMetricsCollector +} + +func (r *chaosRecorder) Event(object runtime.Object, ev ChaosEvent) { + eventtype := ev.Type() + reason := ev.Reason() + message := ev.Message() + + annotations, err := generateAnnotations(ev) + if err != nil { + r.log.Error(err, "failed to generate annotations for event", "event", ev) + } + + ref, err := ref.GetReference(r.scheme, object) + if err != nil { + r.log.Error(err, "fail to construct reference", "object", object) + return + } + + if !util.ValidateEventType(eventtype) { + r.log.Error(fmt.Errorf("unsupported event type:'%v'", eventtype), "eventtype", eventtype) + return + } + + event := r.makeEvent(ref, annotations, eventtype, reason, message) + event.Source = r.source + go func() { + err := r.client.Create(context.TODO(), event) + if err != nil { + r.log.Error(err, "fail to submit event", "event", event) + } else { + r.metricsCollector.EmittedEvents.WithLabelValues(event.Type, event.Reason, event.Namespace).Inc() + } + }() +} + +func (r *chaosRecorder) makeEvent(ref *v1.ObjectReference, annotations map[string]string, eventtype, reason, message string) *v1.Event { + t := metav1.Time{Time: time.Now()} + namespace := ref.Namespace + if namespace == "" { + namespace = metav1.NamespaceDefault + } + return &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%v.%x", ref.Name, t.UnixNano()), + Namespace: namespace, + Annotations: annotations, + }, + InvolvedObject: *ref, + Reason: reason, + Message: message, + FirstTimestamp: t, + LastTimestamp: t, + Count: 1, + Type: eventtype, + } +} + +type ChaosEvent interface { + Type() string + Reason() string + Message() string +} + +var allEvents = make(map[string]ChaosEvent) + +func register(ev ...ChaosEvent) { + for _, ev := range ev { + val := reflect.ValueOf(ev) + val = reflect.Indirect(val) + + allEvents[strcase.ToKebab(val.Type().Name())] = ev + } +} + +type RecorderBuilder struct { + c client.Client + logger logr.Logger + scheme *runtime.Scheme + metricsCollector *metrics.ChaosControllerManagerMetricsCollector +} + +func (b *RecorderBuilder) Build(name string) ChaosRecorder { + return &chaosRecorder{ + log: b.logger.WithName("event-recorder-" + name), + source: v1.EventSource{ + Component: name, + }, + client: b.c, + scheme: b.scheme, + metricsCollector: b.metricsCollector, + } +} + +func NewRecorderBuilder(c client.Client, logger logr.Logger, scheme *runtime.Scheme, metricsCollector *metrics.ChaosControllerManagerMetricsCollector) *RecorderBuilder { + return &RecorderBuilder{ + c, + logger, + scheme, + metricsCollector, + } +} + +type debugRecorder struct { + Events map[types.NamespacedName][]ChaosEvent +} + +func (d *debugRecorder) Event(object runtime.Object, ev ChaosEvent) { + obj := object.(metav1.Object) + id := types.NamespacedName{ + Namespace: obj.GetNamespace(), + Name: obj.GetName(), + } + + if d.Events[id] == nil { + d.Events[id] = []ChaosEvent{} + } + + d.Events[id] = append(d.Events[id], ev) +} + +func NewDebugRecorder() *debugRecorder { + return &debugRecorder{ + Events: make(map[types.NamespacedName][]ChaosEvent), + } +} diff --git a/controllers/utils/recorder/recorder_test.go b/controllers/utils/recorder/recorder_test.go new file mode 100644 index 0000000000..f9e28a077a --- /dev/null +++ b/controllers/utils/recorder/recorder_test.go @@ -0,0 +1,105 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recorder + +import ( + "fmt" + "testing" + "time" + + . "github.com/onsi/gomega" +) + +func TestGenerateAnnotations(t *testing.T) { + g := NewGomegaWithT(t) + + type casePair struct { + annotations map[string]string + ev ChaosEvent + } + + missedRun, _ := time.Parse(time.RFC3339Nano, "2021-05-19T18:36:06Z") + testCases := []casePair{ + {map[string]string{"chaos-mesh.org/id": "", "chaos-mesh.org/type": "applied"}, Applied{}}, + {map[string]string{"chaos-mesh.org/id": "test", "chaos-mesh.org/type": "applied"}, Applied{"test"}}, + {map[string]string{"chaos-mesh.org/id": "test", "chaos-mesh.org/type": "recovered"}, Recovered{"test"}}, + + {map[string]string{"chaos-mesh.org/field": "test", "chaos-mesh.org/type": "updated"}, Updated{"test"}}, + + {map[string]string{"chaos-mesh.org/type": "deleted"}, Deleted{}}, + {map[string]string{"chaos-mesh.org/type": "time-up"}, TimeUp{}}, + {map[string]string{"chaos-mesh.org/type": "paused"}, Paused{}}, + {map[string]string{"chaos-mesh.org/type": "started"}, Started{}}, + + {map[string]string{"chaos-mesh.org/activity": "test1", "chaos-mesh.org/err": "test2", "chaos-mesh.org/type": "failed"}, Failed{"test1", "test2"}}, + {map[string]string{"chaos-mesh.org/type": "not-supported", "chaos-mesh.org/activity": "pausing a workflow schedule"}, NotSupported{Activity: "pausing a workflow schedule"}}, + + {map[string]string{"chaos-mesh.org/type": "finalizer-inited"}, FinalizerInited{}}, + {map[string]string{"chaos-mesh.org/type": "finalizer-removed"}, FinalizerRemoved{}}, + + {map[string]string{"chaos-mesh.org/missed-run": "2021-05-19T18:36:06Z", "chaos-mesh.org/type": "missed-schedule"}, MissedSchedule{MissedRun: missedRun}}, + {map[string]string{"chaos-mesh.org/name": "test", "chaos-mesh.org/type": "schedule-spawn"}, ScheduleSpawn{Name: "test"}}, + {map[string]string{"chaos-mesh.org/running-name": "test", "chaos-mesh.org/type": "schedule-forbid"}, ScheduleForbid{RunningName: "test"}}, + {map[string]string{"chaos-mesh.org/running-name": "test", "chaos-mesh.org/type": "schedule-skip-remove-history"}, ScheduleSkipRemoveHistory{RunningName: "test"}}, + {map[string]string{"chaos-mesh.org/type": "nodes-created", "chaos-mesh.org/child-nodes": "[\"node-a\",\"node-b\"]"}, NodesCreated{ChildNodes: []string{"node-a", "node-b"}}}, + } + + for _, c := range testCases { + g.Expect(generateAnnotations(c.ev)).To(Equal(c.annotations)) + + ev, err := FromAnnotations(c.annotations) + if err != nil { + fmt.Printf("fail") + } + g.Expect(ev).To(Equal(c.ev)) + } +} + +func TestParse(t *testing.T) { + g := NewGomegaWithT(t) + + type casePair struct { + message string + ev ChaosEvent + } + + missedRun, _ := time.Parse(time.RFC1123Z, "Wed, 19 May 2021 18:36:06 +0000") + testCases := []casePair{ + {"Successfully apply chaos for test", Applied{"test"}}, + {"Successfully recover chaos for test", Recovered{"test"}}, + + {"Successfully update test of resource", Updated{"test"}}, + + {"Experiment has been deleted", Deleted{}}, + {"Time up according to the duration", TimeUp{}}, + {"Experiment has been paused", Paused{}}, + {"Experiment has started", Started{}}, + + {"Failed to test1: test2", Failed{"test1", "test2"}}, + + {"Finalizer has been inited", FinalizerInited{}}, + {"Finalizer has been removed", FinalizerRemoved{}}, + + {"Missed scheduled time to start a job: Wed, 19 May 2021 18:36:06 +0000", MissedSchedule{MissedRun: missedRun}}, + {"Create new object: test", ScheduleSpawn{Name: "test"}}, + {"Forbid spawning new job because: test is still running", ScheduleForbid{RunningName: "test"}}, + {"Skip removing history: test is still running", ScheduleSkipRemoveHistory{RunningName: "test"}}, + } + + for _, c := range testCases { + g.Expect(c.ev.Message()).To(Equal(c.message)) + } +} diff --git a/controllers/utils/recorder/schedule.go b/controllers/utils/recorder/schedule.go new file mode 100644 index 0000000000..87a5164fd7 --- /dev/null +++ b/controllers/utils/recorder/schedule.go @@ -0,0 +1,89 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recorder + +import ( + "fmt" + "time" +) + +type MissedSchedule struct { + MissedRun time.Time +} + +func (m MissedSchedule) Type() string { + return "Warning" +} + +func (m MissedSchedule) Reason() string { + return "MissSchedule" +} + +func (m MissedSchedule) Message() string { + return fmt.Sprintf("Missed scheduled time to start a job: %s", m.MissedRun.Format(time.RFC1123Z)) +} + +type ScheduleSpawn struct { + Name string +} + +func (s ScheduleSpawn) Type() string { + return "Normal" +} + +func (s ScheduleSpawn) Reason() string { + return "Spawned" +} + +func (s ScheduleSpawn) Message() string { + return fmt.Sprintf("Create new object: %s", s.Name) +} + +type ScheduleForbid struct { + RunningName string +} + +func (s ScheduleForbid) Type() string { + return "Warning" +} + +func (s ScheduleForbid) Reason() string { + return "Forbid" +} + +func (s ScheduleForbid) Message() string { + return fmt.Sprintf("Forbid spawning new job because: %s is still running", s.RunningName) +} + +type ScheduleSkipRemoveHistory struct { + RunningName string +} + +func (s ScheduleSkipRemoveHistory) Type() string { + return "Warning" +} + +func (s ScheduleSkipRemoveHistory) Reason() string { + return "Skip" +} + +func (s ScheduleSkipRemoveHistory) Message() string { + return fmt.Sprintf("Skip removing history: %s is still running", s.RunningName) +} + +func init() { + register(MissedSchedule{}, ScheduleSpawn{}, ScheduleForbid{}, ScheduleSkipRemoveHistory{}) +} diff --git a/controllers/utils/recorder/statuscheck.go b/controllers/utils/recorder/statuscheck.go new file mode 100644 index 0000000000..f2879b4a29 --- /dev/null +++ b/controllers/utils/recorder/statuscheck.go @@ -0,0 +1,128 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recorder + +import ( + "fmt" + + corev1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type StatusCheckCompleted struct { + Msg v1alpha1.StatusCheckReason +} + +func (it StatusCheckCompleted) Type() string { + return corev1.EventTypeNormal +} + +func (it StatusCheckCompleted) Reason() string { + return v1alpha1.StatusCheckCompleted +} + +func (it StatusCheckCompleted) Message() string { + return fmt.Sprintf("status check completed: %s", string(it.Msg)) +} + +type StatusCheckExecutionFailed struct { + ExecutorType string + Msg string +} + +func (it StatusCheckExecutionFailed) Type() string { + return corev1.EventTypeWarning +} + +func (it StatusCheckExecutionFailed) Reason() string { + return string(v1alpha1.StatusCheckExecutionFailed) +} + +func (it StatusCheckExecutionFailed) Message() string { + return fmt.Sprintf("%s execution of status check failed: %s", it.ExecutorType, it.Msg) +} + +type StatusCheckExecutionSucceed struct { + ExecutorType string +} + +func (it StatusCheckExecutionSucceed) Type() string { + return corev1.EventTypeNormal +} + +func (it StatusCheckExecutionSucceed) Reason() string { + return string(v1alpha1.StatusCheckExecutionSucceed) +} + +func (it StatusCheckExecutionSucceed) Message() string { + return fmt.Sprintf("%s execution of status check succeed", it.ExecutorType) +} + +type StatusCheckDurationExceed struct { +} + +func (it StatusCheckDurationExceed) Type() string { + return corev1.EventTypeWarning +} + +func (it StatusCheckDurationExceed) Reason() string { + return string(v1alpha1.StatusCheckDurationExceed) +} + +func (it StatusCheckDurationExceed) Message() string { + return "duration exceed" +} + +type StatusCheckFailureThresholdExceed struct { +} + +func (it StatusCheckFailureThresholdExceed) Type() string { + return corev1.EventTypeWarning +} + +func (it StatusCheckFailureThresholdExceed) Reason() string { + return string(v1alpha1.StatusCheckFailureThresholdExceed) +} + +func (it StatusCheckFailureThresholdExceed) Message() string { + return "failure threshold exceed" +} + +type StatusCheckSuccessThresholdExceed struct { +} + +func (it StatusCheckSuccessThresholdExceed) Type() string { + return corev1.EventTypeNormal +} + +func (it StatusCheckSuccessThresholdExceed) Reason() string { + return string(v1alpha1.StatusCheckSuccessThresholdExceed) +} + +func (it StatusCheckSuccessThresholdExceed) Message() string { + return "success threshold exceed" +} + +func init() { + register( + StatusCheckCompleted{}, + StatusCheckExecutionFailed{}, + StatusCheckDurationExceed{}, + StatusCheckFailureThresholdExceed{}, + StatusCheckSuccessThresholdExceed{}, + ) +} diff --git a/controllers/utils/recorder/workflow.go b/controllers/utils/recorder/workflow.go new file mode 100644 index 0000000000..02222fc3e0 --- /dev/null +++ b/controllers/utils/recorder/workflow.go @@ -0,0 +1,401 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recorder + +import ( + "fmt" + "strings" + + corev1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type InvalidEntry struct { + EntryTemplate string +} + +func (it InvalidEntry) Type() string { + return corev1.EventTypeWarning +} + +func (it InvalidEntry) Reason() string { + return v1alpha1.InvalidEntry +} + +func (it InvalidEntry) Message() string { + return fmt.Sprintf("failed to spawn new entry node of workflow, entry: %s", it.EntryTemplate) +} + +type EntryCreated struct { + Entry string +} + +func (it EntryCreated) Type() string { + return corev1.EventTypeNormal +} + +func (it EntryCreated) Reason() string { + return v1alpha1.EntryCreated +} + +func (it EntryCreated) Message() string { + return fmt.Sprintf("entry node created, entry node %s", it.Entry) +} + +type NodesCreated struct { + ChildNodes []string +} + +func (it NodesCreated) Type() string { + return corev1.EventTypeNormal +} + +func (it NodesCreated) Reason() string { + return v1alpha1.NodesCreated +} + +func (it NodesCreated) Message() string { + return fmt.Sprintf("child nodes created, %s", strings.Join(it.ChildNodes, ",")) +} + +type ChaosCustomResourceCreated struct { + Name string + Kind string +} + +func (it ChaosCustomResourceCreated) Type() string { + return corev1.EventTypeNormal +} + +func (it ChaosCustomResourceCreated) Reason() string { + return v1alpha1.ChaosCRCreated +} + +func (it ChaosCustomResourceCreated) Message() string { + return fmt.Sprintf("chaos CR %s created", it.Name) +} + +type ChaosCustomResourceCreateFailed struct { +} + +func (it ChaosCustomResourceCreateFailed) Type() string { + return corev1.EventTypeWarning +} + +func (it ChaosCustomResourceCreateFailed) Reason() string { + return v1alpha1.ChaosCRCreateFailed +} + +func (it ChaosCustomResourceCreateFailed) Message() string { + return "failed to create chaos CR" +} + +type ChaosCustomResourceDeleted struct { + Name string + Kind string +} + +func (it ChaosCustomResourceDeleted) Type() string { + return corev1.EventTypeNormal +} + +func (it ChaosCustomResourceDeleted) Reason() string { + return v1alpha1.ChaosCRDeleted +} + +func (it ChaosCustomResourceDeleted) Message() string { + return fmt.Sprintf("chaos CR %s deleted", it.Name) +} + +type ChaosCustomResourceDeleteFailed struct { + Name string + Kind string +} + +func (it ChaosCustomResourceDeleteFailed) Type() string { + return corev1.EventTypeWarning +} + +func (it ChaosCustomResourceDeleteFailed) Reason() string { + return v1alpha1.ChaosCRDeleteFailed +} + +func (it ChaosCustomResourceDeleteFailed) Message() string { + return fmt.Sprintf("chaos CR %s delete failed", it.Name) +} + +type DeadlineExceed struct { +} + +func (it DeadlineExceed) Type() string { + return corev1.EventTypeNormal +} + +func (it DeadlineExceed) Reason() string { + return v1alpha1.NodeDeadlineExceed +} + +func (it DeadlineExceed) Message() string { + return "deadline exceed" +} + +type ParentNodeDeadlineExceed struct { + ParentNodeName string +} + +func (it ParentNodeDeadlineExceed) Type() string { + return corev1.EventTypeNormal +} + +func (it ParentNodeDeadlineExceed) Reason() string { + return v1alpha1.ParentNodeDeadlineExceed +} + +func (it ParentNodeDeadlineExceed) Message() string { + return fmt.Sprintf("deadline exceed bscause parent node %s deadline exceed", it.ParentNodeName) +} + +type WorkflowAccomplished struct { +} + +func (it WorkflowAccomplished) Type() string { + return corev1.EventTypeNormal +} + +func (it WorkflowAccomplished) Reason() string { + return v1alpha1.WorkflowAccomplished +} + +func (it WorkflowAccomplished) Message() string { + return "workflow accomplished" +} + +type NodeAccomplished struct { +} + +func (it NodeAccomplished) Type() string { + return corev1.EventTypeNormal +} + +func (it NodeAccomplished) Reason() string { + return v1alpha1.NodeAccomplished +} + +func (it NodeAccomplished) Message() string { + return "node accomplished" +} + +type TaskPodSpawned struct { + PodName string +} + +func (it TaskPodSpawned) Type() string { + return corev1.EventTypeNormal +} + +func (it TaskPodSpawned) Reason() string { + return v1alpha1.TaskPodSpawned +} + +func (it TaskPodSpawned) Message() string { + return fmt.Sprintf("pod %s spawned for task", it.PodName) +} + +type TaskPodSpawnFailed struct { +} + +func (it TaskPodSpawnFailed) Type() string { + return corev1.EventTypeWarning +} + +func (it TaskPodSpawnFailed) Reason() string { + return v1alpha1.TaskPodSpawnFailed +} + +func (it TaskPodSpawnFailed) Message() string { + return "failed to create pod for task" +} + +type TaskPodPodCompleted struct { + PodName string +} + +func (it TaskPodPodCompleted) Type() string { + return corev1.EventTypeNormal +} + +func (it TaskPodPodCompleted) Reason() string { + return v1alpha1.TaskPodPodCompleted +} + +func (it TaskPodPodCompleted) Message() string { + return fmt.Sprintf("pod %s for task node completed", it.PodName) +} + +type ConditionalBranchesSelected struct { + SelectedBranches []string +} + +func (it ConditionalBranchesSelected) Type() string { + return corev1.EventTypeNormal +} + +func (it ConditionalBranchesSelected) Reason() string { + return v1alpha1.ConditionalBranchesSelected +} + +func (it ConditionalBranchesSelected) Message() string { + return fmt.Sprintf("selected branches: %s", it.SelectedBranches) +} + +type RerunBySpecChanged struct { + CleanedChildrenNode []string +} + +func (it RerunBySpecChanged) Type() string { + return corev1.EventTypeNormal +} + +func (it RerunBySpecChanged) Reason() string { + return v1alpha1.RerunBySpecChanged +} + +func (it RerunBySpecChanged) Message() string { + return fmt.Sprintf("rerun by spec changed, remove children nodes: %s", it.CleanedChildrenNode) +} + +type StatusCheckCreated struct { + Name string +} + +func (it StatusCheckCreated) Type() string { + return corev1.EventTypeNormal +} + +func (it StatusCheckCreated) Reason() string { + return v1alpha1.StatusCheckCreated +} + +func (it StatusCheckCreated) Message() string { + return fmt.Sprintf("status check %s created", it.Name) +} + +type StatusCheckCreatedFailed struct { + Name string +} + +func (it StatusCheckCreatedFailed) Type() string { + return corev1.EventTypeWarning +} + +func (it StatusCheckCreatedFailed) Reason() string { + return v1alpha1.StatusCheckCreatedFailed +} + +func (it StatusCheckCreatedFailed) Message() string { + return fmt.Sprintf("status check %s create failed", it.Name) +} + +type StatusCheckDeleted struct { + Name string +} + +func (it StatusCheckDeleted) Type() string { + return corev1.EventTypeNormal +} + +func (it StatusCheckDeleted) Reason() string { + return v1alpha1.StatusCheckDeleted +} + +func (it StatusCheckDeleted) Message() string { + return fmt.Sprintf("status check %s deleted", it.Name) +} + +type StatusCheckDeletedFailed struct { + Name string +} + +func (it StatusCheckDeletedFailed) Type() string { + return corev1.EventTypeWarning +} + +func (it StatusCheckDeletedFailed) Reason() string { + return v1alpha1.StatusCheckDeletedFailed +} + +func (it StatusCheckDeletedFailed) Message() string { + return fmt.Sprintf("status check %s delete failed", it.Name) +} + +type ParentNodeAborted struct { + ParentNodeName string +} + +func (it ParentNodeAborted) Type() string { + return corev1.EventTypeNormal +} + +func (it ParentNodeAborted) Reason() string { + return v1alpha1.ParentNodeAborted +} + +func (it ParentNodeAborted) Message() string { + return fmt.Sprintf("abort the node because parent node %s aborted", it.ParentNodeName) +} + +type WorkflowAborted struct { + WorkflowName string +} + +func (it WorkflowAborted) Type() string { + return corev1.EventTypeNormal +} + +func (it WorkflowAborted) Reason() string { + return v1alpha1.WorkflowAborted +} + +func (it WorkflowAborted) Message() string { + return fmt.Sprintf("abort the node because workflow %s aborted", it.WorkflowName) +} + +func init() { + register( + InvalidEntry{}, + EntryCreated{}, + NodesCreated{}, + ChaosCustomResourceCreated{}, + ChaosCustomResourceCreateFailed{}, + ChaosCustomResourceDeleted{}, + ChaosCustomResourceDeleteFailed{}, + DeadlineExceed{}, + ParentNodeDeadlineExceed{}, + WorkflowAccomplished{}, + NodeAccomplished{}, + TaskPodSpawned{}, + TaskPodSpawnFailed{}, + TaskPodPodCompleted{}, + ConditionalBranchesSelected{}, + RerunBySpecChanged{}, + StatusCheckCreated{}, + StatusCheckCreatedFailed{}, + StatusCheckDeleted{}, + StatusCheckDeletedFailed{}, + ParentNodeAborted{}, + ) +} diff --git a/controllers/utils/test/manager/test_manager.go b/controllers/utils/test/manager/test_manager.go new file mode 100644 index 0000000000..ccdc9244e4 --- /dev/null +++ b/controllers/utils/test/manager/test_manager.go @@ -0,0 +1,62 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package manager + +import ( + "context" + "fmt" + "os" + + "go.uber.org/fx" + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + + ccfg "github.com/chaos-mesh/chaos-mesh/controllers/config" +) + +func NewTestManager(lc fx.Lifecycle, options *ctrl.Options, cfg *rest.Config) (ctrl.Manager, error) { + if ccfg.ControllerCfg.QPS > 0 { + cfg.QPS = ccfg.ControllerCfg.QPS + } + if ccfg.ControllerCfg.Burst > 0 { + cfg.Burst = ccfg.ControllerCfg.Burst + } + + mgr, err := ctrl.NewManager(cfg, *options) + if err != nil { + return nil, err + } + + ctx, cancelFunc := context.WithCancel(context.TODO()) + lc.Append(fx.Hook{ + OnStart: func(context.Context) error { + fmt.Println("Starting manager") + go func() { + if err := mgr.Start(ctx); err != nil { + fmt.Println(err) + os.Exit(1) + } + }() + return nil + }, + OnStop: func(ctx context.Context) error { + fmt.Println("Stopping manager") + cancelFunc() + return nil + }, + }) + return mgr, nil +} diff --git a/controllers/utils/test/metrics/test_metrics_collector.go b/controllers/utils/test/metrics/test_metrics_collector.go new file mode 100644 index 0000000000..44804f8ed6 --- /dev/null +++ b/controllers/utils/test/metrics/test_metrics_collector.go @@ -0,0 +1,27 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package metrics + +import ( + "github.com/go-logr/logr" + + "github.com/chaos-mesh/chaos-mesh/pkg/metrics" +) + +// NewTestChaosControllerManagerMetricsCollector provides metrics collector for testing +func NewTestChaosControllerManagerMetricsCollector(logger logr.Logger) *metrics.ChaosControllerManagerMetricsCollector { + return metrics.NewChaosControllerManagerMetricsCollector(nil, nil, logger) +} diff --git a/controllers/utils/test/provider.go b/controllers/utils/test/provider.go new file mode 100644 index 0000000000..fe4fced85e --- /dev/null +++ b/controllers/utils/test/provider.go @@ -0,0 +1,37 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package test + +import ( + "go.uber.org/fx" + + "github.com/chaos-mesh/chaos-mesh/cmd/chaos-controller-manager/provider" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/test/manager" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/test/metrics" +) + +var Module = fx.Provide( + provider.NewOption, + provider.NewClient, + provider.NewAuthCli, + provider.NewScheme, + provider.NewNoCacheReader, + provider.NewControlPlaneCacheReader, + manager.NewTestManager, + recorder.NewRecorderBuilder, + metrics.NewTestChaosControllerManagerMetricsCollector, +) diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index f5756b3983..0000000000 --- a/docs/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Docs - -This directory was moved to [chaos-mesh/website](https://github.com/chaos-mesh/website). diff --git a/docs/placeholder.go b/docs/placeholder.go deleted file mode 100644 index 1aae8bb3cd..0000000000 --- a/docs/placeholder.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -// This file only ensures `doc` package exist even if swagger is not enabled. This is required for `go mod tidy`. - -package docs diff --git a/e2e-test/action.go b/e2e-test/action.go new file mode 100644 index 0000000000..a3d0e85281 --- /dev/null +++ b/e2e-test/action.go @@ -0,0 +1,227 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package test + +import ( + "context" + "fmt" + "os/exec" + "strings" + "time" + + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" + aggregatorclientset "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset" + "k8s.io/kubernetes/test/e2e/framework" + + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/e2econst" + e2eutil "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" +) + +const ( + operatorChartName = "chaos-mesh" +) + +// OperatorAction describe the common operation during test (e2e/stability/etc..) +type OperatorAction interface { + CleanCRDOrDie() + DeployOperator(config *OperatorConfig) error + UpgradeOperator(config *OperatorConfig) error + RestartDaemon(info *OperatorConfig) error + RestartControllerManager(info *OperatorConfig) error + InstallCRD(config *OperatorConfig) error +} + +// BuildOperatorAction build an OperatorAction interface instance or fail +func BuildOperatorActionAndCfg(cfg *Config) (OperatorAction, *OperatorConfig, error) { + // Get clients + config, err := framework.LoadConfig() + if err != nil { + return nil, nil, errors.Wrap(err, "load config") + } + kubeCli, err := kubernetes.NewForConfig(config) + if err != nil { + return nil, nil, errors.Wrap(err, "create kube client") + } + aggrCli, err := aggregatorclientset.NewForConfig(config) + if err != nil { + return nil, nil, errors.Wrap(err, "create aggr client") + } + apiExtCli, err := apiextensionsclientset.NewForConfig(config) + if err != nil { + return nil, nil, errors.Wrap(err, "create apiExt clientset") + } + oa := NewOperatorAction(kubeCli, aggrCli, apiExtCli, cfg) + ocfg := NewDefaultOperatorConfig() + ocfg.Manager.ImageRegistry = cfg.ManagerImageRegistry + ocfg.Manager.ImageRepository = cfg.ManagerImage + ocfg.Manager.ImageTag = cfg.ManagerTag + ocfg.Daemon.ImageRegistry = cfg.DaemonImageRegistry + ocfg.Daemon.ImageRepository = cfg.DaemonImage + ocfg.Daemon.ImageTag = cfg.DaemonTag + ocfg.DNSImage = cfg.ChaosCoreDNSImage + ocfg.EnableDashboard = cfg.EnableDashboard + + return oa, &ocfg, nil +} + +// NewOperatorAction create an OperatorAction interface instance +func NewOperatorAction( + kubeCli kubernetes.Interface, + aggrCli aggregatorclientset.Interface, + apiExtCli apiextensionsclientset.Interface, + cfg *Config) OperatorAction { + + oa := &operatorAction{ + kubeCli: kubeCli, + aggrCli: aggrCli, + apiExtCli: apiExtCli, + cfg: cfg, + } + return oa +} + +func (oa *operatorAction) DeployOperator(info *OperatorConfig) error { + klog.Infof("create namespace chaos-mesh") + cmd := fmt.Sprintf(`kubectl create ns %s`, e2econst.ChaosMeshNamespace) + klog.Infof(cmd) + output, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput() + if err != nil { + return errors.Errorf("failed to create namespace chaos-mesh: %v %s", err, string(output)) + } + return oa.UpgradeOperator(info) +} + +func (oa *operatorAction) UpgradeOperator(info *OperatorConfig) error { + klog.Infof("deploying chaos-mesh:%v", info.ReleaseName) + cmd := fmt.Sprintf(`helm upgrade --install %s %s --namespace %s --set %s --skip-crds`, + info.ReleaseName, + oa.operatorChartPath(info.Tag), + info.Namespace, + info.operatorHelmSetValue()) + klog.Info(cmd) + res, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput() + if err != nil { + return errors.Errorf("failed to deploy operator: %v, %s", err, string(res)) + } + klog.Infof("start to waiting chaos-mesh ready") + err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { + ls := &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/instance": "chaos-mesh", + }, + } + l, err := metav1.LabelSelectorAsSelector(ls) + if err != nil { + klog.Errorf("failed to get selector, err:%v", err) + return false, nil + } + pods, err := oa.kubeCli.CoreV1().Pods(info.Namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: l.String()}) + if err != nil { + klog.Errorf("failed to get chaos-mesh pods, err:%v", err) + return false, nil + } + for _, pod := range pods.Items { + if pod.Status.Phase != corev1.PodRunning { + return false, nil + } + } + return true, nil + }) + if err != nil { + return err + } + return e2eutil.WaitForAPIServicesAvailable(oa.aggrCli, labels.Everything()) +} + +func (oa *operatorAction) InstallCRD(info *OperatorConfig) error { + klog.Infof("deploying chaos-mesh crd :%v", info.ReleaseName) + oa.runKubectlOrDie("create", "-f", oa.manifestPath("e2e/crd.yaml"), "--validate=false") + + e2eutil.WaitForCRDsEstablished(oa.apiExtCli, labels.Everything()) + // workaround for https://github.com/kubernetes/kubernetes/issues/65517 + klog.Infof("force sync kubectl cache") + cmdArgs := []string{"sh", "-c", "rm -rf ~/.kube/cache ~/.kube/http-cache"} + _, err := exec.Command(cmdArgs[0], cmdArgs[1:]...).CombinedOutput() + if err != nil { + klog.Fatalf("Failed to run '%s': %v", strings.Join(cmdArgs, " "), err) + } + return nil +} + +func (oa *operatorAction) RestartDaemon(info *OperatorConfig) error { + return oa.restartComponent(info, "chaos-daemon-") +} + +func (oa *operatorAction) RestartControllerManager(info *OperatorConfig) error { + return oa.restartComponent(info, "chaos-controller-manager-") +} + +func (oa *operatorAction) restartComponent(info *OperatorConfig, prefix string) error { + klog.Infof("klling component %v", prefix) + ls := &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/instance": "chaos-mesh", + }, + } + l, err := metav1.LabelSelectorAsSelector(ls) + if err != nil { + return errors.Wrap(err, "get selector") + } + + pods, err := oa.kubeCli.CoreV1().Pods(info.Namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: l.String()}) + if err != nil { + return errors.Wrap(err, "select pods") + } + + for _, pod := range pods.Items { + if strings.HasPrefix(pod.Name, prefix) { + err = oa.kubeCli.CoreV1().Pods(info.Namespace).Delete(context.TODO(), pod.Name, metav1.DeleteOptions{}) + if err != nil { + return errors.Wrapf(err, "delete pod(%s)", pod.Name) + } + } + } + + klog.Infof("start to waiting chaos-mesh ready") + err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { + pods, err := oa.kubeCli.CoreV1().Pods(info.Namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: l.String()}) + if err != nil { + klog.Errorf("get chaos-mesh pods: %v", err) + return false, nil + } + for _, pod := range pods.Items { + if pod.Status.Phase != corev1.PodRunning { + return false, nil + } + } + return true, nil + }) + if err != nil { + return err + } + return e2eutil.WaitForAPIServicesAvailable(oa.aggrCli, labels.Everything()) +} + +func (oa *operatorAction) CleanCRDOrDie() { + oa.runKubectlOrDie("delete", "crds", "--all") +} diff --git a/e2e-test/cmd/e2e_helper/Dockerfile b/e2e-test/cmd/e2e_helper/Dockerfile new file mode 100644 index 0000000000..1f5a6193ab --- /dev/null +++ b/e2e-test/cmd/e2e_helper/Dockerfile @@ -0,0 +1,13 @@ +FROM golang:1.20-alpine3.18 + +WORKDIR /src + +COPY . /src + +RUN go build -o test . + +FROM alpine:3.18 + +COPY --from=0 /src/test /bin + +ENTRYPOINT ["/bin/test"] diff --git a/e2e-test/cmd/e2e_helper/child_process_time_server.go b/e2e-test/cmd/e2e_helper/child_process_time_server.go new file mode 100644 index 0000000000..b188baef27 --- /dev/null +++ b/e2e-test/cmd/e2e_helper/child_process_time_server.go @@ -0,0 +1,63 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package main + +import ( + "context" + "io/ioutil" + "net/http" + "os" + "os/exec" + "time" +) + +type childProcessTimeServer interface { + Start(ctx context.Context) error + Time() (*time.Time, error) +} + +var _ childProcessTimeServer = (*defaultChildProcessTimeServer)(nil) + +// the default implementation would create another instance of e2e-helper, but bind with a different port +type defaultChildProcessTimeServer struct { +} + +// Start implements childProcessTimeServer +func (s *defaultChildProcessTimeServer) Start(ctx context.Context) error { + selfPath, err := os.Executable() + if err != nil { + return err + } + return exec.CommandContext(ctx, selfPath, "--port", "8081").Run() +} + +// Time implements childProcessTimeServer +func (s *defaultChildProcessTimeServer) Time() (*time.Time, error) { + resp, err := http.Get("http://localhost:8081/time") + if err != nil { + return nil, err + } + defer resp.Body.Close() + bytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + time, err := time.Parse(time.RFC3339Nano, string(bytes)) + if err != nil { + return nil, err + } + return &time, nil +} diff --git a/e2e-test/cmd/e2e_helper/go.mod b/e2e-test/cmd/e2e_helper/go.mod new file mode 100644 index 0000000000..5661b922c0 --- /dev/null +++ b/e2e-test/cmd/e2e_helper/go.mod @@ -0,0 +1,14 @@ +module github.com/chaos-mesh/chaos-mesh/test/cmd/e2e_helper + +go 1.20 + +require github.com/containerd/cgroups v1.1.0 + +require ( + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/opencontainers/runtime-spec v1.1.0-rc.1 // indirect + golang.org/x/sys v0.11.0 // indirect +) diff --git a/e2e-test/cmd/e2e_helper/go.sum b/e2e-test/cmd/e2e_helper/go.sum new file mode 100644 index 0000000000..ef47d2f3b9 --- /dev/null +++ b/e2e-test/cmd/e2e_helper/go.sum @@ -0,0 +1,44 @@ +github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/opencontainers/runtime-spec v1.1.0-rc.1 h1:wHa9jroFfKGQqFHj0I1fMRKLl0pfj+ynAqBxo3v6u9w= +github.com/opencontainers/runtime-spec v1.1.0-rc.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/e2e-test/cmd/e2e_helper/main.go b/e2e-test/cmd/e2e_helper/main.go new file mode 100644 index 0000000000..29a4c749a0 --- /dev/null +++ b/e2e-test/cmd/e2e_helper/main.go @@ -0,0 +1,354 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package main + +import ( + "bytes" + "context" + "encoding/json" + "flag" + "fmt" + "io" + "net" + "net/http" + "os" + "path/filepath" + "time" + + "github.com/containerd/cgroups" +) + +func main() { + port := flag.Int("port", 8080, "listen port") + dataDir := flag.String("data-dir", "/var/run/data", "data dir is the dir to write temp file, only used in io test") + + flag.Parse() + + s := newServer(*dataDir) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go s.childProcessTimeServer.Start(ctx) + err := s.setupUDPServer() + if err != nil { + fmt.Println("failed to serve udp server", err) + os.Exit(1) + } + + addr := fmt.Sprintf("0.0.0.0:%d", *port) + if err := http.ListenAndServe(addr, s.mux); err != nil { + fmt.Println("failed to serve http server", err) + os.Exit(1) + } +} + +type server struct { + mux *http.ServeMux + dataDir string + childProcessTimeServer childProcessTimeServer + + // ONLY FOR TEST: a buf without lock + recvBuf []byte +} + +func newServer(dataDir string) *server { + s := &server{ + mux: http.NewServeMux(), + dataDir: dataDir, + recvBuf: make([]byte, 5), + childProcessTimeServer: &defaultChildProcessTimeServer{}, + } + s.mux.HandleFunc("/ping", pong) + s.mux.HandleFunc("/time", s.time) + s.mux.HandleFunc("/child-process-time", s.childProcessTime) + s.mux.HandleFunc("/io", s.ioTest) + s.mux.HandleFunc("/mistake", s.mistakeTest) + s.mux.HandleFunc("/network/send", s.networkSendTest) + s.mux.HandleFunc("/network/recv", s.networkRecvTest) + s.mux.HandleFunc("/network/ping", s.networkPingTest) + s.mux.HandleFunc("/dns", s.dnsTest) + s.mux.HandleFunc("/stress", s.stressCondition) + s.mux.HandleFunc("/http", s.httpEcho) + s.mux.HandleFunc("/setup_https", s.SetupHTTPSServer) + return s +} + +func pong(w http.ResponseWriter, _ *http.Request) { + w.Write([]byte("pong")) +} + +func (s *server) setupUDPServer() error { + pc, err := net.ListenPacket("udp", "0.0.0.0:1070") + if err != nil { + return err + } + + go func() { + for { + _, _, err := pc.ReadFrom(s.recvBuf) + fmt.Println("receive buf " + string(s.recvBuf)) + if err != nil { + return + } + } + }() + + return nil +} + +// time write the current time as response body +func (s *server) time(w http.ResponseWriter, _ *http.Request) { + w.Write([]byte(time.Now().Format(time.RFC3339Nano))) +} + +// childProcessTime write the child process current time as response body +func (s *server) childProcessTime(w http.ResponseWriter, _ *http.Request) { + now, err := s.childProcessTimeServer.Time() + if err != nil { + panic(err) + } + w.Write([]byte(now.Format(time.RFC3339Nano))) +} + +// a handler to test io chaos +func (s *server) mistakeTest(w http.ResponseWriter, _ *http.Request) { + path := filepath.Join(s.dataDir, "e2e-test") + origData := []byte("hello world!!!!!!!!!!!!") + + err := os.WriteFile(path, origData, 0644) + if err != nil { + w.Write([]byte(fmt.Sprintf("failed to write file %v", err))) + return + } + gotData, err := os.ReadFile(path) + if err != nil { + w.Write([]byte(err.Error())) + return + } + result := bytes.Equal(origData, gotData) + if result { + w.Write([]byte("false")) + return + } + for i := 0; i < 10; i++ { + tmp, err := os.ReadFile(path) + if err != nil { + w.Write([]byte(err.Error())) + } + if !bytes.Equal(tmp, gotData) { + w.Write([]byte("true")) + return + } + } + w.Write([]byte("err")) +} + +// a handler to test io chaos +func (s *server) ioTest(w http.ResponseWriter, _ *http.Request) { + t1 := time.Now() + f, err := os.CreateTemp(s.dataDir, "e2e-test") + if err != nil { + w.Write([]byte(fmt.Sprintf("failed to create temp file %v", err))) + return + } + if _, err := f.Write([]byte("hello world")); err != nil { + w.Write([]byte(fmt.Sprintf("failed to write file %v", err))) + return + } + t2 := time.Now() + w.Write([]byte(t2.Sub(t1).String())) +} + +// a handler to test dns chaos +func (s *server) dnsTest(w http.ResponseWriter, r *http.Request) { + + url, ok := r.URL.Query()["url"] + + if !ok || len(url[0]) < 1 { + http.Error(w, "failed", http.StatusBadRequest) + return + } + + ips, err := net.LookupIP(url[0]) + if err != nil { + http.Error(w, "failed", http.StatusBadRequest) + return + } + + if len(ips) == 0 { + http.Error(w, "failed", http.StatusBadRequest) + return + } + + w.Write([]byte(ips[0].String())) +} + +type networkSendTestBody struct { + TargetIP string `json:"targetIP"` +} + +// a handler to test network chaos +func (s *server) networkPingTest(w http.ResponseWriter, r *http.Request) { + var body networkSendTestBody + + err := json.NewDecoder(r.Body).Decode(&body) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + c := http.Client{ + Timeout: 2 * time.Second, + } + startTime := time.Now() + resp, err := c.Get(fmt.Sprintf("http://%s:8080/ping", body.TargetIP)) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + defer resp.Body.Close() + + endTime := time.Now() + out, err := io.ReadAll(resp.Body) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + if string(out) != "pong" { + http.Error(w, "response is not pong", http.StatusBadRequest) + return + } + + w.Write([]byte(fmt.Sprintf("OK %d", endTime.UnixNano()-startTime.UnixNano()))) +} + +// a handler to test network chaos +func (s *server) networkSendTest(w http.ResponseWriter, r *http.Request) { + var body networkSendTestBody + + err := json.NewDecoder(r.Body).Decode(&body) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + conn, err := net.DialUDP("udp", nil, &net.UDPAddr{ + IP: net.ParseIP(body.TargetIP), + Port: 1070, + }) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + defer conn.Close() + + n, err := io.WriteString(conn, "ping\n") + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if n != 5 { + http.Error(w, "udp send less than 5 bytes", http.StatusBadRequest) + return + } + w.Write([]byte("send successfully\n")) +} + +// a handler to test network chaos +func (s *server) networkRecvTest(w http.ResponseWriter, r *http.Request) { + w.Write(s.recvBuf) + + s.recvBuf = []byte{} +} + +func (s *server) stressCondition(w http.ResponseWriter, r *http.Request) { + control, err := cgroups.Load(cgroups.V1, cgroups.PidPath(1)) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + stats, err := control.Stat(cgroups.IgnoreNotExist) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + response, err := json.Marshal(map[string]uint64{ + "cpuTime": stats.CPU.Usage.Total, + "memoryUsage": stats.Memory.Usage.Usage - stats.Memory.Kernel.Usage - stats.Memory.Cache, + }) + if err != nil { + http.Error(w, "fail to marshal response", http.StatusInternalServerError) + return + } + + w.Write(response) +} + +func (s *server) httpEcho(w http.ResponseWriter, r *http.Request) { + secrets := r.Header["Secret"] + if len(secrets) == 0 { + http.Error(w, "Forbidden", http.StatusForbidden) + return + } + + for _, secret := range secrets { + w.Header().Add("Secret", secret) + } + defer r.Body.Close() + _, err := io.Copy(w, r.Body) + if err != nil { + http.Error(w, "fail to copy body between request and response", http.StatusInternalServerError) + return + } +} + +type TLSServerKeys struct { + Cert []byte `json:"cert"` + Key []byte `json:"key"` +} + +func (s *server) SetupHTTPSServer(w http.ResponseWriter, r *http.Request) { + var body TLSServerKeys + err := json.NewDecoder(r.Body).Decode(&body) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + err = os.WriteFile("/tmp/server.crt", body.Cert, 0644) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + err = os.WriteFile("/tmp/server.key", body.Key, 0644) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + srv := &server{ + mux: http.NewServeMux(), + } + srv.mux.HandleFunc("/ping", pong) + + go func() { + panic(http.ListenAndServeTLS("0.0.0.0:8081", "/tmp/server.crt", "/tmp/server.key", srv.mux)) + }() + if err != nil { + return + } +} diff --git a/e2e-test/config.go b/e2e-test/config.go new file mode 100644 index 0000000000..bf62f3562b --- /dev/null +++ b/e2e-test/config.go @@ -0,0 +1,54 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package test + +// Config describe the basic config for the operator test +type Config struct { + ChartDir string + ManifestDir string + Tag string + ManagerImageRegistry string + ManagerImage string + ManagerTag string + DaemonImageRegistry string + DaemonImage string + DaemonTag string + E2EImage string + PauseImage string + ChaosCoreDNSImage string + InstallChaosMesh bool + EnableDashboard bool +} + +// NewDefaultConfig describe the default configuration for operator test +func NewDefaultConfig() *Config { + return &Config{ + ChartDir: "/charts", + ManifestDir: "/manifests", + Tag: "e2e", + ManagerImageRegistry: "ghcr.io", + ManagerImage: "chaos-mesh/chaos-mesh", + ManagerTag: "latest", + DaemonImageRegistry: "ghcr.io", + DaemonImage: "chaos-mesh/chaos-daemon", + DaemonTag: "latest", + E2EImage: "ghcr.io/chaos-mesh/e2e-helper:latest", + ChaosCoreDNSImage: "ghcr.io/chaos-mesh/chaos-coredns:latest", + PauseImage: "gcr.io/google-containers/pause:latest", + InstallChaosMesh: false, + EnableDashboard: false, + } +} diff --git a/e2e-test/e2e/chaos/basic.go b/e2e-test/e2e/chaos/basic.go new file mode 100644 index 0000000000..78f32d123e --- /dev/null +++ b/e2e-test/e2e/chaos/basic.go @@ -0,0 +1,549 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package chaos + +import ( + "context" + "fmt" + "net/http" + "strconv" + "strings" + "time" + + "github.com/onsi/ginkgo/v2" + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + restClient "k8s.io/client-go/rest" + "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/pod-security-admission/api" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + dnschaostestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/dnschaos" + httpchaostestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/httpchaos" + iochaostestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/iochaos" + networkchaostestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/networkchaos" + podchaostestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/podchaos" + sidecartestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/sidecar" + stresstestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/stresschaos" + timechaostestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/timechaos" + e2econfig "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/config" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/e2econst" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" + "github.com/chaos-mesh/chaos-mesh/e2e-test/pkg/fixture" + "github.com/chaos-mesh/chaos-mesh/pkg/log" + "github.com/chaos-mesh/chaos-mesh/pkg/portforward" // testcases +) + +var _ = ginkgo.Describe("[Basic]", func() { + f := framework.NewDefaultFramework("chaos-mesh") + f.NamespacePodSecurityEnforceLevel = api.LevelPrivileged + var ns string + var fwCancel context.CancelFunc + var fw portforward.PortForward + var kubeCli kubernetes.Interface + var config *restClient.Config + var cli client.Client + c := http.Client{ + Timeout: 10 * time.Second, + } + + ginkgo.BeforeEach(func() { + ns = f.Namespace.Name + ctx, cancel := context.WithCancel(context.Background()) + clientRawConfig, err := e2econfig.LoadClientRawConfig() + framework.ExpectNoError(err, "failed to load raw config") + logger, err := log.NewDefaultZapLogger() + framework.ExpectNoError(err, "failed to create logger") + fw, err = portforward.NewPortForwarder(ctx, e2econfig.NewSimpleRESTClientGetter(clientRawConfig), true, logger) + framework.ExpectNoError(err, "failed to create port forwarder") + fwCancel = cancel + kubeCli = f.ClientSet + config, err = framework.LoadConfig() + framework.ExpectNoError(err, "config error") + scheme := runtime.NewScheme() + _ = clientgoscheme.AddToScheme(scheme) + _ = v1alpha1.AddToScheme(scheme) + cli, err = client.New(config, client.Options{Scheme: scheme}) + framework.ExpectNoError(err, "create client error") + }) + + ginkgo.AfterEach(func() { + if fwCancel != nil { + fwCancel() + } + }) + + ginkgo.Context("[PodChaos]", func() { + ginkgo.Context("[PodFailure]", func() { + ginkgo.It("[Schedule]", func() { + podchaostestcases.TestcasePodFailureOnceThenDelete(ns, kubeCli, cli) + }) + ginkgo.It("[Pause]", func() { + podchaostestcases.TestcasePodFailurePauseThenUnPause(ns, kubeCli, cli) + }) + }) + ginkgo.Context("[PodKill]", func() { + ginkgo.It("[Schedule]", func() { + podchaostestcases.TestcasePodKillOnceThenDelete(ns, kubeCli, cli) + }) + ginkgo.It("[Pause]", func() { + podchaostestcases.TestcasePodKillPauseThenUnPause(ns, kubeCli, cli) + }) + }) + ginkgo.Context("[ContainerKill]", func() { + ginkgo.It("[Schedule]", func() { + podchaostestcases.TestcaseContainerKillOnceThenDelete(ns, kubeCli, cli) + }) + ginkgo.It("[Pause]", func() { + podchaostestcases.TestcaseContainerKillPauseThenUnPause(ns, kubeCli, cli) + }) + }) + }) + + // time chaos case in [TimeChaos] context + ginkgo.Context("[TimeChaos]", func() { + + var err error + var port uint16 + var pfCancel context.CancelFunc + + ginkgo.JustBeforeEach(func() { + svc := fixture.NewE2EService("timer", ns) + _, err = kubeCli.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create service error") + nd := fixture.NewTimerDeployment("timer", ns) + _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create timer deployment error") + err = util.WaitDeploymentReady("timer", ns, kubeCli) + framework.ExpectNoError(err, "wait timer deployment ready error") + _, port, pfCancel, err = portforward.ForwardOnePort(fw, ns, "svc/timer", 8080) + framework.ExpectNoError(err, "create helper port-forward failed") + }) + + ginkgo.JustAfterEach(func() { + if pfCancel != nil { + pfCancel() + } + }) + + // time skew chaos case in [TimeSkew] context + ginkgo.Context("[TimeSkew]", func() { + + ginkgo.It("[Schedule]", func() { + timechaostestcases.TestcaseTimeSkewOnceThenRecover(ns, cli, c, port) + }) + + ginkgo.It("[Pause]", func() { + timechaostestcases.TestcaseTimeSkewPauseThenUnpause(ns, cli, c, port) + }) + + ginkgo.It("[Child Process]", func() { + timechaostestcases.TestcaseTimeSkewPauseThenUnpause(ns, cli, c, port) + }) + }) + }) + + // io chaos case in [IOChaos] context + ginkgo.Context("[IOChaos]", func() { + + var ( + err error + port uint16 + pfCancel context.CancelFunc + ) + + ginkgo.JustBeforeEach(func() { + svc := fixture.NewE2EService("io", ns) + _, err = kubeCli.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create service error") + nd := fixture.NewIOTestDeployment("io-test", ns) + _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create io-test deployment error") + err = util.WaitDeploymentReady("io-test", ns, kubeCli) + framework.ExpectNoError(err, "wait io-test deployment ready error") + _, port, pfCancel, err = portforward.ForwardOnePort(fw, ns, "svc/io", 8080) + framework.ExpectNoError(err, "create helper io port port-forward failed") + }) + + ginkgo.JustAfterEach(func() { + if pfCancel != nil { + pfCancel() + } + }) + + // io chaos case in [IODelay] context + ginkgo.Context("[IODelay]", func() { + + ginkgo.It("[Schedule]", func() { + iochaostestcases.TestcaseIODelayDurationForATimeThenRecover(ns, cli, c, port) + }) + + ginkgo.It("[Pause]", func() { + iochaostestcases.TestcaseIODelayDurationForATimePauseAndUnPause(ns, cli, c, port) + }) + ginkgo.It("[SpecifyContainer]", func() { + iochaostestcases.TestcaseIODelayWithSpecifiedContainer(ns, cli, c, port) + }) + ginkgo.It("[WrongSpec]", func() { + iochaostestcases.TestcaseIODelayWithWrongSpec(ns, cli, c, port) + }) + }) + + // io chaos case in [IOError] context + ginkgo.Context("[IOErrno]", func() { + + ginkgo.It("[Schedule]", func() { + iochaostestcases.TestcaseIOErrorDurationForATimeThenRecover(ns, cli, c, port) + }) + ginkgo.It("[Pause]", func() { + iochaostestcases.TestcaseIOErrorDurationForATimePauseAndUnPause(ns, cli, c, port) + }) + ginkgo.It("[SpecifyContainer]", func() { + iochaostestcases.TestcaseIOErrorWithSpecifiedContainer(ns, cli, c, port) + }) + }) + + // io mistake case in [IOMistake] context + ginkgo.Context("[IOMistake]", func() { + + ginkgo.It("[Schedule]", func() { + iochaostestcases.TestcaseIOMistakeDurationForATimeThenRecover(ns, cli, c, port) + }) + ginkgo.It("[Pause]", func() { + iochaostestcases.TestcaseIOMistakeDurationForATimePauseAndUnPause(ns, cli, c, port) + }) + ginkgo.It("[SpecifyContainer]", func() { + iochaostestcases.TestcaseIOMistakeWithSpecifiedContainer(ns, cli, c, port) + }) + }) + }) + + //http chaos case in [HTTPChaos] context + ginkgo.Context("[HTTPChaos]", func() { + var ( + err error + port uint16 + tlsPort uint16 + pfCancel context.CancelFunc + client httpchaostestcases.HTTPE2EClient + ) + + ginkgo.JustBeforeEach(func() { + svc := fixture.NewE2EService("http", ns) + svc, err = kubeCli.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create service error") + for _, servicePort := range svc.Spec.Ports { + if servicePort.Name == "http" { + port = uint16(servicePort.NodePort) + continue + } + if servicePort.Name == "https" { + tlsPort = uint16(servicePort.NodePort) + continue + } + } + nd := fixture.NewHTTPTestDeployment("http-test", ns) + _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create http-test deployment error") + err = util.WaitDeploymentReady("http-test", ns, kubeCli) + framework.ExpectNoError(err, "wait http-test deployment ready error") + podlist, err := kubeCli.CoreV1().Pods(ns).List(context.TODO(), metav1.ListOptions{}) + framework.ExpectNoError(err, "find pod list error") + for _, item := range podlist.Items { + if strings.Contains(item.Name, "http-test") { + framework.Logf("get http-test-pod %v", item) + client.IP = item.Status.HostIP + break + } + } + client.C = &c + }) + + ginkgo.JustAfterEach(func() { + if pfCancel != nil { + pfCancel() + } + }) + + // http chaos case in [HTTPDelay] context + ginkgo.Context("[HTTPDelay]", func() { + ginkgo.It("[Schedule]", func() { + httpchaostestcases.TestcaseHttpDelayDurationForATimeThenRecover(ns, cli, client, port) + }) + ginkgo.It("[Pause]", func() { + httpchaostestcases.TestcaseHttpDelayDurationForATimePauseAndUnPause(ns, cli, client, port) + }) + }) + + // http chaos case in [HTTPAbort] context + ginkgo.Context("[HTTPAbort]", func() { + ginkgo.It("[Schedule]", func() { + httpchaostestcases.TestcaseHttpAbortThenRecover(ns, cli, client, port) + }) + ginkgo.It("[Pause]", func() { + httpchaostestcases.TestcaseHttpAbortPauseAndUnPause(ns, cli, client, port) + }) + }) + + // http chaos case in [HTTPReplace] context + ginkgo.Context("[HTTPReplace]", func() { + ginkgo.It("[Schedule]", func() { + httpchaostestcases.TestcaseHttpReplaceThenRecover(ns, cli, client, port) + }) + ginkgo.It("[Pause]", func() { + httpchaostestcases.TestcaseHttpReplacePauseAndUnPause(ns, cli, client, port) + }) + }) + + // http chaos case in [HTTPReplaceBody] context + ginkgo.Context("[HTTPReplaceBody]", func() { + ginkgo.It("[Schedule]", func() { + httpchaostestcases.TestcaseHttpReplaceBodyThenRecover(ns, cli, client, port) + }) + ginkgo.It("[Pause]", func() { + httpchaostestcases.TestcaseHttpReplaceBodyPauseAndUnPause(ns, cli, client, port) + }) + }) + + // http chaos case in [HTTPPatch] context + ginkgo.Context("[HTTPPatch]", func() { + ginkgo.It("[Schedule]", func() { + httpchaostestcases.TestcaseHttpPatchThenRecover(ns, cli, client, port) + }) + ginkgo.It("[Pause]", func() { + httpchaostestcases.TestcaseHttpPatchPauseAndUnPause(ns, cli, client, port) + }) + }) + + // http chaos case in [HTTPPatch] context + ginkgo.Context("[HTTP TLS]", func() { + ginkgo.It("[Schedule]", func() { + httpchaostestcases.TestcaseHttpTLSThenRecover(ns, kubeCli, cli, client, port, tlsPort) + }) + }) + }) + + ginkgo.Context("[Sidecar Config]", func() { + var ( + cmName string + cmNamespace string + ) + + // delete the created config map in each test case + ginkgo.JustAfterEach(func() { + kubeCli.CoreV1().ConfigMaps(cmNamespace).Delete(context.TODO(), cmName, metav1.DeleteOptions{}) + }) + + ginkgo.Context("[Template Config]", func() { + + ginkgo.It("[InValid ConfigMap key]", func() { + cmName = "incorrect-key-name" + cmNamespace = e2econst.ChaosMeshNamespace + sidecartestcases.TestcaseInvalidConfigMapKey(ns, cmNamespace, cmName, kubeCli, cli) + }) + + ginkgo.It("[InValid Configuration]", func() { + cmName = "incorrect-configuration" + cmNamespace = e2econst.ChaosMeshNamespace + sidecartestcases.TestcaseInvalidConfiguration(ns, cmNamespace, cmName, kubeCli, cli) + }) + }) + + ginkgo.Context("[Injection Config]", func() { + ginkgo.It("[No Template]", func() { + cmName = "no-template-name" + cmNamespace = e2econst.ChaosMeshNamespace + sidecartestcases.TestcaseNoTemplate(ns, cmNamespace, cmName, kubeCli, cli) + }) + + ginkgo.It("[No Template Args]", func() { + cmName = "no-template-args" + cmNamespace = e2econst.ChaosMeshNamespace + sidecartestcases.TestcaseNoTemplateArgs(ns, cmNamespace, cmName, kubeCli, cli) + }) + }) + }) + + ginkgo.Context("[NetworkChaos]", func() { + var err error + + var networkPeers []*v1.Pod + var ports []uint16 + var pfCancels []context.CancelFunc + + ginkgo.JustBeforeEach(func() { + ports = []uint16{} + networkPeers = []*v1.Pod{} + for index := 0; index < 4; index++ { + name := fmt.Sprintf("network-peer-%d", index) + + svc := fixture.NewE2EService(name, ns) + _, err = kubeCli.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create service error") + nd := fixture.NewNetworkTestDeployment(name, ns, map[string]string{"partition": strconv.Itoa(index % 2)}) + _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create network-peer deployment error") + err = util.WaitDeploymentReady(name, ns, kubeCli) + framework.ExpectNoError(err, "wait network-peer deployment ready error") + + pod, err := getPod(kubeCli, ns, name) + framework.ExpectNoError(err, "select network-peer pod error") + networkPeers = append(networkPeers, pod) + + _, port, pfCancel, err := portforward.ForwardOnePort(fw, ns, "svc/"+svc.Name, 8080) + ports = append(ports, port) + pfCancels = append(pfCancels, pfCancel) + framework.ExpectNoError(err, "create helper io port port-forward failed") + } + }) + + ginkgo.Context("[ForbidHostNetwork]", func() { + ginkgo.It("[Schedule]", func() { + networkchaostestcases.TestcaseForbidHostNetwork(ns, kubeCli, cli) + }) + }) + + ginkgo.Context("[NetworkPartition]", func() { + ginkgo.It("[Schedule]", func() { + networkchaostestcases.TestcaseNetworkPartition(ns, cli, networkPeers, ports, c) + }) + }) + + ginkgo.Context("[Netem]", func() { + ginkgo.It("[Schedule]", func() { + networkchaostestcases.TestcaseNetworkDelay(ns, cli, networkPeers, ports, c) + }) + ginkgo.It("[PeersCrossoverWithDirectionBoth]", func() { + networkchaostestcases.TestcasePeersCrossover(ns, cli, networkPeers, ports, c) + }) + }) + + ginkgo.JustAfterEach(func() { + for _, cancel := range pfCancels { + cancel() + } + }) + }) + // DNS chaos case in [DNSChaos] context + ginkgo.Context("[DNSChaos]", func() { + var err error + var port uint16 + + ginkgo.JustBeforeEach(func() { + name := "network-peer" + + svc := fixture.NewE2EService(name, ns) + _, err = kubeCli.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create service error") + nd := fixture.NewNetworkTestDeployment(name, ns, map[string]string{"partition": "0"}) + _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create network-peer deployment error") + err = util.WaitDeploymentReady(name, ns, kubeCli) + framework.ExpectNoError(err, "wait network-peer deployment ready error") + + _, err = getPod(kubeCli, ns, name) + framework.ExpectNoError(err, "select network-peer pod error") + + _, port, _, err = portforward.ForwardOnePort(fw, ns, "svc/"+svc.Name, 8080) + framework.ExpectNoError(err, "create helper io port port-forward failed") + }) + ginkgo.It("[RANDOM]", func() { + dnschaostestcases.TestcaseDNSRandom(ns, cli, port, c) + }) + + ginkgo.It("[ERROR]", func() { + dnschaostestcases.TestcaseDNSError(ns, cli, port, c) + }) + }) + // DNS chaos case in [StressChaos] context + ginkgo.Context("[StressChaos]", func() { + var err error + + var ports []uint16 + var stressPeers []*v1.Pod + var pfCancels []context.CancelFunc + + ginkgo.JustBeforeEach(func() { + ports = []uint16{} + stressPeers = []*v1.Pod{} + for index := 0; index < 2; index++ { + name := fmt.Sprintf("stress-peer-%d", index) + + svc := fixture.NewE2EService(name, ns) + _, err = kubeCli.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create service error") + nd := fixture.NewStressTestDeployment(name, ns, map[string]string{"partition": strconv.Itoa(index % 2)}) + _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create network-peer deployment error") + err = util.WaitDeploymentReady(name, ns, kubeCli) + framework.ExpectNoError(err, "wait network-peer deployment ready error") + + pod, err := getPod(kubeCli, ns, name) + framework.ExpectNoError(err, "select network-peer pod error") + stressPeers = append(stressPeers, pod) + + _, port, pfCancel, err := portforward.ForwardOnePort(fw, ns, "svc/"+svc.Name, 8080) + ports = append(ports, port) + pfCancels = append(pfCancels, pfCancel) + framework.ExpectNoError(err, "create helper io port port-forward failed") + } + }) + + ginkgo.It("[CPU]", func() { + stresstestcases.TestcaseCPUStressInjectionOnceThenRecover(ns, cli, stressPeers, ports, c) + }) + + // TODO: unstable test + ginkgo.It("[Memory]", func() { + stresstestcases.TestcaseMemoryStressInjectionOnceThenRecover(ns, cli, stressPeers, ports, c) + }) + + ginkgo.JustAfterEach(func() { + for _, cancel := range pfCancels { + cancel() + } + }) + }) +}) + +func getPod(kubeCli kubernetes.Interface, ns string, appLabel string) (*v1.Pod, error) { + listOption := metav1.ListOptions{ + LabelSelector: labels.SelectorFromSet(map[string]string{ + "app": appLabel, + }).String(), + } + + pods, err := kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) + if err != nil { + return nil, err + } + + if len(pods.Items) > 1 { + return nil, errors.New("select more than one pod") + } + + if len(pods.Items) == 0 { + return nil, errors.New("cannot select any pod") + } + + return &pods.Items[0], nil +} diff --git a/test/e2e/chaos/dnschaos/dns.go b/e2e-test/e2e/chaos/dnschaos/dns.go similarity index 75% rename from test/e2e/chaos/dnschaos/dns.go rename to e2e-test/e2e/chaos/dnschaos/dns.go index c3b4aab62e..f451f4ee57 100644 --- a/test/e2e/chaos/dnschaos/dns.go +++ b/e2e-test/e2e/chaos/dnschaos/dns.go @@ -1,34 +1,37 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// -package networkchaos +package dnschaos import ( "context" "fmt" - "io/ioutil" + "io" "net/http" "strings" "time" + "github.com/pkg/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/klog" + "k8s.io/klog/v2" "k8s.io/kubernetes/test/e2e/framework" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/test/e2e/util" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" ) func TestcaseDNSRandom( @@ -58,11 +61,17 @@ func TestcaseDNSRandom( }, Spec: v1alpha1.DNSChaosSpec{ Action: v1alpha1.RandomAction, - Mode: v1alpha1.AllPodMode, DomainNamePatterns: []string{"not-exist-?ost.*", "not_exist?host.abc", "not-exist-host.def"}, - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "network-peer"}, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Mode: v1alpha1.AllMode, + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "network-peer"}, + }, + }, + }, }, }, } @@ -71,7 +80,7 @@ func TestcaseDNSRandom( framework.ExpectNoError(err, "create dns chaos error") for _, domainName := range effectDomainNames { - err = wait.Poll(time.Second, 5*time.Second, func() (done bool, err error) { + err = wait.Poll(time.Second, 10*time.Second, func() (done bool, err error) { // get IP of a non exists host, because chaos DNS server will return a random IP, // so err should be nil _, dnsErr := testDNSServer(c, port, domainName) @@ -116,11 +125,17 @@ func TestcaseDNSError( }, Spec: v1alpha1.DNSChaosSpec{ Action: v1alpha1.ErrorAction, - Mode: v1alpha1.AllPodMode, DomainNamePatterns: []string{"chaos-mes?.org", "github.com", "16?.co*"}, - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "network-peer"}, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Mode: v1alpha1.AllMode, + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "network-peer"}, + }, + }, + }, }, }, } @@ -129,8 +144,8 @@ func TestcaseDNSError( framework.ExpectNoError(err, "create dns chaos error") for _, domainName := range effectDomainNames { - err = wait.Poll(time.Second, 5*time.Second, func() (done bool, err error) { - // get IP of a chaos-mesh.org, because chaos DNS server will return error, + err = wait.Poll(time.Second, 10*time.Second, func() (done bool, err error) { + // get IP of some domain names, because chaos DNS server will return error, // so err should not be nil _, dnsErr := testDNSServer(c, port, domainName) if dnsErr == nil { @@ -155,7 +170,7 @@ func testDNSServer(c http.Client, port uint16, url string) (string, error) { return "", err } - out, err := ioutil.ReadAll(resp.Body) + out, err := io.ReadAll(resp.Body) defer resp.Body.Close() if err != nil { return "", err @@ -164,7 +179,7 @@ func testDNSServer(c http.Client, port uint16, url string) (string, error) { result := string(out) klog.Infof("testDNSServer result: %s", result) if strings.Contains(result, "failed") { - return "", fmt.Errorf("test DNS server failed") + return "", errors.New("test DNS server failed") } return result, nil diff --git a/e2e-test/e2e/chaos/graceful-shutdown.go b/e2e-test/e2e/chaos/graceful-shutdown.go new file mode 100644 index 0000000000..ad9e61c611 --- /dev/null +++ b/e2e-test/e2e/chaos/graceful-shutdown.go @@ -0,0 +1,163 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package chaos + +import ( + "context" + "net/http" + "strings" + "time" + + "github.com/onsi/ginkgo/v2" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + restClient "k8s.io/client-go/rest" + "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/pod-security-admission/api" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + httpchaostestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/httpchaos" + iochaostestcases "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos/iochaos" + e2econfig "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/config" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" + "github.com/chaos-mesh/chaos-mesh/e2e-test/pkg/fixture" + "github.com/chaos-mesh/chaos-mesh/pkg/log" + "github.com/chaos-mesh/chaos-mesh/pkg/portforward" // testcases +) + +var _ = ginkgo.Describe("[Graceful-Shutdown]", func() { + f := framework.NewDefaultFramework("chaos-mesh") + f.NamespacePodSecurityEnforceLevel = api.LevelPrivileged + var ns string + var fwCancel context.CancelFunc + var fw portforward.PortForward + var kubeCli kubernetes.Interface + var config *restClient.Config + var cli client.Client + c := http.Client{ + Timeout: 10 * time.Second, + } + + ginkgo.BeforeEach(func() { + ns = f.Namespace.Name + ctx, cancel := context.WithCancel(context.Background()) + clientRawConfig, err := e2econfig.LoadClientRawConfig() + framework.ExpectNoError(err, "failed to load raw config") + logger, err := log.NewDefaultZapLogger() + framework.ExpectNoError(err, "failed to create logger") + fw, err = portforward.NewPortForwarder(ctx, e2econfig.NewSimpleRESTClientGetter(clientRawConfig), true, logger) + framework.ExpectNoError(err, "failed to create port forwarder") + fwCancel = cancel + kubeCli = f.ClientSet + config, err = framework.LoadConfig() + framework.ExpectNoError(err, "config error") + scheme := runtime.NewScheme() + _ = clientgoscheme.AddToScheme(scheme) + _ = v1alpha1.AddToScheme(scheme) + cli, err = client.New(config, client.Options{Scheme: scheme}) + framework.ExpectNoError(err, "create client error") + }) + + ginkgo.AfterEach(func() { + if fwCancel != nil { + fwCancel() + } + }) + + // io chaos case in [IOChaos] context + ginkgo.Context("[IOChaos]", func() { + var ( + err error + port uint16 + pfCancel context.CancelFunc + ) + + ginkgo.JustBeforeEach(func() { + svc := fixture.NewE2EService("io", ns) + _, err = kubeCli.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create service error") + nd := fixture.NewIOTestDeployment("io-test", ns) + _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create io-test deployment error") + err = util.WaitDeploymentReady("io-test", ns, kubeCli) + framework.ExpectNoError(err, "wait io-test deployment ready error") + _, port, pfCancel, err = portforward.ForwardOnePort(fw, ns, "svc/io", 8080) + framework.ExpectNoError(err, "create helper io port port-forward failed") + }) + + ginkgo.JustAfterEach(func() { + if pfCancel != nil { + pfCancel() + } + }) + + // io chaos case in [Shutdown] context + ginkgo.It("[Shutdown]", func() { + iochaostestcases.TestcaseIOErrorGracefulShutdown(ns, cli, c, port) + }) + }) + + //http chaos case in [HTTPChaos] context + ginkgo.Context("[HTTPChaos]", func() { + var ( + err error + port uint16 + pfCancel context.CancelFunc + client httpchaostestcases.HTTPE2EClient + ) + + ginkgo.JustBeforeEach(func() { + svc := fixture.NewE2EService("http", ns) + svc, err = kubeCli.CoreV1().Services(ns).Create(context.TODO(), svc, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create service error") + for _, servicePort := range svc.Spec.Ports { + if servicePort.Name == "http" { + port = uint16(servicePort.NodePort) + break + } + } + nd := fixture.NewHTTPTestDeployment("http-test", ns) + _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create http-test deployment error") + err = util.WaitDeploymentReady("http-test", ns, kubeCli) + framework.ExpectNoError(err, "wait http-test deployment ready error") + podlist, err := kubeCli.CoreV1().Pods(ns).List(context.TODO(), metav1.ListOptions{}) + framework.ExpectNoError(err, "find pod list error") + for _, item := range podlist.Items { + if strings.Contains(item.Name, "http-test") { + framework.Logf("get http-test-pod %v", item) + client.IP = item.Status.HostIP + break + } + } + client.C = &c + }) + + ginkgo.JustAfterEach(func() { + if pfCancel != nil { + pfCancel() + } + }) + + // http chaos case in [Shutdown] context + ginkgo.It("[Shutdown]", func() { + httpchaostestcases.TestcaseHttpGracefulAbortShutdown(ns, cli, client, port) + }) + }) +}) diff --git a/e2e-test/e2e/chaos/httpchaos/http_abort.go b/e2e-test/e2e/chaos/httpchaos/http_abort.go new file mode 100644 index 0000000000..36cd7bf91a --- /dev/null +++ b/e2e-test/e2e/chaos/httpchaos/http_abort.go @@ -0,0 +1,260 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package httpchaos + +import ( + "context" + "time" + + . "github.com/onsi/ginkgo/v2" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/kubernetes/test/e2e/framework" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" +) + +func TestcaseHttpAbortThenRecover( + ns string, + cli client.Client, + c HTTPE2EClient, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("waiting on e2e helper ready") + err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + By("create http abort chaos CRD objects") + + abort := true + + httpChaos := &v1alpha1.HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-chaos", + Namespace: ns, + }, + Spec: v1alpha1.HTTPChaosSpec{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "http"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + Port: 8080, + Target: "Request", + PodHttpChaosActions: v1alpha1.PodHttpChaosActions{ + Abort: &abort, + }, + }, + } + err = cli.Create(ctx, httpChaos) + framework.ExpectNoError(err, "create http chaos error") + + By("waiting for assertion HTTP abort") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + _, err := getPodHttpNoBody(c, port) + + // abort applied + if err != nil { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "http chaos doesn't work as expected") + By("apply http chaos successfully") + + By("delete chaos CRD objects") + // delete chaos CRD + err = cli.Delete(ctx, httpChaos) + framework.ExpectNoError(err, "failed to delete http chaos") + + By("waiting for assertion recovering") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + _, err := getPodHttpNoBody(c, port) + + // abort recovered + if err != nil { + return false, nil + } + return true, nil + }) + framework.ExpectNoError(err, "fail to recover http chaos") +} + +func TestcaseHttpAbortPauseAndUnPause( + ns string, + cli client.Client, + c HTTPE2EClient, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("waiting on e2e helper ready") + err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + By("create http abort chaos CRD objects") + + abort := true + + httpChaos := &v1alpha1.HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-chaos", + Namespace: ns, + }, + Spec: v1alpha1.HTTPChaosSpec{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "http"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + Port: 8080, + Target: "Request", + PodHttpChaosActions: v1alpha1.PodHttpChaosActions{ + Abort: &abort, + }, + }, + } + + err = cli.Create(ctx, httpChaos) + framework.ExpectNoError(err, "error occurs while applying http chaos") + + chaosKey := types.NamespacedName{ + Namespace: ns, + Name: "http-chaos", + } + + By("waiting for assertion http chaos") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllInjected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + _, err := getPodHttpNoBody(c, port) + + // abort applied + if err != nil { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "http chaos doesn't work as expected") + + By("pause http abort chaos experiment") + // pause experiment + err = util.PauseChaos(ctx, cli, httpChaos) + framework.ExpectNoError(err, "pause chaos error") + + By("waiting for assertion about pause") + err = wait.Poll(1*time.Second, 1*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllRecovered { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + return true, err + }) + framework.ExpectNoError(err, "check paused chaos failed") + + // wait 1 min to check whether io delay still exists + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + _, err := getPodHttpNoBody(c, port) + + // abort recovered + if err != nil { + return false, nil + } + return true, nil + }) + framework.ExpectNoError(err, "fail to recover http chaos") + By("resume http abort chaos experiment") + // resume experiment + err = util.UnPauseChaos(ctx, cli, httpChaos) + framework.ExpectNoError(err, "resume chaos error") + + By("assert that http abort is effective again") + err = wait.Poll(1*time.Second, 1*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllInjected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + return true, err + }) + framework.ExpectNoError(err, "check resumed chaos failed") + + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + _, err := getPodHttpNoBody(c, port) + + // abort applied + if err != nil { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "HTTP chaos doesn't work as expected") + + By("cleanup") + // cleanup + cli.Delete(ctx, httpChaos) +} diff --git a/e2e-test/e2e/chaos/httpchaos/http_delay.go b/e2e-test/e2e/chaos/httpchaos/http_delay.go new file mode 100644 index 0000000000..fe9cace401 --- /dev/null +++ b/e2e-test/e2e/chaos/httpchaos/http_delay.go @@ -0,0 +1,278 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package httpchaos + +import ( + "context" + "time" + + . "github.com/onsi/ginkgo/v2" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/klog/v2" + "k8s.io/kubernetes/test/e2e/framework" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" +) + +func TestcaseHttpDelayDurationForATimeThenRecover( + ns string, + cli client.Client, + c HTTPE2EClient, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("waiting on e2e helper ready") + err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + By("create http delay chaos CRD objects") + + delay := "1s" + + httpChaos := &v1alpha1.HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-chaos", + Namespace: ns, + }, + Spec: v1alpha1.HTTPChaosSpec{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "http"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + Port: 8080, + Target: "Request", + PodHttpChaosActions: v1alpha1.PodHttpChaosActions{ + Delay: &delay, + }, + }, + } + err = cli.Create(ctx, httpChaos) + framework.ExpectNoError(err, "create http chaos error") + + By("waiting for assertion HTTP delay") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, dur, err := getPodHttpDelay(c, port) + if err != nil { + return false, err + } + second := dur.Seconds() + klog.Infof("Status(%d): get http delay %fs", resp.StatusCode, second) + // IO Delay >= 1s + if second >= 1 { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "http chaos doesn't work as expected") + By("apply http chaos successfully") + + By("delete chaos CRD objects") + // delete chaos CRD + err = cli.Delete(ctx, httpChaos) + framework.ExpectNoError(err, "failed to delete http chaos") + + time.Sleep(time.Second * 5) + + By("waiting for assertion recovering") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, dur, err := getPodHttpDelay(c, port) + if err != nil { + return false, err + } + second := dur.Seconds() + klog.Infof("Status(%d): get http delay %fs", resp.StatusCode, second) + // IO Delay shouldn't longer than 1s + if second >= 1 { + return false, nil + } + return true, nil + }) + framework.ExpectNoError(err, "fail to recover http chaos") +} + +func TestcaseHttpDelayDurationForATimePauseAndUnPause( + ns string, + cli client.Client, + c HTTPE2EClient, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("waiting on e2e helper ready") + err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + By("create http delay chaos CRD objects") + + delay := "1s" + + httpChaos := &v1alpha1.HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-chaos", + Namespace: ns, + }, + Spec: v1alpha1.HTTPChaosSpec{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "http"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + Port: 8080, + Target: "Request", + PodHttpChaosActions: v1alpha1.PodHttpChaosActions{ + Delay: &delay, + }, + }, + } + + err = cli.Create(ctx, httpChaos) + framework.ExpectNoError(err, "error occurs while applying http chaos") + + chaosKey := types.NamespacedName{ + Namespace: ns, + Name: "http-chaos", + } + + By("waiting for assertion http chaos") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllInjected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + _, dur, _ := getPodHttpDelay(c, port) + + s := dur.Seconds() + klog.Infof("get http delay %fs", s) + // HTTP Delay >= 1s + if s >= 1 { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "http chaos doesn't work as expected") + + By("pause http delay chaos experiment") + // pause experiment + err = util.PauseChaos(ctx, cli, httpChaos) + framework.ExpectNoError(err, "pause chaos error") + + By("waiting for assertion about pause") + err = wait.Poll(1*time.Second, 1*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllRecovered { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + return true, err + }) + framework.ExpectNoError(err, "check paused chaos failed") + + // wait 1 min to check whether io delay still exists + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + _, dur, _ := getPodHttpDelay(c, port) + + s := dur.Seconds() + klog.Infof("get http delay %fs", s) + // HTTP Delay >= 1s + if s >= 1 { + return false, nil + } + return true, nil + }) + framework.ExpectNoError(err, "fail to recover http chaos") + + By("resume http delay chaos experiment") + // resume experiment + err = util.UnPauseChaos(ctx, cli, httpChaos) + framework.ExpectNoError(err, "resume chaos error") + + By("assert that http delay is effective again") + err = wait.Poll(1*time.Second, 1*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllInjected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + return true, err + }) + framework.ExpectNoError(err, "check resumed chaos failed") + + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + _, dur, _ := getPodHttpDelay(c, port) + + s := dur.Seconds() + klog.Infof("get http delay %fs", s) + // HTTP Delay >= 1s + if s >= 1 { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "HTTP chaos doesn't work as expected") + + By("cleanup") + // cleanup + cli.Delete(ctx, httpChaos) +} diff --git a/e2e-test/e2e/chaos/httpchaos/http_graceful_shutdown.go b/e2e-test/e2e/chaos/httpchaos/http_graceful_shutdown.go new file mode 100644 index 0000000000..580f0787f9 --- /dev/null +++ b/e2e-test/e2e/chaos/httpchaos/http_graceful_shutdown.go @@ -0,0 +1,112 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package httpchaos + +import ( + "context" + "time" + + . "github.com/onsi/ginkgo/v2" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/kubernetes/test/e2e/framework" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + test "github.com/chaos-mesh/chaos-mesh/e2e-test" + e2econfig "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/config" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" +) + +func TestcaseHttpGracefulAbortShutdown( + ns string, + cli client.Client, + c HTTPE2EClient, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("waiting on e2e helper ready") + err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + By("create http abort chaos CRD objects") + + abort := true + + httpChaos := &v1alpha1.HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-chaos", + Namespace: ns, + }, + Spec: v1alpha1.HTTPChaosSpec{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "http"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + Port: 8080, + Target: "Request", + PodHttpChaosActions: v1alpha1.PodHttpChaosActions{ + Abort: &abort, + }, + }, + } + err = cli.Create(ctx, httpChaos) + framework.ExpectNoError(err, "create http chaos error") + + defer func() { + err = cli.Delete(ctx, httpChaos) + framework.ExpectNoError(err, "delete http chaos") + }() + + By("waiting for assertion HTTP abort") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + _, err := getPodHttpNoBody(c, port) + + // abort applied + if err != nil { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "http chaos doesn't work as expected") + By("apply http chaos successfully") + + By("upgrade chaos mesh") + // Get clients + oa, ocfg, err := test.BuildOperatorActionAndCfg(e2econfig.TestConfig) + framework.ExpectNoError(err, "failed to create operator action") + err = oa.RestartDaemon(ocfg) + framework.ExpectNoError(err, "failed to restart chaos daemon") + + By("waiting for assertion chaos recovered") + err = wait.PollImmediate(5*time.Second, 2*time.Minute, func() (bool, error) { + _, err := getPodHttpNoBody(c, port) + + // abort recovered + if err == nil { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "http chaos doesn't gracefully shutdown as expected") + By("http chaos shutdown successfully") +} diff --git a/e2e-test/e2e/chaos/httpchaos/http_patch.go b/e2e-test/e2e/chaos/httpchaos/http_patch.go new file mode 100644 index 0000000000..55cfa826ae --- /dev/null +++ b/e2e-test/e2e/chaos/httpchaos/http_patch.go @@ -0,0 +1,395 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package httpchaos + +import ( + "context" + "io" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/klog/v2" + "k8s.io/kubernetes/test/e2e/framework" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" +) + +func TestcaseHttpPatchThenRecover( + ns string, + cli client.Client, + c HTTPE2EClient, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("waiting on e2e helper ready") + err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + + body := `{"msg":"Hello","target":"World"}` + secret := "Bar" + + By("waiting for assertion normal behaviour") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, body) + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := strings.Join(resp.Header[SECRET], "; ") + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == secret && string(b) == body { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "helper server doesn't work as expected") + By("deploy helper server successfully") + + By("create http patch chaos CRD objects") + + patchbody := `{"target": "Chaos Mesh"}` + patchSecret := "Foo!" + expectedSecret := "Bar; Foo!" + expectedBody := `{"msg":"Hello","target":"Chaos Mesh"}` + + httpChaos := &v1alpha1.HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-chaos", + Namespace: ns, + }, + Spec: v1alpha1.HTTPChaosSpec{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "http"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + Port: 8080, + Target: "Request", + PodHttpChaosActions: v1alpha1.PodHttpChaosActions{ + Patch: &v1alpha1.PodHttpChaosPatchActions{ + Headers: [][]string{ + {SECRET, patchSecret}, + }, + Body: &v1alpha1.PodHttpChaosPatchBodyAction{ + Type: "JSON", + Value: patchbody, + }, + }, + }, + }, + } + err = cli.Create(ctx, httpChaos) + framework.ExpectNoError(err, "create http chaos error") + + By("waiting for assertion HTTP patch") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, body) + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := strings.Join(resp.Header[SECRET], "; ") + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == expectedSecret && string(b) == expectedBody { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "http chaos doesn't work as expected") + By("apply http chaos successfully") + + By("delete chaos CRD objects") + // delete chaos CRD + err = cli.Delete(ctx, httpChaos) + framework.ExpectNoError(err, "failed to delete http chaos") + + By("waiting for assertion recovering") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, body) + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := strings.Join(resp.Header[SECRET], "; ") + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == secret && string(b) == body { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "fail to recover http chaos") +} + +func TestcaseHttpPatchPauseAndUnPause( + ns string, + cli client.Client, + c HTTPE2EClient, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("waiting on e2e helper ready") + err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + + body := `{"msg":"Hello","target":"World"}` + secret := "Bar" + + By("waiting for assertion normal behaviour") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, body) + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := strings.Join(resp.Header[SECRET], "; ") + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == secret && string(b) == body { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "helper server doesn't work as expected") + By("deploy helper server successfully") + + By("create http patch chaos CRD objects") + patchbody := `{"target": "Chaos Mesh"}` + patchSecret := "Foo!" + expectedSecret := "Bar; Foo!" + expectedBody := `{"msg":"Hello","target":"Chaos Mesh"}` + + httpChaos := &v1alpha1.HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-chaos", + Namespace: ns, + }, + Spec: v1alpha1.HTTPChaosSpec{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "http"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + Port: 8080, + Target: "Request", + PodHttpChaosActions: v1alpha1.PodHttpChaosActions{ + Patch: &v1alpha1.PodHttpChaosPatchActions{ + Headers: [][]string{ + {SECRET, patchSecret}, + }, + Body: &v1alpha1.PodHttpChaosPatchBodyAction{ + Type: "JSON", + Value: patchbody, + }, + }, + }, + }, + } + err = cli.Create(ctx, httpChaos) + framework.ExpectNoError(err, "create http chaos error") + + chaosKey := types.NamespacedName{ + Namespace: ns, + Name: "http-chaos", + } + + By("waiting for assertion http chaos") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllInjected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + resp, err := getPodHttp(c, port, secret, body) + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := strings.Join(resp.Header[SECRET], "; ") + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == expectedSecret && string(b) == expectedBody { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "http chaos doesn't work as expected") + + By("pause http patch chaos experiment") + // pause experiment + err = util.PauseChaos(ctx, cli, httpChaos) + framework.ExpectNoError(err, "pause chaos error") + + By("waiting for assertion about pause") + err = wait.Poll(1*time.Second, 1*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllRecovered { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + return true, err + }) + framework.ExpectNoError(err, "check paused chaos failed") + + // wait 1 min to check whether io patch still exists + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, body) + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := strings.Join(resp.Header[SECRET], "; ") + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == secret && string(b) == body { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "fail to recover http chaos") + + By("resume http patch chaos experiment") + // resume experiment + err = util.UnPauseChaos(ctx, cli, httpChaos) + framework.ExpectNoError(err, "resume chaos error") + + By("assert that http patch is effective again") + err = wait.Poll(1*time.Second, 1*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllInjected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + return true, err + }) + framework.ExpectNoError(err, "check resumed chaos failed") + + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, body) + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := strings.Join(resp.Header[SECRET], "; ") + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == expectedSecret && string(b) == expectedBody { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "HTTP chaos doesn't work as expected") + + By("cleanup") + // cleanup + cli.Delete(ctx, httpChaos) +} diff --git a/e2e-test/e2e/chaos/httpchaos/http_replace.go b/e2e-test/e2e/chaos/httpchaos/http_replace.go new file mode 100644 index 0000000000..c0b189eb34 --- /dev/null +++ b/e2e-test/e2e/chaos/httpchaos/http_replace.go @@ -0,0 +1,724 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package httpchaos + +import ( + "context" + "io" + "time" + + . "github.com/onsi/ginkgo/v2" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/klog/v2" + "k8s.io/kubernetes/test/e2e/framework" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" +) + +func TestcaseHttpReplaceThenRecover( + ns string, + cli client.Client, + c HTTPE2EClient, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("waiting on e2e helper ready") + err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + + secret := "Bar" + + By("waiting for assertion normal behaviour") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, "") + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := resp.Header.Get(SECRET) + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == secret { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "helper server doesn't work as expected") + By("deploy helper server successfully") + + By("create http replace chaos CRD objects") + replaceSecret := "Foo!" + + httpChaos := &v1alpha1.HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-chaos", + Namespace: ns, + }, + Spec: v1alpha1.HTTPChaosSpec{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "http"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + Port: 8080, + Target: "Request", + PodHttpChaosActions: v1alpha1.PodHttpChaosActions{ + Replace: &v1alpha1.PodHttpChaosReplaceActions{ + Headers: map[string]string{ + SECRET: replaceSecret, + }, + }, + }, + }, + } + err = cli.Create(ctx, httpChaos) + framework.ExpectNoError(err, "create http chaos error") + + By("waiting for assertion HTTP replace") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, "") + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := resp.Header.Get(SECRET) + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == replaceSecret { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "http chaos doesn't work as expected") + By("apply http chaos successfully") + + By("delete chaos CRD objects") + // delete chaos CRD + err = cli.Delete(ctx, httpChaos) + framework.ExpectNoError(err, "failed to delete http chaos") + + By("waiting for assertion recovering") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, "") + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := resp.Header.Get(SECRET) + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == secret { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "fail to recover http chaos") +} + +func TestcaseHttpReplacePauseAndUnPause( + ns string, + cli client.Client, + c HTTPE2EClient, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("waiting on e2e helper ready") + err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + + secret := "Bar" + + By("waiting for assertion normal behaviour") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, "") + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := resp.Header.Get(SECRET) + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == secret { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "helper server doesn't work as expected") + By("deploy helper server successfully") + + By("create http replace chaos CRD objects") + replaceSecret := "Foo!" + + httpChaos := &v1alpha1.HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-chaos", + Namespace: ns, + }, + Spec: v1alpha1.HTTPChaosSpec{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "http"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + Port: 8080, + Target: "Request", + PodHttpChaosActions: v1alpha1.PodHttpChaosActions{ + Replace: &v1alpha1.PodHttpChaosReplaceActions{ + Headers: map[string]string{ + SECRET: replaceSecret, + }, + }, + }, + }, + } + err = cli.Create(ctx, httpChaos) + framework.ExpectNoError(err, "create http chaos error") + + chaosKey := types.NamespacedName{ + Namespace: ns, + Name: "http-chaos", + } + + By("waiting for assertion http chaos") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllInjected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + resp, err := getPodHttp(c, port, secret, "") + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := resp.Header.Get(SECRET) + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == replaceSecret { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "http chaos doesn't work as expected") + + By("pause http replace chaos experiment") + // pause experiment + err = util.PauseChaos(ctx, cli, httpChaos) + framework.ExpectNoError(err, "pause chaos error") + + By("waiting for assertion about pause") + err = wait.Poll(1*time.Second, 1*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllRecovered { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + return true, err + }) + framework.ExpectNoError(err, "check paused chaos failed") + + // wait 1 min to check whether io replace still exists + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, "") + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := resp.Header.Get(SECRET) + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == secret { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "fail to recover http chaos") + By("resume http replace chaos experiment") + // resume experiment + err = util.UnPauseChaos(ctx, cli, httpChaos) + framework.ExpectNoError(err, "resume chaos error") + + By("assert that http replace is effective again") + err = wait.Poll(1*time.Second, 1*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllInjected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + return true, err + }) + framework.ExpectNoError(err, "check resumed chaos failed") + + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, "") + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := resp.Header.Get(SECRET) + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == replaceSecret { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "HTTP chaos doesn't work as expected") + + By("cleanup") + // cleanup + cli.Delete(ctx, httpChaos) +} + +func TestcaseHttpReplaceBodyThenRecover( + ns string, + cli client.Client, + c HTTPE2EClient, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("waiting on e2e helper ready") + err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + + body := "Hello World" + secret := "Bar" + + By("waiting for assertion normal behaviour") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, body) + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := resp.Header.Get(SECRET) + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == secret && string(b) == body { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "helper server doesn't work as expected") + By("deploy helper server successfully") + + By("create http replace chaos CRD objects") + replacebody := "Hello Chaos Mesh" + replaceSecret := "Foo!" + + httpChaos := &v1alpha1.HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-chaos", + Namespace: ns, + }, + Spec: v1alpha1.HTTPChaosSpec{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "http"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + Port: 8080, + Target: "Request", + PodHttpChaosActions: v1alpha1.PodHttpChaosActions{ + Replace: &v1alpha1.PodHttpChaosReplaceActions{ + Headers: map[string]string{ + SECRET: replaceSecret, + }, + Body: []byte(replacebody), + }, + }, + }, + } + err = cli.Create(ctx, httpChaos) + framework.ExpectNoError(err, "create http chaos error") + + By("waiting for assertion HTTP replace") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, body) + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := resp.Header.Get(SECRET) + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == replaceSecret && string(b) == replacebody { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "http chaos doesn't work as expected") + By("apply http chaos successfully") + + By("delete chaos CRD objects") + // delete chaos CRD + err = cli.Delete(ctx, httpChaos) + framework.ExpectNoError(err, "failed to delete http chaos") + + By("waiting for assertion recovering") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, body) + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := resp.Header.Get(SECRET) + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == secret && string(b) == body { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "fail to recover http chaos") +} + +func TestcaseHttpReplaceBodyPauseAndUnPause( + ns string, + cli client.Client, + c HTTPE2EClient, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("waiting on e2e helper ready") + err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + + body := "Hello World" + secret := "Bar" + + By("waiting for assertion normal behaviour") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, body) + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := resp.Header.Get(SECRET) + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == secret && string(b) == body { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "helper server doesn't work as expected") + By("deploy helper server successfully") + + By("create http replace chaos CRD objects") + replacebody := "Hello Chaos Mesh" + replaceSecret := "Foo!" + + httpChaos := &v1alpha1.HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-chaos", + Namespace: ns, + }, + Spec: v1alpha1.HTTPChaosSpec{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "http"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + Port: 8080, + Target: "Request", + PodHttpChaosActions: v1alpha1.PodHttpChaosActions{ + Replace: &v1alpha1.PodHttpChaosReplaceActions{ + Headers: map[string]string{ + SECRET: replaceSecret, + }, + Body: []byte(replacebody), + }, + }, + }, + } + err = cli.Create(ctx, httpChaos) + framework.ExpectNoError(err, "create http chaos error") + + chaosKey := types.NamespacedName{ + Namespace: ns, + Name: "http-chaos", + } + + By("waiting for assertion http chaos") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllInjected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + resp, err := getPodHttp(c, port, secret, body) + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := resp.Header.Get(SECRET) + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == replaceSecret && string(b) == replacebody { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "http chaos doesn't work as expected") + + By("pause http replace chaos experiment") + // pause experiment + err = util.PauseChaos(ctx, cli, httpChaos) + framework.ExpectNoError(err, "pause chaos error") + + By("waiting for assertion about pause") + err = wait.Poll(1*time.Second, 1*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllRecovered { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + return true, err + }) + framework.ExpectNoError(err, "check paused chaos failed") + + // wait 1 min to check whether io replace still exists + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, body) + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := resp.Header.Get(SECRET) + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == secret && string(b) == body { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "fail to recover http chaos") + By("resume http replace chaos experiment") + // resume experiment + err = util.UnPauseChaos(ctx, cli, httpChaos) + framework.ExpectNoError(err, "resume chaos error") + + By("assert that http replace is effective again") + err = wait.Poll(1*time.Second, 1*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.HTTPChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get http chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllInjected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + return true, err + }) + framework.ExpectNoError(err, "check resumed chaos failed") + + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + resp, err := getPodHttp(c, port, secret, body) + if err != nil { + return false, err + } + defer resp.Body.Close() + + s := resp.Header.Get(SECRET) + b, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + klog.Infof("Status(%d), Secret(%s), Body(%s)", resp.StatusCode, s, string(b)) + + if s == replaceSecret && string(b) == replacebody { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "HTTP chaos doesn't work as expected") + + By("cleanup") + // cleanup + cli.Delete(ctx, httpChaos) +} diff --git a/e2e-test/e2e/chaos/httpchaos/http_tls.go b/e2e-test/e2e/chaos/httpchaos/http_tls.go new file mode 100644 index 0000000000..209fa11c4a --- /dev/null +++ b/e2e-test/e2e/chaos/httpchaos/http_tls.go @@ -0,0 +1,193 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package httpchaos + +import ( + "context" + "crypto/tls" + "crypto/x509" + "embed" + "encoding/json" + "fmt" + "net/http" + "os" + "os/exec" + "time" + + . "github.com/onsi/ginkgo/v2" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" + "k8s.io/kubernetes/test/e2e/framework" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" +) + +//go:embed keys +var content embed.FS + +type TLSServerKeys struct { + Cert []byte `json:"cert"` + Key []byte `json:"key"` +} + +func setupHTTPS(cli *http.Client, serverIP string) (TLSServerKeys, []byte) { + c, err := content.ReadDir("keys") + framework.ExpectNoError(err, "read key dir error") + var key []byte + var ca []byte + for _, f := range c { + if f.IsDir() { + continue + } + b, err := content.ReadFile("keys/" + f.Name()) + framework.ExpectNoError(err, "read key file error") + switch f.Name() { + case "server.key": + key = b + case "ca.crt": + ca = b + } + err = os.WriteFile(f.Name(), b, 0644) + framework.ExpectNoError(err, "write key file error") + } + + f, err := os.OpenFile("server.ext", os.O_APPEND|os.O_WRONLY, 0644) + if err != nil { + framework.ExpectNoError(err, "open server.ext file error") + } + if _, err = f.WriteString(fmt.Sprint("IP.1 = " + serverIP)); err != nil { + framework.ExpectNoError(err, "write server.ext file error") + } + err = f.Close() + framework.ExpectNoError(err, "close server.ext file error") + + cmdStr := "openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650 -sha256 -extfile server.ext" + cmd := exec.Command("bash", "-c", cmdStr) + output, err := cmd.CombinedOutput() + if err != nil { + framework.ExpectNoError(err, "run openssl cmd error: "+string(output)) + } + crt, err := os.ReadFile("server.crt") + framework.ExpectNoError(err, "read server.crt file error") + + roots := x509.NewCertPool() + caPk, err := os.ReadFile("ca.crt") + if err != nil { + panic(err) + } + ok := roots.AppendCertsFromPEM(caPk) + framework.ExpectEqual(ok, true, "failed to parse root certificate") + + cli.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: roots, + }, + } + + return TLSServerKeys{ + Cert: crt, + Key: key, + }, ca +} + +func TestcaseHttpTLSThenRecover( + ns string, + kubeCli kubernetes.Interface, + cli client.Client, + c HTTPE2EClient, + port uint16, + tlsPort uint16, +) { + serverKeys, ca := setupHTTPS(c.C, c.IP) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("waiting on e2e helper ready") + err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + By("create http delay chaos CRD objects") + + body, err := json.Marshal(serverKeys) + framework.ExpectNoError(err, "marshal server keys error") + err = util.SetupHTTPE2EHelperTLSConfig(*c.C, c.IP, port, tlsPort, body) + framework.ExpectNoError(err, "setup e2e helper tls config error") + delay := "1ms" + + _, err = kubeCli.CoreV1().Secrets(ns).Create(ctx, &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-tls", + Namespace: ns, + }, + Data: map[string][]byte{ + "ca.crt": ca, + "server.crt": serverKeys.Cert, + "server.key": serverKeys.Key, + }, + }, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create secret error") + caName := "ca.crt" + httpChaos := &v1alpha1.HTTPChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-chaos", + Namespace: ns, + }, + Spec: v1alpha1.HTTPChaosSpec{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "http"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + Port: 8081, + Target: "Request", + PodHttpChaosActions: v1alpha1.PodHttpChaosActions{ + Delay: &delay, + }, + TLS: &v1alpha1.PodHttpChaosTLS{ + SecretName: "http-tls", + SecretNamespace: ns, + CertName: "server.crt", + KeyName: "server.key", + CAName: &caName, + }, + }, + } + err = cli.Create(ctx, httpChaos) + framework.ExpectNoError(err, "create http chaos error") + + By("waiting for HTTP pong") + err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { + err := util.WaitHTTPE2EHelperTLSReady(*c.C, c.IP, tlsPort) + if err != nil { + return false, err + } + return true, nil + }) + framework.ExpectNoError(err, "http chaos doesn't work as expected") + By("apply http chaos successfully") + + By("delete chaos CRD objects") + // delete chaos CRD + err = cli.Delete(ctx, httpChaos) + framework.ExpectNoError(err, "failed to delete http chaos") +} diff --git a/e2e-test/e2e/chaos/httpchaos/keys/ca.crt b/e2e-test/e2e/chaos/httpchaos/keys/ca.crt new file mode 100644 index 0000000000..a9c9b93a2e --- /dev/null +++ b/e2e-test/e2e/chaos/httpchaos/keys/ca.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDjTCCAnWgAwIBAgIUJLVy8EzjPmicdZYIEzY/HoZXk6AwDQYJKoZIhvcNAQEL +BQAwVjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAwwGYW5kcmV3MB4XDTIy +MDkxODIyMDAzMVoXDTMyMDkxNTIyMDAzMVowVjELMAkGA1UEBhMCQVUxEzARBgNV +BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 +ZDEPMA0GA1UEAwwGYW5kcmV3MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA380jUBTIbuZhtAMkZroUUTU1hIY0kqn0X2bX6Y3CTFoCrTOtHh4oqH1N1XEI +H9WO19uyMy1Wyb5jBIUHsj1l9NRfwL+F+QS8np4mCJm5lS/LgRsDJQHKgRKxovSh +DjkwRDPMyaQm6gkEdl6n77AR68jCYfuscXebCJ6LQvYb+HebMXszWWRowQ3xvaf8 +2NFTxXcMStXtLK+Dv38aIl7M2edWOosMMW0Y0tw+D/c2SBYPUZAP6AY/GxWuPPn8 +7IyISe/FlI4nw7xSiEwHsHWvgMBWDsdSw0zeI4KzSbl7NLvdByMulTKjeWcdkFzS +3ML4qDKto68BzrauTyq2woWHtQIDAQABo1MwUTAdBgNVHQ4EFgQUVUmOdlB1BMSj +rkSl+9t0q/1ykaQwHwYDVR0jBBgwFoAUVUmOdlB1BMSjrkSl+9t0q/1ykaQwDwYD +VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAMmF9COWaV/Kpl7hEArib +cZlNr17NPGXTApS74ZTO0AstEB5mntjtPVtTlaDt/VccNMNJkvloIhhQ9yRC6778 +A9RWO1WJbfRlBYhyUY/afK4DqX5zXMIa7kVjRT09umGIKlSaL+cpmBf9jwTLuE85 +9WlVaanOPrxdo/ELl4JJ+iUlpXtwxsVkiVL9edAoTk4yXZXaMDt3d063dk/eqhQU +H5doRAfU8IYGd6QFZIoqOnrOU7ipBnXve+I0rjSMZJBCPdX7HthVSsGHoEcJBQ9C +DUByGuKP9/lj5UGls0ODy2fzDcSCuxNjeJ/uXD23DmzxzBZpGPwt1SJrChxlUexd +7g== +-----END CERTIFICATE----- diff --git a/e2e-test/e2e/chaos/httpchaos/keys/ca.key b/e2e-test/e2e/chaos/httpchaos/keys/ca.key new file mode 100644 index 0000000000..e22d77a06d --- /dev/null +++ b/e2e-test/e2e/chaos/httpchaos/keys/ca.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDfzSNQFMhu5mG0 +AyRmuhRRNTWEhjSSqfRfZtfpjcJMWgKtM60eHiiofU3VcQgf1Y7X27IzLVbJvmME +hQeyPWX01F/Av4X5BLyeniYImbmVL8uBGwMlAcqBErGi9KEOOTBEM8zJpCbqCQR2 +XqfvsBHryMJh+6xxd5sInotC9hv4d5sxezNZZGjBDfG9p/zY0VPFdwxK1e0sr4O/ +fxoiXszZ51Y6iwwxbRjS3D4P9zZIFg9RkA/oBj8bFa48+fzsjIhJ78WUjifDvFKI +TAewda+AwFYOx1LDTN4jgrNJuXs0u90HIy6VMqN5Zx2QXNLcwvioMq2jrwHOtq5P +KrbChYe1AgMBAAECggEAY0xLfL6b58jEVPCH+CRb22Q2aKR7Mw/BY4roBbJmISZW +xa6GAzTyaT+fhzJtnmJMzK2ntVlKhpy4pkq4DXd8g1KvYYAY21IktmQJEAvU8cKR +Eql/ja3rwbUfp+POidcJ+VjaZiU1NuXlWvfIn2qJqQocZQkbjAS7fumJdJ5p7qWe +fraL/an8pVvXOWS89VXM3sMqbjgVa2BRCcDEo4Y03TI6hJqwr3M1Ehg9yzd3Webn +q3sSdWzPxCDmvhrHBpqdiPfNMn3bxI+m45Bb66139yiLCNpovCEGivU0L603BeHK +f5sOs/4eZSAQDBy4sCzHj4idxak1q5N4EMCS5BeQAQKBgQDz53H1/7cWjWHWZ9di +PPRdg4MxXVliYRt3pBb/f3ex4QGQFpcCRIm7OGbqs3Dy/js3ud0Xt5Vv8bwJJDgV +5cl0rNdlj9XBfAODJhYeK0Og0Rx9OOQJszFAJR9tJdpOxUBzqm3o6c3HhQCCQMcW +LItU2OQRNB5uVb4UWXEsRCcOAQKBgQDq5njreNxUy8OpMMSyrZZn1zazmOTfJDNk +9JnKM4ag9JLzCHTzqvcm+PKothWV3+yKsiO2fXayhd+Ucs7aEo/6PpUSeJaJlIPD +OTnp6EezVMv9uqvKCREd8yf++qy9F3QVV8ynERJl/S7eHQavI9pAGA+dzohb7jqm +xsJUlxqhtQKBgDbzJNSkWO5mye0RFhBW5UMQNwVvH40vjY2l1VyYrjHQHJcGz9y9 +7j3U1jL4XHESX+sNH8eRH8TJtHBmzY/5Ziq4KgsCncjqlKv+b6s6WhEoK3/2ykF5 +MpZeBreDeKyYeg3VDtATpL3XtCakS3YucPGbr75EfLqk7J8PC5VKgXYBAoGBALhx +6BjdegSLS0Oaq5ixfRxkfOtg7rXYMxLejbOb6eaQpKJ4zXxXjmHnsIKRFznr7kyp +vCkbMwzS2dAypgHN+YfBhERQs8Or/hpY4QSuAz7pIpRE84dcvzgJKiqoouKHe/sW +SfgVC6FRwG9f01PKjyEsw3ZiKeglk6BJCWZqj9rRAoGBAJHUaulTyazLFfk8rumV +FnJf7OZzizC6yNRKpecJv42QfcyQgftishPUvkvppDaYjNfn2fLZ/HfE9pGvs8iH +NFV3i6E67APHki7I+HGM9oz525OMUpTgsifz61Flwx3SFA1MlU+qlyN8UDQAn43r +G+OJyM21xTn6lUeSR7OTMC+w +-----END PRIVATE KEY----- diff --git a/e2e-test/e2e/chaos/httpchaos/keys/server.crt b/e2e-test/e2e/chaos/httpchaos/keys/server.crt new file mode 100644 index 0000000000..5969731b7f --- /dev/null +++ b/e2e-test/e2e/chaos/httpchaos/keys/server.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDMzCCAhsCFFSUDRQ3zY9VlhMIpeByOxe4CytgMA0GCSqGSIb3DQEBCwUAMFYx +CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl +cm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMMBmFuZHJldzAeFw0yMjA5MTgy +MjE5MTZaFw0zMjA5MTUyMjE5MTZaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApT +b21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzAN +BgNVBAMMBmFuZHJldzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ0o +HbmpAiJu2rjQ+BOYi0nBG5U2PGt96yddoCOEA+arV6Css/XkYTzWEae51G7mNpPr +dMCMiQoNxY2W1pB+B2NWS2wCGxiaTMfsp+hStSaHubvEzYQlQXIZJjogZWXtxFPD +UfjhHnd0Ykf/oaoN4DWxi+sCFDkYzft5iX1qgbJUbxblGVQ/QXvJZoLr0xKwn5qe +dvOndkFcTGvGL0uyZ3jpbUnAqx28MEKC6BWP+IT19Mlj7BZOQn/YtCbB0uyoomfY +PI6Nb4dDaoaGRhIqKDONwcuapdix9wMyem2Bu0HdzC9BM4k2pEUn2WM/KmfrWY7n +yuPP1EVD4FqNwc1QtuMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAUTi0ub2j5wKf +t0Txw+fete8QpC7tFVJGhrNBnunbJ33RTSwnJLcaUBu1aWVaQPhLbR7LFkuleE9S +qb1I/oe3WZFqM9q/lqMXryymm0nJb5SvWK8BdaRdiJ65lfgbapf7ZBMGYDcNbW6V +2uTwNEQFmOJze/o584vJJaen8VG9K2zYAgmDLKYt1bInFosu20JfdhXguVNNsx1s +XMX6x0NsEgAGK/GgP9Ru0OK47rV2C0juS3S/QIByAK1O855v7pZmaJ8NVrvuSpmf +8spLhhjxQWnukXaoP6ZtfWylvigxFIJjcIASpiBplCb1W0Uos7FQ4ZQOaqeAGycb +Rkwy67b8jw== +-----END CERTIFICATE----- diff --git a/e2e-test/e2e/chaos/httpchaos/keys/server.csr b/e2e-test/e2e/chaos/httpchaos/keys/server.csr new file mode 100644 index 0000000000..8b5e211a46 --- /dev/null +++ b/e2e-test/e2e/chaos/httpchaos/keys/server.csr @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICmzCCAYMCAQAwVjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx +ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAwwGYW5k +cmV3MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnSgduakCIm7auND4 +E5iLScEblTY8a33rJ12gI4QD5qtXoKyz9eRhPNYRp7nUbuY2k+t0wIyJCg3FjZbW +kH4HY1ZLbAIbGJpMx+yn6FK1Joe5u8TNhCVBchkmOiBlZe3EU8NR+OEed3RiR/+h +qg3gNbGL6wIUORjN+3mJfWqBslRvFuUZVD9Be8lmguvTErCfmp5286d2QVxMa8Yv +S7JneOltScCrHbwwQoLoFY/4hPX0yWPsFk5Cf9i0JsHS7KiiZ9g8jo1vh0NqhoZG +EiooM43By5ql2LH3AzJ6bYG7Qd3ML0EziTakRSfZYz8qZ+tZjufK48/URUPgWo3B +zVC24wIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAEXLHKiwMJz4HN5NGwP2V29l +ZhLYA10J/BzIpqWyarG5pdZvuUSU1pEBd0xSFF9y7jGrFAVicvy/CsEYi18e5xPJ +9IGBZQtYYy9gRVaXSpBDkviMNXn0Kk47B38nsCHcq5uxU6V/G3yutWMDDeE4cXK0 +7p9kZOU8+lqb4+DjZz1EceQNi46SsSV1ldWu30RxJJeB+Q6NbUhIHtS3ZdOVEets +U6drkFQgs/VJSS6yQfJbm+2nch+KX0iLywcqsxaQekFqLFZmb1tON4iUWBoa3U7V +UqUFq4wc4//KpL75bxq3lhY7dY8SWbIshKBtryRgWC4Iw5rK8Yb6ZFJoSwSQc60= +-----END CERTIFICATE REQUEST----- diff --git a/e2e-test/e2e/chaos/httpchaos/keys/server.ext b/e2e-test/e2e/chaos/httpchaos/keys/server.ext new file mode 100644 index 0000000000..6083d960ed --- /dev/null +++ b/e2e-test/e2e/chaos/httpchaos/keys/server.ext @@ -0,0 +1,6 @@ +authorityKeyIdentifier=keyid,issuer +basicConstraints=CA:FALSE +keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment +subjectAltName = @alt_names + +[alt_names] diff --git a/e2e-test/e2e/chaos/httpchaos/keys/server.key b/e2e-test/e2e/chaos/httpchaos/keys/server.key new file mode 100644 index 0000000000..dddabf6ebe --- /dev/null +++ b/e2e-test/e2e/chaos/httpchaos/keys/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAnSgduakCIm7auND4E5iLScEblTY8a33rJ12gI4QD5qtXoKyz +9eRhPNYRp7nUbuY2k+t0wIyJCg3FjZbWkH4HY1ZLbAIbGJpMx+yn6FK1Joe5u8TN +hCVBchkmOiBlZe3EU8NR+OEed3RiR/+hqg3gNbGL6wIUORjN+3mJfWqBslRvFuUZ +VD9Be8lmguvTErCfmp5286d2QVxMa8YvS7JneOltScCrHbwwQoLoFY/4hPX0yWPs +Fk5Cf9i0JsHS7KiiZ9g8jo1vh0NqhoZGEiooM43By5ql2LH3AzJ6bYG7Qd3ML0Ez +iTakRSfZYz8qZ+tZjufK48/URUPgWo3BzVC24wIDAQABAoIBAH+VstQoTjBQGMdT +9yJJhEMDP/ZaCqEln8PcsYZDxbr9vW0W6B6nIv31uG2XYswJn6Nk0usC7Lo5xfkV +zOmPN0ZBJ4fvCbpmghEIoqPsiV5Xb8Ttl/9BE6mimzMzW75tUibCegj4Efjehm93 +K/LXwv80PagzjuFvrsIKwEEON27i8UCvPCwQMgZT4DBpxRyCvdBQFXr1/FFNdKJE +eJ0fsxOUcNILBaCAFim0B/2IEg7cal9VWA6YxY9vumsVSr9vFH5hkpw15flAxWw5 +M5SLxSPmthJzq0KUMJWOtsh5ApSG645k+hlQzkIxw6MNRi1ChHm1eQNwuOF2Arxy +TgKgDpkCgYEA0MLrEQQixHml7b0ndmW7JQQW4Oraem8ybpz9iNpcEtWtEfV9/jhI +vexOy3ZHqousX9fzAf4oDKp4n0MT58SiK7yd+PiWNHAQbmf+wqeZfdPBr5sX7Mfn +idyYI2g8brPK4tu1NTgwcyrGwAva+8Fc/SHmRs6brq/iYXubgKL54lUCgYEAwLfa +Yy2bDnNBIfXtIzqVZlOBPZexVcMr+Cq6TDy51oAzPxtefiFLP10nxYZuKzrN7Y3q +OhPVh2wj0TmdlEtUIKjhFNocE7ZBuC4HfOIkB/6iA1+1ag2wncSoL54gOvsCqY6X +iyyNiepHIHzJj6KQX6EU9fugalcP0qrIpsWVnFcCgYBQgSpXOIoTzHmhcZVbQiXm +Q2pzN/4iwujm4SGgedyR4tbIGyyIMbpTi2Jjcex3Jz/FAikTNqjJIaA8goiVky2a +wjUFQw/hjum3OeFzvWAittt1VdDnHbv7XRdKaDMN2cW+sE10BYQhlXhprOi4tzud +3knIOnqs5eTeBOXVuIO2tQKBgHrHZzoSfxvYr+FMBbWRCEe14bv03cUO3/9ucVxK +v/b5nCyTakMfQQpwdfsw5xVhlHrJFDXGFx789WDBvTQSPdnE3glj38lrLzmBEcIt +bNkvD9bobfLQH/qTpLcZnd0VuB+AOeowC0iXWpNHDT8WSbazMGB63DuDlhAYQFeH +wAZnAoGAObu6rVG58DvDiFFkQAe0icseLmS2gBG5Rc+ojcpAK6md+Yd2uyJ+N+DE +oD7b2S8ch5eJFgoHaZ3PtHMfZmi0hOWOPRm+iV0Birhhs1X2DN/S6CjIbCgqifYl +FlTgIflcJ611XzC0GxXUwFChc1QFY1dbWSkSTVDS+7siqAtL/Tk= +-----END RSA PRIVATE KEY----- diff --git a/e2e-test/e2e/chaos/httpchaos/misc.go b/e2e-test/e2e/chaos/httpchaos/misc.go new file mode 100644 index 0000000000..74b6e1980b --- /dev/null +++ b/e2e-test/e2e/chaos/httpchaos/misc.go @@ -0,0 +1,66 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package httpchaos + +import ( + "fmt" + "net/http" + "strings" + "time" +) + +const SECRET = "Secret" + +type HTTPE2EClient struct { + IP string + C *http.Client +} + +func getPodHttp(c HTTPE2EClient, port uint16, secret, body string) (*http.Response, error) { + request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d/http", c.IP, port), strings.NewReader(body)) + if err != nil { + return nil, err + } + request.Header.Set(SECRET, secret) + client := &http.Client{ + Transport: &http.Transport{}, + } + resp, err := client.Do(request) + return resp, err +} + +func getPodHttpNoSecret(c HTTPE2EClient, port uint16) (*http.Response, error) { + return getPodHttp(c, port, "", "") +} + +func getPodHttpDefaultSecret(c HTTPE2EClient, port uint16, body string) (*http.Response, error) { + return getPodHttp(c, port, "foo", body) +} + +func getPodHttpNoBody(c HTTPE2EClient, port uint16) (*http.Response, error) { + return getPodHttpDefaultSecret(c, port, "") +} + +// get pod http delay +func getPodHttpDelay(c HTTPE2EClient, port uint16) (*http.Response, time.Duration, error) { + start := time.Now() + resp, err := getPodHttpNoBody(c, port) + if err != nil { + return nil, 0, err + } + + return resp, time.Now().Sub(start), nil +} diff --git a/e2e-test/e2e/chaos/iochaos/io_delay.go b/e2e-test/e2e/chaos/iochaos/io_delay.go new file mode 100644 index 0000000000..4594fd0c5f --- /dev/null +++ b/e2e-test/e2e/chaos/iochaos/io_delay.go @@ -0,0 +1,393 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package iochaos + +import ( + "context" + "net/http" + "time" + + . "github.com/onsi/ginkgo/v2" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/klog/v2" + "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/utils/pointer" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" +) + +func TestcaseIODelayDurationForATimeThenRecover( + ns string, + cli client.Client, + c http.Client, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("waiting on e2e helper ready") + err := util.WaitE2EHelperReady(c, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + By("create IO delay chaos CRD objects") + ioChaos := &v1alpha1.IOChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "io-chaos", + Namespace: ns, + }, + Spec: v1alpha1.IOChaosSpec{ + Action: v1alpha1.IoLatency, + VolumePath: "/var/run/data", + Path: "/var/run/data/*", + Delay: "1s", + Percent: 100, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "io"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + }, + }, + } + err = cli.Create(ctx, ioChaos) + framework.ExpectNoError(err, "create io chaos error") + By("waiting for assertion IO delay") + err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { + dur, _ := getPodIODelay(c, port) + second := dur.Seconds() + klog.Infof("get io delay %fs", second) + // IO Delay >= 1s + if second >= 1 { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "io chaos doesn't work as expected") + By("apply io chaos successfully") + + By("delete chaos CRD objects") + // delete chaos CRD + err = cli.Delete(ctx, ioChaos) + framework.ExpectNoError(err, "failed to delete io chaos") + By("waiting for assertion recovering") + err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { + dur, _ := getPodIODelay(c, port) + second := dur.Seconds() + klog.Infof("get io delay %fs", second) + // IO Delay shouldn't longer than 1s + if second >= 1 { + return false, nil + } + return true, nil + }) + framework.ExpectNoError(err, "fail to recover io chaos") +} + +func TestcaseIODelayDurationForATimePauseAndUnPause( + ns string, + cli client.Client, + c http.Client, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + By("waiting for e2e helper ready") + err := util.WaitE2EHelperReady(c, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + + By("create io chaos crd object") + ioChaos := &v1alpha1.IOChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "io-chaos", + Namespace: ns, + }, + Spec: v1alpha1.IOChaosSpec{ + Action: v1alpha1.IoLatency, + VolumePath: "/var/run/data", + Path: "/var/run/data/*", + Delay: "10ms", + Percent: 100, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "io"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + }, + }, + } + err = cli.Create(ctx, ioChaos) + framework.ExpectNoError(err, "error occurs while applying io chaos") + + chaosKey := types.NamespacedName{ + Namespace: ns, + Name: "io-chaos", + } + + By("waiting for assertion io chaos") + err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { + chaos := &v1alpha1.IOChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get io chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllInjected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + dur, _ := getPodIODelay(c, port) + + ms := dur.Milliseconds() + klog.Infof("get io delay %dms", ms) + // IO Delay >= 500ms + if ms >= 10 { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "io chaos doesn't work as expected") + + By("pause io delay chaos experiment") + // pause experiment + err = util.PauseChaos(ctx, cli, ioChaos) + framework.ExpectNoError(err, "pause chaos error") + + By("waiting for assertion about pause") + err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.IOChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get io chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllRecovered { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + return true, err + }) + framework.ExpectNoError(err, "check paused chaos failed") + + // wait 1 min to check whether io delay still exists + err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { + dur, _ := getPodIODelay(c, port) + + ms := dur.Milliseconds() + klog.Infof("get io delay %dms", ms) + // IO Delay shouldn't longer than 10ms + if ms > 10 { + return false, nil + } + return true, nil + }) + framework.ExpectNoError(err, "fail to recover io chaos") + + By("resume io delay chaos experiment") + // resume experiment + err = util.UnPauseChaos(ctx, cli, ioChaos) + framework.ExpectNoError(err, "resume chaos error") + + By("assert that io delay is effective again") + err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.IOChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get io chaos error") + + for _, c := range chaos.GetStatus().Conditions { + if c.Type == v1alpha1.ConditionAllInjected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } else if c.Type == v1alpha1.ConditionSelected { + if c.Status != corev1.ConditionTrue { + return false, nil + } + } + } + + return true, err + }) + framework.ExpectNoError(err, "check resumed chaos failed") + + err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { + dur, _ := getPodIODelay(c, port) + + ms := dur.Milliseconds() + klog.Infof("get io delay %dms", ms) + // IO Delay >= 10ms + if ms >= 10 { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "io chaos doesn't work as expected") + + By("cleanup") + // cleanup + cli.Delete(ctx, ioChaos) +} + +func TestcaseIODelayWithSpecifiedContainer( + ns string, + cli client.Client, + c http.Client, + port uint16) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + err := util.WaitE2EHelperReady(c, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + + containerName := "io" + ioChaos := &v1alpha1.IOChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "io-chaos", + Namespace: ns, + }, + Spec: v1alpha1.IOChaosSpec{ + Action: v1alpha1.IoLatency, + VolumePath: "/var/run/data", + Path: "/var/run/data/*", + Delay: "10ms", + Percent: 100, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "io"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + ContainerNames: []string{containerName}, + }, + }, + } + err = cli.Create(ctx, ioChaos) + framework.ExpectNoError(err, "create io chaos error") + + err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { + dur, _ := getPodIODelay(c, port) + + ms := dur.Milliseconds() + klog.Infof("get io delay %dms", ms) + // IO Delay >= 10ms + if ms >= 10 { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "io chaos doesn't work as expected") + klog.Infof("apply io chaos successfully") + + err = cli.Delete(ctx, ioChaos) + framework.ExpectNoError(err, "failed to delete io chaos") + + err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { + dur, _ := getPodIODelay(c, port) + + ms := dur.Milliseconds() + klog.Infof("get io delay %dms", ms) + // IO Delay shouldn't longer than 10ms + if ms >= 10 { + return false, nil + } + return true, nil + }) + framework.ExpectNoError(err, "fail to recover io chaos") +} + +func TestcaseIODelayWithWrongSpec( + ns string, + cli client.Client, + c http.Client, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("waiting on e2e helper ready") + err := util.WaitE2EHelperReady(c, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + By("create IO delay chaos CRD objects") + ioChaos := &v1alpha1.IOChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "io-chaos", + Namespace: ns, + }, + Spec: v1alpha1.IOChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "io"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + }, + Action: v1alpha1.IoLatency, + VolumePath: "/var/run/data/123", + Path: "/var/run/data/*", + Delay: "1s", + Percent: 100, + Duration: pointer.StringPtr("9m"), + }, + } + err = cli.Create(ctx, ioChaos) + framework.ExpectNoError(err, "create io chaos error") + // TODO: resume the e2e test + // err = wait.PollImmediate(5*time.Second, 30*time.Second, func() (bool, error) { + // err := cli.Get(ctx, types.NamespacedName{Namespace: ioChaos.ObjectMeta.Namespace, Name: ioChaos.ObjectMeta.Name}, ioChaos) + // if err != nil { + // return false, err + // } + // errStr := ioChaos.Status.ChaosStatus.FailedMessage + // klog.Infof("get chaos err: %s", errStr) + // if strings.Contains(errStr, "Toda startup takes too long or an error occurs") { + // return true, nil + // } + // return false, nil + // }) + // framework.ExpectNoError(err, "A wrong chaos spec should raise an error") +} diff --git a/test/e2e/chaos/iochaos/io_error.go b/e2e-test/e2e/chaos/iochaos/io_error.go similarity index 77% rename from test/e2e/chaos/iochaos/io_error.go rename to e2e-test/e2e/chaos/iochaos/io_error.go index d32d7e08e6..94cddecf5c 100644 --- a/test/e2e/chaos/iochaos/io_error.go +++ b/e2e-test/e2e/chaos/iochaos/io_error.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package iochaos @@ -22,13 +24,12 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/klog" + "k8s.io/klog/v2" "k8s.io/kubernetes/test/e2e/framework" - "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/test/e2e/util" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" ) func TestcaseIOErrorDurationForATimeThenRecover( @@ -41,28 +42,30 @@ func TestcaseIOErrorDurationForATimeThenRecover( err := util.WaitE2EHelperReady(c, port) framework.ExpectNoError(err, "wait e2e helper ready error") - ioChaos := &v1alpha1.IoChaos{ + ioChaos := &v1alpha1.IOChaos{ ObjectMeta: metav1.ObjectMeta{ Name: "io-chaos", Namespace: ns, }, - Spec: v1alpha1.IoChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "io"}, - }, + Spec: v1alpha1.IOChaosSpec{ Action: v1alpha1.IoFaults, - Mode: v1alpha1.OnePodMode, VolumePath: "/var/run/data", Path: "/var/run/data/*", Percent: 100, // errno 5 is EIO -> I/O error Errno: 5, // only inject write method - Methods: []v1alpha1.IoMethod{v1alpha1.Write}, - Duration: pointer.StringPtr("9m"), - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", + Methods: []v1alpha1.IoMethod{v1alpha1.Write}, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "io"}, + }, + }, + Mode: v1alpha1.OneMode, + }, }, }, } @@ -106,28 +109,30 @@ func TestcaseIOErrorDurationForATimePauseAndUnPause( err := util.WaitE2EHelperReady(c, port) framework.ExpectNoError(err, "wait e2e helper ready error") - ioChaos := &v1alpha1.IoChaos{ + ioChaos := &v1alpha1.IOChaos{ ObjectMeta: metav1.ObjectMeta{ Name: "io-chaos", Namespace: ns, }, - Spec: v1alpha1.IoChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "io"}, - }, + Spec: v1alpha1.IOChaosSpec{ Action: v1alpha1.IoFaults, - Mode: v1alpha1.OnePodMode, VolumePath: "/var/run/data", Path: "/var/run/data/*", Percent: 100, // errno 5 is EIO -> I/O error Errno: 5, // only inject write method - Methods: []v1alpha1.IoMethod{v1alpha1.Write}, - Duration: pointer.StringPtr("9m"), - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", + Methods: []v1alpha1.IoMethod{v1alpha1.Write}, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "io"}, + }, + }, + Mode: v1alpha1.OneMode, + }, }, }, } @@ -158,10 +163,10 @@ func TestcaseIOErrorDurationForATimePauseAndUnPause( klog.Info("pause iochaos") err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - chaos := &v1alpha1.IoChaos{} + chaos := &v1alpha1.IOChaos{} err = cli.Get(ctx, chaosKey, chaos) framework.ExpectNoError(err, "get io chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhasePaused { + if chaos.Status.Experiment.DesiredPhase == v1alpha1.StoppedPhase { return true, nil } return false, err @@ -184,10 +189,10 @@ func TestcaseIOErrorDurationForATimePauseAndUnPause( framework.ExpectNoError(err, "resume chaos error") err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { - chaos := &v1alpha1.IoChaos{} + chaos := &v1alpha1.IOChaos{} err = cli.Get(ctx, chaosKey, chaos) framework.ExpectNoError(err, "get io chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhaseRunning { + if chaos.Status.Experiment.DesiredPhase == v1alpha1.RunningPhase { return true, nil } return false, err @@ -220,29 +225,31 @@ func TestcaseIOErrorWithSpecifiedContainer( framework.ExpectNoError(err, "wait e2e helper ready error") containerName := "io" - ioChaos := &v1alpha1.IoChaos{ + ioChaos := &v1alpha1.IOChaos{ ObjectMeta: metav1.ObjectMeta{ Name: "io-chaos", Namespace: ns, }, - Spec: v1alpha1.IoChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "io"}, - }, + Spec: v1alpha1.IOChaosSpec{ Action: v1alpha1.IoFaults, - Mode: v1alpha1.OnePodMode, VolumePath: "/var/run/data", Path: "/var/run/data/*", Percent: 100, // errno 5 is EIO -> I/O error Errno: 5, // only inject write method - ContainerName: &containerName, - Methods: []v1alpha1.IoMethod{v1alpha1.Write}, - Duration: pointer.StringPtr("9m"), - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", + Methods: []v1alpha1.IoMethod{v1alpha1.Write}, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "io"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + ContainerNames: []string{containerName}, }, }, } diff --git a/e2e-test/e2e/chaos/iochaos/io_graceful_shutdown.go b/e2e-test/e2e/chaos/iochaos/io_graceful_shutdown.go new file mode 100644 index 0000000000..e92150ab71 --- /dev/null +++ b/e2e-test/e2e/chaos/iochaos/io_graceful_shutdown.go @@ -0,0 +1,110 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package iochaos + +import ( + "context" + "net/http" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/kubernetes/test/e2e/framework" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + test "github.com/chaos-mesh/chaos-mesh/e2e-test" + e2econfig "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/config" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" +) + +func TestcaseIOErrorGracefulShutdown( + ns string, + cli client.Client, + c http.Client, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + err := util.WaitE2EHelperReady(c, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + + ioChaos := &v1alpha1.IOChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "io-chaos", + Namespace: ns, + }, + Spec: v1alpha1.IOChaosSpec{ + Action: v1alpha1.IoFaults, + VolumePath: "/var/run/data", + Path: "/var/run/data/*", + Percent: 100, + // errno 5 is EIO -> I/O error + Errno: 5, + // only inject write method + Methods: []v1alpha1.IoMethod{v1alpha1.Write}, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "io"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + }, + }, + } + err = cli.Create(ctx, ioChaos) + framework.ExpectNoError(err, "create io chaos") + + defer func() { + err = cli.Delete(ctx, ioChaos) + framework.ExpectNoError(err, "delete io chaos") + }() + + err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { + _, err = getPodIODelay(c, port) + // input/output error is errno 5 + if err != nil && strings.Contains(err.Error(), "input/output error") { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "io chaos doesn't work as expected") + + By("upgrade chaos mesh") + // Get clients + oa, ocfg, err := test.BuildOperatorActionAndCfg(e2econfig.TestConfig) + framework.ExpectNoError(err, "failed to create operator action") + err = oa.RestartDaemon(ocfg) + framework.ExpectNoError(err, "failed to restart chaos daemon") + + By("waiting for assertion IO error recovery") + err = wait.PollImmediate(5*time.Second, 2*time.Minute, func() (bool, error) { + _, err = getPodIODelay(c, port) + // recovered + if err == nil { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "io chaos doesn't gracefully shutdown as expected") + By("io chaos shutdown successfully") +} diff --git a/test/e2e/chaos/iochaos/io_mistake.go b/e2e-test/e2e/chaos/iochaos/io_mistake.go similarity index 80% rename from test/e2e/chaos/iochaos/io_mistake.go rename to e2e-test/e2e/chaos/iochaos/io_mistake.go index c275c577a8..9a539473d5 100644 --- a/test/e2e/chaos/iochaos/io_mistake.go +++ b/e2e-test/e2e/chaos/iochaos/io_mistake.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package iochaos @@ -21,13 +23,13 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/klog" + "k8s.io/klog/v2" "k8s.io/kubernetes/test/e2e/framework" "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/test/e2e/util" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" ) func TestcaseIOMistakeDurationForATimeThenRecover( @@ -41,18 +43,24 @@ func TestcaseIOMistakeDurationForATimeThenRecover( err := util.WaitE2EHelperReady(c, port) framework.ExpectNoError(err, "wait e2e helper ready error") - ioChaos := &v1alpha1.IoChaos{ + ioChaos := &v1alpha1.IOChaos{ ObjectMeta: metav1.ObjectMeta{ Name: "io-chaos", Namespace: ns, }, - Spec: v1alpha1.IoChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "io"}, + Spec: v1alpha1.IOChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "io"}, + }, + }, + Mode: v1alpha1.OneMode, + }, }, Action: v1alpha1.IoMistake, - Mode: v1alpha1.OnePodMode, VolumePath: "/var/run/data", Path: "/var/run/data/*", Percent: 100, @@ -64,9 +72,6 @@ func TestcaseIOMistakeDurationForATimeThenRecover( // only inject read or write method. Other method may or may not run properly, but is not recommended Methods: []v1alpha1.IoMethod{v1alpha1.Read, v1alpha1.Write}, Duration: pointer.StringPtr("9m"), - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", - }, }, } err = cli.Create(ctx, ioChaos) @@ -112,18 +117,24 @@ func TestcaseIOMistakeDurationForATimePauseAndUnPause( err := util.WaitE2EHelperReady(c, port) framework.ExpectNoError(err, "wait e2e helper ready error") - ioChaos := &v1alpha1.IoChaos{ + ioChaos := &v1alpha1.IOChaos{ ObjectMeta: metav1.ObjectMeta{ Name: "io-chaos", Namespace: ns, }, - Spec: v1alpha1.IoChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "io"}, + Spec: v1alpha1.IOChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "io"}, + }, + }, + Mode: v1alpha1.OneMode, + }, }, Action: v1alpha1.IoMistake, - Mode: v1alpha1.OnePodMode, VolumePath: "/var/run/data", Path: "/var/run/data/*", Percent: 100, @@ -135,9 +146,6 @@ func TestcaseIOMistakeDurationForATimePauseAndUnPause( // only inject read or write method. Other method may or may not run properly, but is not recommended Methods: []v1alpha1.IoMethod{v1alpha1.Read, v1alpha1.Write}, Duration: pointer.StringPtr("9m"), - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", - }, }, } err = cli.Create(ctx, ioChaos) @@ -169,10 +177,10 @@ func TestcaseIOMistakeDurationForATimePauseAndUnPause( klog.Info("pause iochaos") err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - chaos := &v1alpha1.IoChaos{} + chaos := &v1alpha1.IOChaos{} err = cli.Get(ctx, chaosKey, chaos) framework.ExpectNoError(err, "get io chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhasePaused { + if chaos.Status.Experiment.DesiredPhase == v1alpha1.StoppedPhase { return true, nil } return false, err @@ -197,10 +205,10 @@ func TestcaseIOMistakeDurationForATimePauseAndUnPause( framework.ExpectNoError(err, "resume chaos error") err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { - chaos := &v1alpha1.IoChaos{} + chaos := &v1alpha1.IOChaos{} err = cli.Get(ctx, chaosKey, chaos) framework.ExpectNoError(err, "get io chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhaseRunning { + if chaos.Status.Experiment.DesiredPhase == v1alpha1.RunningPhase { return true, nil } return false, err @@ -234,18 +242,25 @@ func TestcaseIOMistakeWithSpecifiedContainer( framework.ExpectNoError(err, "wait e2e helper ready error") containerName := "io" - ioChaos := &v1alpha1.IoChaos{ + ioChaos := &v1alpha1.IOChaos{ ObjectMeta: metav1.ObjectMeta{ Name: "io-chaos", Namespace: ns, }, - Spec: v1alpha1.IoChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "io"}, + Spec: v1alpha1.IOChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "io"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + ContainerNames: []string{containerName}, }, Action: v1alpha1.IoMistake, - Mode: v1alpha1.OnePodMode, VolumePath: "/var/run/data", Path: "/var/run/data/*", Percent: 100, @@ -254,13 +269,9 @@ func TestcaseIOMistakeWithSpecifiedContainer( MaxLength: 10000, Filling: v1alpha1.Zero, }, - ContainerName: &containerName, // only inject read or write method. Other method may or may not run properly, but is not recommended Methods: []v1alpha1.IoMethod{v1alpha1.Read, v1alpha1.Write}, Duration: pointer.StringPtr("9m"), - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", - }, }, } err = cli.Create(ctx, ioChaos) diff --git a/e2e-test/e2e/chaos/iochaos/misc.go b/e2e-test/e2e/chaos/iochaos/misc.go new file mode 100644 index 0000000000..0a9c117cc6 --- /dev/null +++ b/e2e-test/e2e/chaos/iochaos/misc.go @@ -0,0 +1,77 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package iochaos + +import ( + "fmt" + "io" + "net/http" + "strings" + "time" + + "github.com/pkg/errors" +) + +// get pod io delay +func getPodIODelay(c http.Client, port uint16) (time.Duration, error) { + resp, err := c.Get(fmt.Sprintf("http://localhost:%d/io", port)) + if err != nil { + return 0, err + } + + out, err := io.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + return 0, err + } + + result := string(out) + if strings.Contains(result, "failed to write file") { + return 0, errors.New(result) + } + dur, err := time.ParseDuration(result) + if err != nil { + return 0, err + } + + return dur, nil +} + +func getPodIoMistake(c http.Client, port uint16) (bool, error) { + resp, err := c.Get(fmt.Sprintf("http://localhost:%d/mistake", port)) + if err != nil { + return false, err + } + + out, err := io.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + return false, err + } + + result := string(out) + fmt.Println("e2e server io mistake test response: ", resp, result) + if strings.Contains(result, "true") { + return true, nil + } + if strings.Contains(result, "false") { + return false, nil + } + if strings.Contains(result, "err") { + return false, errors.New(result) + } + return false, errors.New("unexpected reply from e2e server") +} diff --git a/e2e-test/e2e/chaos/networkchaos/misc.go b/e2e-test/e2e/chaos/networkchaos/misc.go new file mode 100644 index 0000000000..6bf2674099 --- /dev/null +++ b/e2e-test/e2e/chaos/networkchaos/misc.go @@ -0,0 +1,297 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package networkchaos + +import ( + "bytes" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "sync" + "time" + + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog/v2" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +const ( + networkConditionBlocked = "blocked" + networkConditionSlow = "slow" + networkConditionGood = "good" +) + +func recvUDPPacket(c http.Client, port uint16) (string, error) { + klog.Infof("sending request to http://localhost:%d/network/recv", port) + resp, err := c.Get(fmt.Sprintf("http://localhost:%d/network/recv", port)) + if err != nil { + return "", err + } + + out, err := io.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + return "", err + } + + result := string(out) + return result, nil +} + +func sendUDPPacket(c http.Client, port uint16, targetIP string) error { + body := []byte(fmt.Sprintf("{\"targetIP\":\"%s\"}", targetIP)) + klog.Infof("sending request to http://localhost:%d/network/send with body: %s", port, string(body)) + + resp, err := c.Post(fmt.Sprintf("http://localhost:%d/network/send", port), "application/json", bytes.NewReader(body)) + if err != nil { + return err + } + + out, err := io.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + return err + } + + result := string(out) + if result != "send successfully\n" { + return errors.Errorf("doesn't send successfully: %s", result) + } + + klog.Info("send request successfully") + return nil +} + +func testNetworkDelay(c http.Client, port uint16, targetIP string) (int64, error) { + body := []byte(fmt.Sprintf("{\"targetIP\":\"%s\"}", targetIP)) + klog.Infof("sending request to localhost:%d with body: %s", port, string(body)) + + resp, err := c.Post(fmt.Sprintf("http://localhost:%d/network/ping", port), "application/json", bytes.NewReader(body)) + if err != nil { + return 0, err + } + + out, err := io.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + return 0, err + } + + result := string(out) + parts := strings.Split(result, " ") + if len(parts) != 2 { + return 0, errors.Errorf("the length of parts is not 2 %v", parts) + } + + if parts[0] != "OK" { + return 0, errors.New("the first part of response is not OK") + } + + return strconv.ParseInt(parts[1], 10, 64) +} + +func makeNetworkPartitionChaos( + namespace, name string, fromLabelSelectors, toLabelSelectors map[string]string, + fromPodMode, toPodMode v1alpha1.SelectorMode, + direction v1alpha1.Direction, + duration *string, +) *v1alpha1.NetworkChaos { + var target *v1alpha1.PodSelector + if toLabelSelectors != nil { + target = &v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{namespace}, + LabelSelectors: toLabelSelectors, + }, + }, + Mode: toPodMode, + } + } + + return &v1alpha1.NetworkChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: v1alpha1.NetworkChaosSpec{ + Action: v1alpha1.PartitionAction, + Direction: direction, + Target: target, + Duration: duration, + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{namespace}, + LabelSelectors: fromLabelSelectors, + }, + }, + Mode: fromPodMode, + }, + }, + } +} + +func makeNetworkDelayChaos( + namespace, name string, fromLabelSelectors, toLabelSelectors map[string]string, + fromPodMode, toPodMode v1alpha1.SelectorMode, direction v1alpha1.Direction, tcparam v1alpha1.TcParameter, duration *string, +) *v1alpha1.NetworkChaos { + var target *v1alpha1.PodSelector + if toLabelSelectors != nil { + target = &v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{namespace}, + LabelSelectors: toLabelSelectors, + }, + }, + Mode: toPodMode, + } + } + + return &v1alpha1.NetworkChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: v1alpha1.NetworkChaosSpec{ + Action: v1alpha1.DelayAction, + TcParameter: tcparam, + Duration: duration, + Target: target, + Direction: direction, + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{namespace}, + LabelSelectors: fromLabelSelectors, + }, + }, + Mode: fromPodMode, + }, + }, + } +} + +func probeNetworkCondition(c http.Client, peers []*corev1.Pod, ports []uint16, bidirection bool) map[string][][]int { + result := make(map[string][][]int) + + testDelay := func(from int, to int) (int64, error) { + return testNetworkDelay(c, ports[from], peers[to].Status.PodIP) + } + + for source := 0; source < len(peers); source++ { + initialTarget := source + 1 + if bidirection { + initialTarget = 0 + } + for target := initialTarget; target < len(peers); target++ { + if target == source { + continue + } + + connectable := true + + var ( + wg sync.WaitGroup + link1, link2 bool + ) + wg.Add(2) + go func() { + defer wg.Done() + // case 1-1: source to target blocked? + klog.Infof("testing connectivity from %s to %s", peers[source].Name, peers[target].Name) + link1 = couldConnect(c, ports[source], peers[target].Status.PodIP, ports[target]) + + }() + + go func() { + defer wg.Done() + // case 1-2: target to source blocked? + klog.Infof("testing connectivity from %s to %s", peers[target].Name, peers[source].Name) + link2 = couldConnect(c, ports[target], peers[source].Status.PodIP, ports[source]) + }() + wg.Wait() + + if !link1 { + klog.Infof("%s could not connect to %s", peers[source].Name, peers[target].Name) + result[networkConditionBlocked] = append(result[networkConditionBlocked], []int{source, target}) + connectable = false + } + if !link2 { + klog.Infof("%s could not connect to %s", peers[target].Name, peers[source].Name) + result[networkConditionBlocked] = append(result[networkConditionBlocked], []int{target, source}) + connectable = false + } + + if !connectable { + continue + } + + // case 2: slow network + klog.Infof("testing delay from %s to %s", peers[source].Name, peers[target].Name) + delay, err := testDelay(source, target) + if err != nil { + klog.Errorf("error from %d to %d: %v", source, target, err) + continue + } + + klog.Infof("delay from %d to %d: %d", source, target, delay) + if delay > 100*1e6 { + klog.Infof("detect slow network from %s to %s", peers[source].Name, peers[target].Name) + result[networkConditionSlow] = append(result[networkConditionSlow], []int{source, target}) + continue + } + + // case 3: otherwise, good network + klog.Infof("good network from %d to %d", source, target) + result[networkConditionGood] = append(result[networkConditionGood], []int{source, target}) + } + } + + return result +} + +func couldConnect(c http.Client, sourcePort uint16, targetPodIP string, targetPort uint16) bool { + err := sendUDPPacket(c, sourcePort, targetPodIP) + if err != nil { + klog.Infof("Error: %v", err) + return false + } + + time.Sleep(time.Second) + + data, err := recvUDPPacket(c, targetPort) + if err != nil { + klog.Infof("Error: %v, Data: %s", err, data) + return false + } + + // As this function ignores the data corruption, it will only return false when the + // e2e test cannot connect to the helper, or the helper failed to send (the iptables + // rules drop the sending packet on the sender side, which will give an "operation not permitted" error) + // FIXME: slow network may also make this happens + if data != "ping\n" { + klog.Infof("mismatch data return: %s, it may happens under bad network", data) + } + + return true +} diff --git a/test/e2e/chaos/networkchaos/network_delay.go b/e2e-test/e2e/chaos/networkchaos/network_delay.go similarity index 93% rename from test/e2e/chaos/networkchaos/network_delay.go rename to e2e-test/e2e/chaos/networkchaos/network_delay.go index e17baabb2e..f76c724791 100644 --- a/test/e2e/chaos/networkchaos/network_delay.go +++ b/e2e-test/e2e/chaos/networkchaos/network_delay.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package networkchaos @@ -18,16 +20,15 @@ import ( "net/http" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" corev1 "k8s.io/api/core/v1" - "k8s.io/kubernetes/test/e2e/framework" - "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/kubernetes/test/e2e/framework" "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/test/e2e/util" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" ) func TestcaseNetworkDelay( @@ -78,10 +79,7 @@ func TestcaseNetworkDelay( Correlation: "25", }, } - testDelayDuration = pointer.StringPtr("9m") - testDelaySchedulerSpec = &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", - } + testDelayDuration = pointer.StringPtr("9m") ) By("normal delay chaos") @@ -89,12 +87,11 @@ func TestcaseNetworkDelay( ns, "network-chaos-1", map[string]string{"app": "network-peer-0"}, nil, // no target specified - v1alpha1.OnePodMode, - v1alpha1.OnePodMode, + v1alpha1.OneMode, + v1alpha1.OneMode, v1alpha1.To, testDelayTcParam, testDelayDuration, - testDelaySchedulerSpec, ) By("Injecting delay for 0") err := cli.Create(ctx, networkDelay.DeepCopy()) @@ -130,12 +127,11 @@ func TestcaseNetworkDelay( ns, "network-chaos-1", map[string]string{"app": "network-peer-0"}, map[string]string{"app": "network-peer-1"}, // 0 -> 1 add delays - v1alpha1.OnePodMode, - v1alpha1.OnePodMode, + v1alpha1.OneMode, + v1alpha1.OneMode, v1alpha1.To, testDelayTcParam, testDelayDuration, - testDelaySchedulerSpec, ) By("Injecting delay for 0 -> 1") @@ -171,12 +167,11 @@ func TestcaseNetworkDelay( ns, "network-chaos-2", map[string]string{"app": "network-peer-0"}, map[string]string{"partition": "0"}, // 0 -> even its partition (idx % 2) - v1alpha1.OnePodMode, - v1alpha1.AllPodMode, + v1alpha1.OneMode, + v1alpha1.AllMode, v1alpha1.To, testDelayTcParam, testDelayDuration, - testDelaySchedulerSpec, ) By("Injecting delay for 0 -> even partition") err = cli.Create(ctx, evenNetworkDelay.DeepCopy()) @@ -236,12 +231,11 @@ func TestcaseNetworkDelay( ns, "network-chaos-3", map[string]string{"app": "network-peer-0"}, nil, // no target specified - v1alpha1.OnePodMode, - v1alpha1.OnePodMode, + v1alpha1.OneMode, + v1alpha1.OneMode, v1alpha1.To, testDelayTcParamEvenMoreComplicate, testDelayDuration, - testDelaySchedulerSpec, ) By("Injecting complicate chaos for 0") err = cli.Create(ctx, complicateNetem.DeepCopy()) @@ -274,12 +268,11 @@ func TestcaseNetworkDelay( ns, "network-chaos-4", map[string]string{"app": "network-peer-0"}, map[string]string{"partition": "0"}, // 0 -> even its partition (idx % 2) - v1alpha1.OnePodMode, - v1alpha1.AllPodMode, + v1alpha1.OneMode, + v1alpha1.AllMode, v1alpha1.Both, testDelayTcParam, testDelayDuration, - testDelaySchedulerSpec, ) By("Injecting both direction chaos for 0") err = cli.Create(ctx, bothDirectionNetem.DeepCopy()) diff --git a/e2e-test/e2e/chaos/networkchaos/network_partition.go b/e2e-test/e2e/chaos/networkchaos/network_partition.go new file mode 100644 index 0000000000..b3d252d1b7 --- /dev/null +++ b/e2e-test/e2e/chaos/networkchaos/network_partition.go @@ -0,0 +1,400 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package networkchaos + +import ( + "context" + "net/http" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" + "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/utils/pointer" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" + "github.com/chaos-mesh/chaos-mesh/e2e-test/pkg/fixture" +) + +// TestcaseForbidHostNetwork We do NOT allow that inject chaos on a pod which uses hostNetwork +func TestcaseForbidHostNetwork( + ns string, + kubeCli kubernetes.Interface, + cli client.Client, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("preparing experiment pods") + name := "network-peer-4" + nd := fixture.NewNetworkTestDeployment(name, ns, map[string]string{"partition": "0"}) + nd.Spec.Template.Spec.HostNetwork = true + _, err := kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create network-peer deployment error") + err = util.WaitDeploymentReady(name, ns, kubeCli) + framework.ExpectNoError(err, "wait network-peer deployment ready error") + + By("create network partition chaos CRD objects") + networkPartition := makeNetworkPartitionChaos( + ns, "network-chaos-1", + map[string]string{"app": "network-peer-4"}, + map[string]string{"app": "network-peer-1"}, + v1alpha1.OneMode, + v1alpha1.OneMode, + v1alpha1.To, + pointer.StringPtr("9m"), + ) + + err = cli.Create(ctx, networkPartition.DeepCopy()) + framework.ExpectNoError(err, "create network chaos error") + + By("waiting for rejecting for network chaos with hostNetwork") + err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { + err = cli.Get(ctx, types.NamespacedName{ + Namespace: ns, + Name: "network-chaos-1", + }, networkPartition) + if err != nil { + return false, err + } + + failed := true + for _, record := range networkPartition.Status.ChaosStatus.Experiment.Records { + klog.Infof("current chaos record %s phase: %s", record.Id, record.Phase) + if strings.Contains(record.Id, "network-peer-4") && record.Phase == v1alpha1.Injected { + failed = false + } + } + return failed, nil + }) + + framework.ExpectNoError(err, "failed to waiting on not injected state with chaos") + framework.ExpectEqual(networkPartition.Status.ChaosStatus.Experiment.DesiredPhase, v1alpha1.RunningPhase) + // TODO: add failed event check + //framework.ExpectEqual(strings.Contains(networkPartition.Status.ChaosStatus.FailedMessage, "it's dangerous to inject network chaos on a pod"), true) +} + +func TestcaseNetworkPartition( + ns string, + cli client.Client, + networkPeers []*corev1.Pod, + ports []uint16, + c http.Client, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + By("prepare experiment playground") + for index := range networkPeers { + err := util.WaitE2EHelperReady(c, ports[index]) + + framework.ExpectNoError(err, "wait e2e helper ready error") + } + + var result map[string][][]int + wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { + result = probeNetworkCondition(c, networkPeers, ports, false) + if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + framework.ExpectEqual(len(result[networkConditionBlocked]), 0) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) + + var ( + testDelayDuration = pointer.StringPtr("9m") + ) + + baseNetworkPartition := makeNetworkPartitionChaos( + ns, "network-chaos-1", + map[string]string{"app": "network-peer-0"}, + map[string]string{"app": "network-peer-1"}, + v1alpha1.OneMode, + v1alpha1.OneMode, + v1alpha1.To, + testDelayDuration, + ) + + By("block from peer-0 to peer-1") + err := cli.Create(ctx, baseNetworkPartition.DeepCopy()) + framework.ExpectNoError(err, "create network chaos error") + + wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { + result = probeNetworkCondition(c, networkPeers, ports, false) + if len(result[networkConditionBlocked]) != 1 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + framework.ExpectEqual(result[networkConditionBlocked], [][]int{{0, 1}}) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) + + By("recover") + err = cli.Delete(ctx, baseNetworkPartition.DeepCopy()) + framework.ExpectNoError(err, "delete network chaos error") + + wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { + result = probeNetworkCondition(c, networkPeers, ports, false) + if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + framework.ExpectEqual(len(result[networkConditionBlocked]), 0) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) + + By("block both from peer-0 to peer-1 and from peer-1 to peer-0") + bothDirectionNetworkPartition := makeNetworkPartitionChaos( + ns, "network-chaos-1", + map[string]string{"app": "network-peer-0"}, + map[string]string{"app": "network-peer-1"}, + v1alpha1.OneMode, + v1alpha1.OneMode, + v1alpha1.Both, + testDelayDuration, + ) + err = cli.Create(ctx, bothDirectionNetworkPartition.DeepCopy()) + framework.ExpectNoError(err, "create network chaos error") + + wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { + result = probeNetworkCondition(c, networkPeers, ports, false) + if len(result[networkConditionBlocked]) != 2 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + framework.ExpectEqual(result[networkConditionBlocked], [][]int{{0, 1}, {1, 0}}) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) + + By("recover") + err = cli.Delete(ctx, bothDirectionNetworkPartition.DeepCopy()) + framework.ExpectNoError(err, "delete network chaos error") + + wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { + result = probeNetworkCondition(c, networkPeers, ports, false) + if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + framework.ExpectEqual(len(result[networkConditionBlocked]), 0) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) + + By("block from peer-1 to peer-0") + fromDirectionNetworkPartition := makeNetworkPartitionChaos( + ns, "network-chaos-1", + map[string]string{"app": "network-peer-0"}, + map[string]string{"app": "network-peer-1"}, + v1alpha1.OneMode, + v1alpha1.OneMode, + v1alpha1.From, + testDelayDuration, + ) + + err = cli.Create(ctx, fromDirectionNetworkPartition.DeepCopy()) + framework.ExpectNoError(err, "create network chaos error") + + wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { + result = probeNetworkCondition(c, networkPeers, ports, false) + if len(result[networkConditionBlocked]) != 1 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + framework.ExpectEqual(result[networkConditionBlocked], [][]int{{1, 0}}) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) + + By("recover") + err = cli.Delete(ctx, fromDirectionNetworkPartition.DeepCopy()) + framework.ExpectNoError(err, "delete network chaos error") + + wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { + result = probeNetworkCondition(c, networkPeers, ports, false) + if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + framework.ExpectEqual(len(result[networkConditionBlocked]), 0) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) + + By("network partition 1") + + bothDirectionWithPartitionNetworkPartition := makeNetworkPartitionChaos( + ns, "network-chaos-1", + map[string]string{"app": "network-peer-0"}, + map[string]string{"partition": "1"}, + v1alpha1.OneMode, + v1alpha1.AllMode, + v1alpha1.Both, + testDelayDuration, + ) + err = cli.Create(ctx, bothDirectionWithPartitionNetworkPartition.DeepCopy()) + framework.ExpectNoError(err, "create network chaos error") + + wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { + result = probeNetworkCondition(c, networkPeers, ports, false) + if len(result[networkConditionBlocked]) != 4 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + framework.ExpectEqual(result[networkConditionBlocked], [][]int{{0, 1}, {1, 0}, {0, 3}, {3, 0}}) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) + + By("recover") + err = cli.Delete(ctx, bothDirectionWithPartitionNetworkPartition.DeepCopy()) + framework.ExpectNoError(err, "delete network chaos error") + + wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { + result = probeNetworkCondition(c, networkPeers, ports, false) + if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + framework.ExpectEqual(len(result[networkConditionBlocked]), 0) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) + + By("multiple network partition chaos on peer-0") + anotherNetworkPartition := makeNetworkPartitionChaos( + ns, "network-chaos-2", + map[string]string{"app": "network-peer-0"}, + map[string]string{"partition": "0"}, + v1alpha1.OneMode, + v1alpha1.AllMode, + v1alpha1.To, + testDelayDuration, + ) + err = cli.Create(ctx, bothDirectionWithPartitionNetworkPartition.DeepCopy()) + framework.ExpectNoError(err, "create network chaos error") + err = cli.Create(ctx, anotherNetworkPartition.DeepCopy()) + framework.ExpectNoError(err, "create network chaos error") + + wait.Poll(time.Second, 30*time.Second, func() (done bool, err error) { + result = probeNetworkCondition(c, networkPeers, ports, false) + if len(result[networkConditionBlocked]) != 5 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + framework.ExpectEqual(result[networkConditionBlocked], [][]int{{0, 1}, {1, 0}, {0, 2}, {0, 3}, {3, 0}}) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) + + By("recover") + err = cli.Delete(ctx, bothDirectionWithPartitionNetworkPartition.DeepCopy()) + framework.ExpectNoError(err, "delete network chaos error") + err = cli.Delete(ctx, anotherNetworkPartition.DeepCopy()) + framework.ExpectNoError(err, "delete network chaos error") + + wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { + klog.Info("retry probeNetworkCondition") + result = probeNetworkCondition(c, networkPeers, ports, false) + if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + framework.ExpectEqual(len(result[networkConditionBlocked]), 0) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) + + By("block from peer-0 to all") + networkPartitionWithoutTarget := makeNetworkPartitionChaos( + ns, "network-chaos-without-target", + map[string]string{"app": "network-peer-0"}, + nil, + v1alpha1.OneMode, + v1alpha1.AllMode, + v1alpha1.To, + testDelayDuration, + ) + err = cli.Create(ctx, networkPartitionWithoutTarget.DeepCopy()) + framework.ExpectNoError(err, "create network chaos error") + + wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { + result = probeNetworkCondition(c, networkPeers, ports, false) + if len(result[networkConditionBlocked]) != 3 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + // The expected behavior is to block only 0 -> 1, 0 -> 2 and 0 -> 3 + framework.ExpectEqual(result[networkConditionBlocked], [][]int{{0, 1}, {0, 2}, {0, 3}}) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) + + By("recover") + err = cli.Delete(ctx, networkPartitionWithoutTarget.DeepCopy()) + framework.ExpectNoError(err, "delete network chaos error") + + wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { + klog.Info("retry probeNetworkCondition") + result = probeNetworkCondition(c, networkPeers, ports, false) + if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + framework.ExpectEqual(len(result[networkConditionBlocked]), 0) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) + + By("block from peer-0 from all") + networkPartitionWithoutTarget = makeNetworkPartitionChaos( + ns, "network-chaos-without-target", + map[string]string{"app": "network-peer-0"}, + nil, + v1alpha1.OneMode, + v1alpha1.AllMode, + v1alpha1.From, + testDelayDuration, + ) + err = cli.Create(ctx, networkPartitionWithoutTarget.DeepCopy()) + framework.ExpectNoError(err, "create network chaos error") + + wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { + result = probeNetworkCondition(c, networkPeers, ports, true) + if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + // The expected behavior is to block only 0 -> 1, 0 -> 2 and 0 -> 3 + // but the dropped packet will not throw an error + framework.ExpectEqual(len(result[networkConditionBlocked]), 0) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) + + By("recover") + err = cli.Delete(ctx, networkPartitionWithoutTarget.DeepCopy()) + framework.ExpectNoError(err, "delete network chaos error") + + wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { + klog.Info("retry probeNetworkCondition") + result = probeNetworkCondition(c, networkPeers, ports, false) + if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { + return false, nil + } + return true, nil + }) + framework.ExpectEqual(len(result[networkConditionBlocked]), 0) + framework.ExpectEqual(len(result[networkConditionSlow]), 0) +} diff --git a/test/e2e/chaos/networkchaos/network_peers_crossover.go b/e2e-test/e2e/chaos/networkchaos/network_peers_crossover.go similarity index 93% rename from test/e2e/chaos/networkchaos/network_peers_crossover.go rename to e2e-test/e2e/chaos/networkchaos/network_peers_crossover.go index c24ba6f4c9..3d365e8809 100644 --- a/test/e2e/chaos/networkchaos/network_peers_crossover.go +++ b/e2e-test/e2e/chaos/networkchaos/network_peers_crossover.go @@ -4,12 +4,14 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package networkchaos @@ -18,15 +20,14 @@ import ( "net/http" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" corev1 "k8s.io/api/core/v1" - "k8s.io/kubernetes/test/e2e/framework" - "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/kubernetes/test/e2e/framework" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/test/e2e/util" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" ) // This test case is for https://github.com/chaos-mesh/chaos-mesh/issues/1450 @@ -68,12 +69,11 @@ func TestcasePeersCrossover( ns, "network-chaos-1", map[string]string{"partition": "0"}, map[string]string{"partition": "1"}, - v1alpha1.AllPodMode, - v1alpha1.AllPodMode, + v1alpha1.AllMode, + v1alpha1.AllMode, v1alpha1.Both, testDelayTcParam, nil, - nil, ) // that's important networkDelay.Spec.Direction = v1alpha1.Both diff --git a/e2e-test/e2e/chaos/podchaos/container_kill.go b/e2e-test/e2e/chaos/podchaos/container_kill.go new file mode 100644 index 0000000000..65785e8813 --- /dev/null +++ b/e2e-test/e2e/chaos/podchaos/container_kill.go @@ -0,0 +1,245 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podchaos + +import ( + "context" + "time" + + . "github.com/onsi/ginkgo/v2" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" + "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/utils/pointer" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" + "github.com/chaos-mesh/chaos-mesh/e2e-test/pkg/fixture" +) + +func TestcaseContainerKillOnceThenDelete(ns string, kubeCli kubernetes.Interface, cli client.Client) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + nd := fixture.NewCommonNginxDeployment("nginx", ns, 1) + _, err := kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create nginx deployment error") + err = util.WaitDeploymentReady("nginx", ns, kubeCli) + framework.ExpectNoError(err, "wait nginx deployment ready error") + + containerKillChaos := &v1alpha1.PodChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx-container-kill", + Namespace: ns, + }, + Spec: v1alpha1.PodChaosSpec{ + Action: v1alpha1.ContainerKillAction, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ + ns, + }, + LabelSelectors: map[string]string{ + "app": "nginx", + }, + }, + }, + Mode: v1alpha1.OneMode, + }, + ContainerNames: []string{"nginx"}, + }, + }, + } + err = cli.Create(ctx, containerKillChaos) + framework.ExpectNoError(err, "create container kill chaos error") + + err = wait.PollImmediate(5*time.Second, 5*time.Minute, func() (done bool, err error) { + listOption := metav1.ListOptions{ + LabelSelector: labels.SelectorFromSet(map[string]string{ + "app": "nginx", + }).String(), + } + pods, err := kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) + if err != nil { + return false, nil + } + if len(pods.Items) != 1 { + return false, nil + } + pod := pods.Items[0] + for _, cs := range pod.Status.ContainerStatuses { + if cs.Name == "nginx" && cs.LastTerminationState.Terminated != nil { + return true, nil + } + } + return false, nil + }) + framework.ExpectNoError(err, "container kill apply failed") + + err = cli.Delete(ctx, containerKillChaos) + framework.ExpectNoError(err, "failed to delete container kill chaos") + + By("success to perform container kill") + err = wait.PollImmediate(5*time.Second, 5*time.Minute, func() (done bool, err error) { + listOption := metav1.ListOptions{ + LabelSelector: labels.SelectorFromSet(map[string]string{ + "app": "nginx", + }).String(), + } + pods, err := kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) + if err != nil { + return false, nil + } + if len(pods.Items) != 1 { + return false, nil + } + pod := pods.Items[0] + for _, cs := range pod.Status.ContainerStatuses { + if cs.Name == "nginx" && cs.Ready && cs.State.Running != nil { + return true, nil + } + } + return false, nil + }) + framework.ExpectNoError(err, "container kill recover failed") + +} + +func TestcaseContainerKillPauseThenUnPause(ns string, kubeCli kubernetes.Interface, cli client.Client) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + nd := fixture.NewCommonNginxDeployment("nginx", ns, 1) + _, err := kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create nginx deployment error") + err = util.WaitDeploymentReady("nginx", ns, kubeCli) + framework.ExpectNoError(err, "wait nginx deployment ready error") + + var pods *corev1.PodList + var newPods *corev1.PodList + listOption := metav1.ListOptions{ + LabelSelector: labels.SelectorFromSet(map[string]string{ + "app": "nginx", + }).String(), + } + pods, err = kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) + framework.ExpectNoError(err, "get nginx pods error") + + // Get the running nginx container ID + containerID := pods.Items[0].Status.ContainerStatuses[0].ContainerID + + containerKillChaos := &v1alpha1.PodChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx-container-kill", + Namespace: ns, + }, + Spec: v1alpha1.PodChaosSpec{ + Action: v1alpha1.ContainerKillAction, + Duration: pointer.StringPtr("9m"), + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ + ns, + }, + LabelSelectors: map[string]string{ + "app": "nginx", + }, + }, + }, + Mode: v1alpha1.OneMode, + }, + ContainerNames: []string{"nginx"}, + }, + }, + } + err = cli.Create(ctx, containerKillChaos) + framework.ExpectNoError(err, "create container kill chaos error") + + chaosKey := types.NamespacedName{ + Namespace: ns, + Name: "nginx-container-kill", + } + + // nginx container is killed as expected + err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { + newPods, err = kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) + framework.ExpectNoError(err, "get nginx pods error") + return containerID != newPods.Items[0].Status.ContainerStatuses[0].ContainerID, nil + }) + framework.ExpectNoError(err, "wait container kill failed") + + // pause experiment + err = util.PauseChaos(ctx, cli, containerKillChaos) + framework.ExpectNoError(err, "pause chaos error") + + err = wait.Poll(1*time.Second, 10*time.Second, func() (done bool, err error) { + chaos := &v1alpha1.PodChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get pod chaos error") + if chaos.Status.Experiment.DesiredPhase == v1alpha1.StoppedPhase { + return true, nil + } + return false, err + }) + framework.ExpectError(err, "one-shot chaos shouldn't enter stopped phase") + + // wait for 1 minutes and check whether nginx container will be killed or not + pods, err = kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) + framework.ExpectNoError(err, "get nginx pods error") + containerID = pods.Items[0].Status.ContainerStatuses[0].ContainerID + err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { + newPods, err = kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) + framework.ExpectNoError(err, "get nginx pods error") + return containerID != newPods.Items[0].Status.ContainerStatuses[0].ContainerID, nil + }) + framework.ExpectError(err, "wait container not killed failed") + framework.ExpectEqual(err.Error(), wait.ErrWaitTimeout.Error()) + + // resume experiment + err = util.UnPauseChaos(ctx, cli, containerKillChaos) + framework.ExpectNoError(err, "resume chaos error") + + err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.PodChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get pod chaos error") + if chaos.Status.Experiment.DesiredPhase == v1alpha1.RunningPhase { + return true, nil + } + return false, err + }) + framework.ExpectNoError(err, "chaos should keep in running phase") + + // nginx container is killed by resumed experiment + pods, err = kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) + framework.ExpectNoError(err, "get nginx pods error") + containerID = pods.Items[0].Status.ContainerStatuses[0].ContainerID + err = wait.Poll(1*time.Second, 10*time.Second, func() (done bool, err error) { + newPods, err = kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) + framework.ExpectNoError(err, "get nginx pods error") + return containerID != newPods.Items[0].Status.ContainerStatuses[0].ContainerID, nil + }) + framework.ExpectError(err, "container shouldn't be killed") + +} diff --git a/e2e-test/e2e/chaos/podchaos/misc.go b/e2e-test/e2e/chaos/podchaos/misc.go new file mode 100644 index 0000000000..efb4a5b4a9 --- /dev/null +++ b/e2e-test/e2e/chaos/podchaos/misc.go @@ -0,0 +1,39 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podchaos + +import ( + "context" + "time" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" +) + +func waitPodRunning(name, namespace string, cli kubernetes.Interface) error { + return wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { + pod, err := cli.CoreV1().Pods(namespace).Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil { + return false, nil + } + if pod.Status.Phase != corev1.PodRunning { + return false, nil + } + return true, nil + }) +} diff --git a/test/e2e/chaos/podchaos/pod_failure.go b/e2e-test/e2e/chaos/podchaos/pod_failure.go similarity index 75% rename from test/e2e/chaos/podchaos/pod_failure.go rename to e2e-test/e2e/chaos/podchaos/pod_failure.go index 86e412226b..93342d2f6c 100644 --- a/test/e2e/chaos/podchaos/pod_failure.go +++ b/e2e-test/e2e/chaos/podchaos/pod_failure.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package podchaos @@ -17,7 +19,7 @@ import ( "context" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -29,9 +31,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/test/e2e/e2econst" - "github.com/chaos-mesh/chaos-mesh/test/e2e/util" - "github.com/chaos-mesh/chaos-mesh/test/pkg/fixture" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/config" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" + "github.com/chaos-mesh/chaos-mesh/e2e-test/pkg/fixture" ) func TestcasePodFailureOnceThenDelete(ns string, kubeCli kubernetes.Interface, cli client.Client) { @@ -41,7 +43,7 @@ func TestcasePodFailureOnceThenDelete(ns string, kubeCli kubernetes.Interface, c By("preparing experiment pods") appName := "timer-pod-failure1" nd := fixture.NewTimerDeployment(appName, ns) - _, err := kubeCli.AppsV1().Deployments(ns).Create(nd) + _, err := kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) framework.ExpectNoError(err, "create timer deployment error") err = util.WaitDeploymentReady(appName, ns, kubeCli) framework.ExpectNoError(err, "wait timer deployment ready error") @@ -58,16 +60,22 @@ func TestcasePodFailureOnceThenDelete(ns string, kubeCli kubernetes.Interface, c Namespace: ns, }, Spec: v1alpha1.PodChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ - ns, - }, - LabelSelectors: map[string]string{ - "app": appName, + Action: v1alpha1.PodFailureAction, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ + ns, + }, + LabelSelectors: map[string]string{ + "app": appName, + }, + }, + }, + Mode: v1alpha1.OneMode, }, }, - Action: v1alpha1.PodFailureAction, - Mode: v1alpha1.OnePodMode, }, } @@ -76,7 +84,7 @@ func TestcasePodFailureOnceThenDelete(ns string, kubeCli kubernetes.Interface, c By("waiting for assertion some pod fall into failure") err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - pods, err := kubeCli.CoreV1().Pods(ns).List(listOption) + pods, err := kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) if err != nil { return false, nil } @@ -85,7 +93,7 @@ func TestcasePodFailureOnceThenDelete(ns string, kubeCli kubernetes.Interface, c } pod := pods.Items[0] for _, c := range pod.Spec.Containers { - if c.Image == e2econst.PauseImage { + if c.Image == config.TestConfig.PauseImage { return true, nil } } @@ -99,7 +107,7 @@ func TestcasePodFailureOnceThenDelete(ns string, kubeCli kubernetes.Interface, c By("waiting for assertion recovering") err = wait.Poll(5*time.Second, 2*time.Minute, func() (done bool, err error) { - pods, err := kubeCli.CoreV1().Pods(ns).List(listOption) + pods, err := kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) if err != nil { return false, nil } @@ -124,7 +132,7 @@ func TestcasePodFailurePauseThenUnPause(ns string, kubeCli kubernetes.Interface, By("preparing experiment pods") appName := "timer-pod-failure2" nd := fixture.NewTimerDeployment(appName, ns) - _, err := kubeCli.AppsV1().Deployments(ns).Create(nd) + _, err := kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) framework.ExpectNoError(err, "create timer deployment error") err = util.WaitDeploymentReady(appName, ns, kubeCli) framework.ExpectNoError(err, "wait timer deployment ready error") @@ -143,15 +151,22 @@ func TestcasePodFailurePauseThenUnPause(ns string, kubeCli kubernetes.Interface, Namespace: ns, }, Spec: v1alpha1.PodChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": appName}, - }, Action: v1alpha1.PodFailureAction, - Mode: v1alpha1.OnePodMode, Duration: pointer.StringPtr("9m"), - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ + ns, + }, + LabelSelectors: map[string]string{ + "app": appName, + }, + }, + }, + Mode: v1alpha1.OneMode, + }, }, }, } @@ -165,13 +180,13 @@ func TestcasePodFailurePauseThenUnPause(ns string, kubeCli kubernetes.Interface, By("waiting for assertion some pod fall into failure") // check whether the pod failure chaos succeeded or not err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - pods, err := kubeCli.CoreV1().Pods(ns).List(listOption) + pods, err := kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) if err != nil { return false, nil } pod := pods.Items[0] for _, c := range pod.Spec.Containers { - if c.Image == e2econst.PauseImage { + if c.Image == config.TestConfig.PauseImage { return true, nil } } @@ -189,7 +204,7 @@ func TestcasePodFailurePauseThenUnPause(ns string, kubeCli kubernetes.Interface, chaos := &v1alpha1.PodChaos{} err = cli.Get(ctx, chaosKey, chaos) framework.ExpectNoError(err, "get pod chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhasePaused { + if chaos.Status.Experiment.DesiredPhase == v1alpha1.StoppedPhase { return true, nil } return false, err @@ -197,14 +212,14 @@ func TestcasePodFailurePauseThenUnPause(ns string, kubeCli kubernetes.Interface, framework.ExpectNoError(err, "check paused chaos failed") By("wait for 30 seconds and no pod failure") - pods, err = kubeCli.CoreV1().Pods(ns).List(listOption) + pods, err = kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) framework.ExpectNoError(err, "get timer pod error") err = wait.Poll(5*time.Second, 30*time.Second, func() (done bool, err error) { - pods, err = kubeCli.CoreV1().Pods(ns).List(listOption) + pods, err = kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) framework.ExpectNoError(err, "get timer pod error") pod := pods.Items[0] for _, c := range pod.Spec.Containers { - if c.Image == e2econst.PauseImage { + if c.Image == config.TestConfig.PauseImage { return false, nil } } @@ -222,7 +237,7 @@ func TestcasePodFailurePauseThenUnPause(ns string, kubeCli kubernetes.Interface, chaos := &v1alpha1.PodChaos{} err = cli.Get(ctx, chaosKey, chaos) framework.ExpectNoError(err, "get pod chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhaseRunning { + if chaos.Status.Experiment.DesiredPhase == v1alpha1.RunningPhase { return true, nil } return false, err @@ -231,11 +246,11 @@ func TestcasePodFailurePauseThenUnPause(ns string, kubeCli kubernetes.Interface, By("waiting for assert pod failure happens again") err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - pods, err = kubeCli.CoreV1().Pods(ns).List(listOption) + pods, err = kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) framework.ExpectNoError(err, "get timer pod error") pod := pods.Items[0] for _, c := range pod.Spec.Containers { - if c.Image == e2econst.PauseImage { + if c.Image == config.TestConfig.PauseImage { return true, nil } } diff --git a/e2e-test/e2e/chaos/podchaos/pod_kill.go b/e2e-test/e2e/chaos/podchaos/pod_kill.go new file mode 100644 index 0000000000..36371391a4 --- /dev/null +++ b/e2e-test/e2e/chaos/podchaos/pod_kill.go @@ -0,0 +1,172 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package podchaos + +import ( + "context" + "time" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" + "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/utils/pointer" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" + "github.com/chaos-mesh/chaos-mesh/e2e-test/pkg/fixture" +) + +func TestcasePodKillOnceThenDelete(ns string, kubeCli kubernetes.Interface, cli client.Client) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + pod := fixture.NewCommonNginxPod("nginx", ns) + _, err := kubeCli.CoreV1().Pods(ns).Create(context.TODO(), pod, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create nginx pod error") + err = waitPodRunning("nginx", ns, kubeCli) + framework.ExpectNoError(err, "wait nginx running error") + + podKillChaos := &v1alpha1.PodChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx-kill", + Namespace: ns, + }, + Spec: v1alpha1.PodChaosSpec{ + Action: v1alpha1.PodKillAction, + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ + ns, + }, + LabelSelectors: map[string]string{ + "app": "nginx", + }, + }, + }, + Mode: v1alpha1.OneMode, + }, + }, + }, + } + err = cli.Create(ctx, podKillChaos) + framework.ExpectNoError(err, "create pod chaos error") + + err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { + _, err = kubeCli.CoreV1().Pods(ns).Get(context.TODO(), "nginx", metav1.GetOptions{}) + if err != nil && apierrors.IsNotFound(err) { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "Pod kill chaos perform failed") + +} +func TestcasePodKillPauseThenUnPause(ns string, kubeCli kubernetes.Interface, cli client.Client) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + nd := fixture.NewCommonNginxDeployment("nginx", ns, 3) + _, err := kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) + framework.ExpectNoError(err, "create nginx deployment error") + err = util.WaitDeploymentReady("nginx", ns, kubeCli) + framework.ExpectNoError(err, "wait nginx deployment ready error") + + var pods *corev1.PodList + var newPods *corev1.PodList + listOption := metav1.ListOptions{ + LabelSelector: labels.SelectorFromSet(map[string]string{ + "app": "nginx", + }).String(), + } + pods, err = kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) + framework.ExpectNoError(err, "get nginx pods error") + + podKillChaos := &v1alpha1.PodChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx-kill", + Namespace: ns, + }, + Spec: v1alpha1.PodChaosSpec{ + Action: v1alpha1.PodKillAction, + Duration: pointer.StringPtr("9m"), + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ + ns, + }, + LabelSelectors: map[string]string{ + "app": "nginx", + }, + }, + }, + Mode: v1alpha1.OneMode, + }, + }, + }, + } + err = cli.Create(ctx, podKillChaos) + framework.ExpectNoError(err, "create pod chaos error") + + chaosKey := types.NamespacedName{ + Namespace: ns, + Name: "nginx-kill", + } + + // some pod is killed as expected + err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { + newPods, err = kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) + framework.ExpectNoError(err, "get nginx pods error") + return !fixture.HaveSameUIDs(pods.Items, newPods.Items), nil + }) + framework.ExpectNoError(err, "wait pod killed failed") + + // pause experiment + err = util.PauseChaos(ctx, cli, podKillChaos) + framework.ExpectNoError(err, "pause chaos error") + + err = wait.Poll(1*time.Second, 5*time.Second, func() (done bool, err error) { + chaos := &v1alpha1.PodChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get pod chaos error") + if chaos.Status.Experiment.DesiredPhase == v1alpha1.StoppedPhase { + return true, nil + } + return false, err + }) + framework.ExpectError(err, "chaos shouldn't enter stopped phase") + + // wait for 1 minutes and no pod is killed + pods, err = kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) + framework.ExpectNoError(err, "get nginx pods error") + err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { + newPods, err = kubeCli.CoreV1().Pods(ns).List(context.TODO(), listOption) + framework.ExpectNoError(err, "get nginx pods error") + return !fixture.HaveSameUIDs(pods.Items, newPods.Items), nil + }) + framework.ExpectError(err, "wait pod not killed failed") + framework.ExpectEqual(err.Error(), wait.ErrWaitTimeout.Error()) + +} diff --git a/test/e2e/chaos/sidecar/injection_config.go b/e2e-test/e2e/chaos/sidecar/injection_config.go similarity index 78% rename from test/e2e/chaos/sidecar/injection_config.go rename to e2e-test/e2e/chaos/sidecar/injection_config.go index a47f6ed6a8..3e4da91427 100644 --- a/test/e2e/chaos/sidecar/injection_config.go +++ b/e2e-test/e2e/chaos/sidecar/injection_config.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package sidecar @@ -24,8 +26,8 @@ import ( "k8s.io/kubernetes/test/e2e/framework" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/chaos-mesh/chaos-mesh/test/e2e/util" - "github.com/chaos-mesh/chaos-mesh/test/pkg/fixture" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" + "github.com/chaos-mesh/chaos-mesh/e2e-test/pkg/fixture" ) func TestcaseNoTemplate( @@ -50,16 +52,16 @@ selector: "app.kubernetes.io/component": "controller-manager", }).String(), } - pods, err := kubeCli.CoreV1().Pods(cmNamespace).List(listOptions) + pods, err := kubeCli.CoreV1().Pods(cmNamespace).List(context.TODO(), listOptions) framework.ExpectNoError(err, "get chaos mesh controller pods error") err = wait.Poll(time.Second, 10*time.Second, func() (done bool, err error) { - newPods, err := kubeCli.CoreV1().Pods(cmNamespace).List(listOptions) + newPods, err := kubeCli.CoreV1().Pods(cmNamespace).List(context.TODO(), listOptions) framework.ExpectNoError(err, "get chaos mesh controller pods error") if !fixture.HaveSameUIDs(pods.Items, newPods.Items) { return true, nil } - if newPods.Items[0].Status.ContainerStatuses[0].RestartCount > 0 { + if len(newPods.Items) > 0 && newPods.Items[0].Status.ContainerStatuses[0].RestartCount > 0 { return true, nil } return false, nil @@ -70,7 +72,7 @@ selector: err = enableWebhook(ns) framework.ExpectNoError(err, "enable webhook on ns error") nd := fixture.NewIOTestDeployment("io-test", ns) - _, err = kubeCli.AppsV1().Deployments(ns).Create(nd) + _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) framework.ExpectNoError(err, "create io-test deployment error") err = util.WaitDeploymentReady("io-test", ns, kubeCli) framework.ExpectNoError(err, "wait io-test deployment ready error") @@ -103,16 +105,16 @@ selector: "app.kubernetes.io/component": "controller-manager", }).String(), } - pods, err := kubeCli.CoreV1().Pods(cmNamespace).List(listOptions) + pods, err := kubeCli.CoreV1().Pods(cmNamespace).List(context.TODO(), listOptions) framework.ExpectNoError(err, "get chaos mesh controller pods error") err = wait.Poll(time.Second, 10*time.Second, func() (done bool, err error) { - newPods, err := kubeCli.CoreV1().Pods(cmNamespace).List(listOptions) + newPods, err := kubeCli.CoreV1().Pods(cmNamespace).List(context.TODO(), listOptions) framework.ExpectNoError(err, "get chaos mesh controller pods error") if !fixture.HaveSameUIDs(pods.Items, newPods.Items) { return true, nil } - if newPods.Items[0].Status.ContainerStatuses[0].RestartCount > 0 { + if len(newPods.Items) > 0 && newPods.Items[0].Status.ContainerStatuses[0].RestartCount > 0 { return true, nil } return false, nil @@ -123,7 +125,7 @@ selector: err = enableWebhook(ns) framework.ExpectNoError(err, "enable webhook on ns error") nd := fixture.NewIOTestDeployment("io-test", ns) - _, err = kubeCli.AppsV1().Deployments(ns).Create(nd) + _, err = kubeCli.AppsV1().Deployments(ns).Create(context.TODO(), nd, metav1.CreateOptions{}) framework.ExpectNoError(err, "create io-test deployment error") err = util.WaitDeploymentReady("io-test", ns, kubeCli) framework.ExpectNoError(err, "wait io-test deployment ready error") diff --git a/e2e-test/e2e/chaos/sidecar/misc.go b/e2e-test/e2e/chaos/sidecar/misc.go new file mode 100644 index 0000000000..f55fc98274 --- /dev/null +++ b/e2e-test/e2e/chaos/sidecar/misc.go @@ -0,0 +1,77 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package sidecar + +import ( + "context" + "strings" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog/v2" + "k8s.io/utils/exec" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/e2econst" +) + +func createTemplateConfig( + ctx context.Context, + cli client.Client, + name string, + data map[string]string, +) error { + cm := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: e2econst.ChaosMeshNamespace, + Name: name, + Labels: map[string]string{ + "app.kubernetes.io/component": "template", + }, + }, + Data: data, + } + return cli.Create(ctx, cm) +} + +func createInjectionConfig( + ctx context.Context, + cli client.Client, + ns, name string, + data map[string]string, +) error { + cm := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + Name: name, + Labels: map[string]string{ + "app.kubernetes.io/component": "webhook", + }, + }, + Data: data, + } + return cli.Create(ctx, cm) +} + +// enableWebhook enables webhook on the specific namespace +func enableWebhook(ns string) error { + args := []string{"label", "ns", ns, "--overwrite", "admission-webhook=enabled"} + out, err := exec.New().Command("kubectl", args...).CombinedOutput() + if err != nil { + klog.Fatalf("Failed to run 'kubectl %s'\nCombined output: %q\nError: %v", strings.Join(args, " "), string(out), err) + } + return nil +} diff --git a/test/e2e/chaos/sidecar/template_config.go b/e2e-test/e2e/chaos/sidecar/template_config.go similarity index 79% rename from test/e2e/chaos/sidecar/template_config.go rename to e2e-test/e2e/chaos/sidecar/template_config.go index 33693c656d..5017dbc561 100644 --- a/test/e2e/chaos/sidecar/template_config.go +++ b/e2e-test/e2e/chaos/sidecar/template_config.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package sidecar @@ -24,7 +26,7 @@ import ( "k8s.io/kubernetes/test/e2e/framework" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/chaos-mesh/chaos-mesh/test/pkg/fixture" + "github.com/chaos-mesh/chaos-mesh/e2e-test/pkg/fixture" ) func TestcaseInvalidConfigMapKey( @@ -49,16 +51,16 @@ selector: "app.kubernetes.io/component": "controller-manager", }).String(), } - pods, err := kubeCli.CoreV1().Pods(cmNamespace).List(listOptions) + pods, err := kubeCli.CoreV1().Pods(cmNamespace).List(context.TODO(), listOptions) framework.ExpectNoError(err, "get chaos mesh controller pods error") err = wait.Poll(time.Second, 10*time.Second, func() (done bool, err error) { - newPods, err := kubeCli.CoreV1().Pods(cmNamespace).List(listOptions) + newPods, err := kubeCli.CoreV1().Pods(cmNamespace).List(context.TODO(), listOptions) framework.ExpectNoError(err, "get chaos mesh controller pods error") if !fixture.HaveSameUIDs(pods.Items, newPods.Items) { return true, nil } - if newPods.Items[0].Status.ContainerStatuses[0].RestartCount > 0 { + if len(newPods.Items) > 0 && newPods.Items[0].Status.ContainerStatuses[0].RestartCount > 0 { return true, nil } return false, nil @@ -92,16 +94,16 @@ selector: "app.kubernetes.io/component": "controller-manager", }).String(), } - pods, err := kubeCli.CoreV1().Pods(cmNamespace).List(listOptions) + pods, err := kubeCli.CoreV1().Pods(cmNamespace).List(context.TODO(), listOptions) framework.ExpectNoError(err, "get chaos mesh controller pods error") err = wait.Poll(time.Second, 10*time.Second, func() (done bool, err error) { - newPods, err := kubeCli.CoreV1().Pods(cmNamespace).List(listOptions) + newPods, err := kubeCli.CoreV1().Pods(cmNamespace).List(context.TODO(), listOptions) framework.ExpectNoError(err, "get chaos mesh controller pods error") if !fixture.HaveSameUIDs(pods.Items, newPods.Items) { return true, nil } - if newPods.Items[0].Status.ContainerStatuses[0].RestartCount > 0 { + if len(newPods.Items) > 0 && newPods.Items[0].Status.ContainerStatuses[0].RestartCount > 0 { return true, nil } return false, nil diff --git a/test/e2e/chaos/stresschaos/cpu.go b/e2e-test/e2e/chaos/stresschaos/cpu.go similarity index 91% rename from test/e2e/chaos/stresschaos/cpu.go rename to e2e-test/e2e/chaos/stresschaos/cpu.go index 1e53295d69..a5d78d98be 100644 --- a/test/e2e/chaos/stresschaos/cpu.go +++ b/e2e-test/e2e/chaos/stresschaos/cpu.go @@ -4,22 +4,23 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package stresschaos import ( "context" - "fmt" "net/http" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/kubernetes/test/e2e/framework" @@ -52,7 +53,7 @@ func TestcaseCPUStressInjectionOnceThenRecover( diff[1] = conditions[1].CpuTime - lastCPUTime[1] lastCPUTime[0] = conditions[0].CpuTime lastCPUTime[1] = conditions[1].CpuTime - By(fmt.Sprintf("get CPU: [%d, %d]", diff[0], diff[1])) + framework.Logf("get CPU: [%d, %d]", diff[0], diff[1]) // diff means the increasing CPU time (in nanosecond) // just pick two threshold, 5e8 is a little shorter than one second if diff[0] > 5e8 && diff[1] < 5e6 { @@ -78,7 +79,7 @@ func TestcaseCPUStressInjectionOnceThenRecover( diff[1] = conditions[1].CpuTime - lastCPUTime[1] lastCPUTime[0] = conditions[0].CpuTime lastCPUTime[1] = conditions[1].CpuTime - By(fmt.Sprintf("get CPU: [%d, %d]", diff[0], diff[1])) + framework.Logf("get CPU: [%d, %d]", diff[0], diff[1]) // diff means the increasing CPU time (in nanosecond) // just pick two threshold, they are both much shorter than 1 second if diff[0] < 1e7 && diff[1] < 5e6 { diff --git a/test/e2e/chaos/stresschaos/memory.go b/e2e-test/e2e/chaos/stresschaos/memory.go similarity index 76% rename from test/e2e/chaos/stresschaos/memory.go rename to e2e-test/e2e/chaos/stresschaos/memory.go index 82f104b489..d01b9d8001 100644 --- a/test/e2e/chaos/stresschaos/memory.go +++ b/e2e-test/e2e/chaos/stresschaos/memory.go @@ -4,12 +4,14 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package stresschaos @@ -19,7 +21,7 @@ import ( "net/http" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/kubernetes/test/e2e/framework" @@ -33,6 +35,11 @@ func TestcaseMemoryStressInjectionOnceThenRecover( ports []uint16, c http.Client, ) { + // it will raise two pod: stress-peer-0 and stress-peer-1, and we only inject StressChaos into stress-peer-0 + + // approximate equality within 5 MBytes (10% of injected 50M memory chaos) + const allowedJitter = 5 * 1024 * 1024 + ctx := context.Background() By("create memory stress chaos CRD objects") memoryStressChaos := makeMemoryStressChaos(ns, "memory-stress", ns, "stress-peer-0", "50M", 1) @@ -45,10 +52,10 @@ func TestcaseMemoryStressInjectionOnceThenRecover( if err != nil { return false, err } - if conditions[0].MemoryUsage-conditions[1].MemoryUsage > 50*1024*1024 { + framework.Logf("get Memory: [%d, %d]", conditions[0].MemoryUsage, conditions[1].MemoryUsage) + if int(conditions[0].MemoryUsage)-int(conditions[1].MemoryUsage) > allowedJitter { return true, nil } - By(fmt.Sprintf("get Memory: [%d, %d]", conditions[0].MemoryUsage, conditions[1].MemoryUsage)) return false, nil }) framework.ExpectNoError(err, "memory stress failed") @@ -62,10 +69,10 @@ func TestcaseMemoryStressInjectionOnceThenRecover( if err != nil { return false, err } - if conditions[0].MemoryUsage-conditions[1].MemoryUsage < 1*1024*1024 { + By(fmt.Sprintf("get Memory: [%d, %d]", conditions[0].MemoryUsage, conditions[1].MemoryUsage)) + if conditions[0].MemoryUsage < conditions[1].MemoryUsage+allowedJitter { return true, nil } - By(fmt.Sprintf("get Memory: [%d, %d]", conditions[0].MemoryUsage, conditions[1].MemoryUsage)) return false, nil }) framework.ExpectNoError(err, "fail to recover from memory stress") diff --git a/e2e-test/e2e/chaos/stresschaos/misc.go b/e2e-test/e2e/chaos/stresschaos/misc.go new file mode 100644 index 0000000000..3ed7d7a096 --- /dev/null +++ b/e2e-test/e2e/chaos/stresschaos/misc.go @@ -0,0 +1,140 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package stresschaos + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog/v2" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +func makeMemoryStressChaos( + namespace, name string, + podNs, podAppName string, memorySize string, worker int, +) *v1alpha1.StressChaos { + return &v1alpha1.StressChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: v1alpha1.StressChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Mode: v1alpha1.AllMode, + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{podNs}, + LabelSelectors: map[string]string{ + "app": podAppName, + }, + }, + }, + }, + }, + Stressors: &v1alpha1.Stressors{ + MemoryStressor: &v1alpha1.MemoryStressor{ + Size: memorySize, + Stressor: v1alpha1.Stressor{Workers: worker}, + }, + }, + }, + } +} + +func makeCPUStressChaos( + namespace, name string, + podNs, podAppName string, worker int, load int, +) *v1alpha1.StressChaos { + return &v1alpha1.StressChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: v1alpha1.StressChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Mode: v1alpha1.AllMode, + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{podNs}, + LabelSelectors: map[string]string{ + "app": podAppName, + }, + }, + }, + }, + }, + Stressors: &v1alpha1.Stressors{ + CPUStressor: &v1alpha1.CPUStressor{ + Load: &load, + Stressor: v1alpha1.Stressor{Workers: worker}, + }, + }, + }, + } +} + +type StressCondition struct { + CpuTime uint64 `json:"cpuTime"` + MemoryUsage uint64 `json:"memoryUsage"` +} + +func getStressCondition(c http.Client, port uint16) (*StressCondition, error) { + klog.Infof("sending request to http://localhost:%d/stress", port) + + resp, err := c.Get(fmt.Sprintf("http://localhost:%d/stress", port)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + out, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + condition := &StressCondition{} + err = json.Unmarshal(out, condition) + if err != nil { + return nil, err + } + + return condition, nil +} + +func probeStressCondition( + c http.Client, peers []*corev1.Pod, ports []uint16, +) (map[int]*StressCondition, error) { + stressConditions := make(map[int]*StressCondition) + + for index, port := range ports { + stressCondition, err := getStressCondition(c, port) + if err != nil { + return nil, err + } + + stressConditions[index] = stressCondition + } + + return stressConditions, nil +} diff --git a/e2e-test/e2e/chaos/testcasetemplate/template.go b/e2e-test/e2e/chaos/testcasetemplate/template.go new file mode 100644 index 0000000000..71062cec58 --- /dev/null +++ b/e2e-test/e2e/chaos/testcasetemplate/template.go @@ -0,0 +1,42 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package testcasetemplate + +import ( + . "github.com/onsi/ginkgo/v2" + "k8s.io/client-go/kubernetes" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func TestcaseTemplate( + ns string, + kubeCli kubernetes.Interface, + cli client.Client, + // any other parameters that you need fetch from context +) { + // describe test steps with By() statement + // here are some examples. + By("preparing experiment pods") + // some logic to create pod which will be injected chaos + By("create pod failure chaos CRD objects") + // create chaos CRD + By("waiting for assertion some pod fall into failure") + // assert that chaos is effective + By("delete pod failure chaos CRD objects") + // delete chaos CRD + By("waiting for assertion recovering") + // assert that chaos has gone +} diff --git a/e2e-test/e2e/chaos/timechaos/misc.go b/e2e-test/e2e/chaos/timechaos/misc.go new file mode 100644 index 0000000000..3a660e6894 --- /dev/null +++ b/e2e-test/e2e/chaos/timechaos/misc.go @@ -0,0 +1,63 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package timechaos + +import ( + "fmt" + "io" + "net/http" + "time" +) + +// get pod current time in nanosecond +func getPodTimeNS(c http.Client, port uint16) (*time.Time, error) { + resp, err := c.Get(fmt.Sprintf("http://localhost:%d/time", port)) + if err != nil { + return nil, err + } + + out, err := io.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + return nil, err + } + + t, err := time.Parse(time.RFC3339Nano, string(out)) + if err != nil { + return nil, err + } + return &t, nil +} + +// get pod current time in nanosecond +func getPodChildProcessTimeNS(c http.Client, port uint16) (*time.Time, error) { + resp, err := c.Get(fmt.Sprintf("http://localhost:%d/child-process-time", port)) + if err != nil { + return nil, err + } + + out, err := io.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + return nil, err + } + + t, err := time.Parse(time.RFC3339Nano, string(out)) + if err != nil { + return nil, err + } + return &t, nil +} diff --git a/e2e-test/e2e/chaos/timechaos/time_skew.go b/e2e-test/e2e/chaos/timechaos/time_skew.go new file mode 100644 index 0000000000..fcc44014d2 --- /dev/null +++ b/e2e-test/e2e/chaos/timechaos/time_skew.go @@ -0,0 +1,298 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package timechaos + +import ( + "context" + "net/http" + "time" + + . "github.com/onsi/ginkgo/v2" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/utils/pointer" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util" +) + +func TestcaseTimeSkewOnceThenRecover( + ns string, + cli client.Client, + c http.Client, + port uint16, +) { + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("wait e2e helper ready") + err := util.WaitE2EHelperReady(c, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + + By("create chaos CRD objects") + initTime, err := getPodTimeNS(c, port) + framework.ExpectNoError(err, "failed to get pod time") + + timeChaos := &v1alpha1.TimeChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "timer-time-chaos", + Namespace: ns, + }, + Spec: v1alpha1.TimeChaosSpec{ + Duration: pointer.StringPtr("9m"), + TimeOffset: "-1h", + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "timer"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + }, + }, + } + err = cli.Create(ctx, timeChaos) + framework.ExpectNoError(err, "create time chaos error") + + By("waiting for assertion") + err = wait.PollImmediate(5*time.Second, 5*time.Minute, func() (done bool, err error) { + podTime, err := getPodTimeNS(c, port) + framework.ExpectNoError(err, "failed to get pod time") + if podTime.Before(*initTime) { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "time chaos doesn't work as expected") + + By("delete chaos CRD objects") + err = cli.Delete(ctx, timeChaos) + framework.ExpectNoError(err, "failed to delete time chaos") + + By("waiting for assertion recovering") + err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { + podTime, err := getPodTimeNS(c, port) + framework.ExpectNoError(err, "failed to get pod time") + // since there is no timechaos now, current pod time should not be earlier + // than the init time + if podTime.Before(*initTime) { + return true, nil + } + return false, nil + }) + framework.ExpectError(err, "wait no timechaos error") + framework.ExpectEqual(err.Error(), wait.ErrWaitTimeout.Error()) + By("success to perform time chaos") +} + +func TestcaseTimeSkewPauseThenUnpause( + ns string, + cli client.Client, + c http.Client, + port uint16, +) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("wait e2e helper ready") + err := util.WaitE2EHelperReady(c, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + + initTime, err := getPodTimeNS(c, port) + framework.ExpectNoError(err, "failed to get pod time") + + By("create chaos CRD objects") + timeChaos := &v1alpha1.TimeChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "timer-time-chaos", + Namespace: ns, + }, + Spec: v1alpha1.TimeChaosSpec{ + Duration: pointer.StringPtr("9m"), + TimeOffset: "-1h", + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "timer"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + }, + }, + } + err = cli.Create(ctx, timeChaos) + framework.ExpectNoError(err, "create time chaos error") + + By("waiting for assertion") + err = wait.PollImmediate(5*time.Second, 5*time.Minute, func() (done bool, err error) { + podTime, err := getPodTimeNS(c, port) + framework.ExpectNoError(err, "failed to get pod time") + if podTime.Before(*initTime) { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "time chaos doesn't work as expected") + + chaosKey := types.NamespacedName{ + Namespace: ns, + Name: "timer-time-chaos", + } + + By("pause time skew chaos experiment") + // pause experiment + err = util.PauseChaos(ctx, cli, timeChaos) + framework.ExpectNoError(err, "pause chaos error") + + By("assert pause is effective") + err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.TimeChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get time chaos error") + if chaos.Status.Experiment.DesiredPhase == v1alpha1.StoppedPhase { + return true, nil + } + return false, err + }) + framework.ExpectNoError(err, "check paused chaos failed") + + // wait for 1 minutes and check timer + framework.ExpectNoError(err, "get timer pod error") + err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { + podTime, err := getPodTimeNS(c, port) + framework.ExpectNoError(err, "failed to get pod time") + if podTime.Before(*initTime) { + return true, nil + } + return false, nil + }) + framework.ExpectError(err, "wait time chaos paused error") + framework.ExpectEqual(err.Error(), wait.ErrWaitTimeout.Error()) + + By("resume time skew chaos experiment") + err = util.UnPauseChaos(ctx, cli, timeChaos) + framework.ExpectNoError(err, "resume chaos error") + + By("assert chaos experiment resumed") + err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { + chaos := &v1alpha1.TimeChaos{} + err = cli.Get(ctx, chaosKey, chaos) + framework.ExpectNoError(err, "get time chaos error") + if chaos.Status.Experiment.DesiredPhase == v1alpha1.RunningPhase { + return true, nil + } + return false, err + }) + framework.ExpectNoError(err, "check resumed chaos failed") + + // timechaos is running again, we want to check pod + // whether time is earlier than init time, + err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (done bool, err error) { + podTime, err := getPodTimeNS(c, port) + framework.ExpectNoError(err, "failed to get pod time") + if podTime.Before(*initTime) { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "time chaos failed") + + By("delete chaos CRD objects") + cli.Delete(ctx, timeChaos) +} + +func TestcaseTimeSkewShouldAlsoAffectChildProces( + ns string, + cli client.Client, + c http.Client, + port uint16, +) { + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + By("wait e2e helper ready") + err := util.WaitE2EHelperReady(c, port) + framework.ExpectNoError(err, "wait e2e helper ready error") + + By("create chaos CRD objects") + initTime, err := getPodChildProcessTimeNS(c, port) + framework.ExpectNoError(err, "failed to get pod time") + + timeChaos := &v1alpha1.TimeChaos{ + ObjectMeta: metav1.ObjectMeta{ + Name: "timer-time-chaos", + Namespace: ns, + }, + Spec: v1alpha1.TimeChaosSpec{ + Duration: pointer.StringPtr("9m"), + TimeOffset: "-1h", + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{"app": "timer"}, + }, + }, + Mode: v1alpha1.OneMode, + }, + }, + }, + } + err = cli.Create(ctx, timeChaos) + framework.ExpectNoError(err, "create time chaos error") + + By("waiting for assertion") + err = wait.PollImmediate(5*time.Second, 5*time.Minute, func() (done bool, err error) { + podTime, err := getPodChildProcessTimeNS(c, port) + framework.ExpectNoError(err, "failed to get pod time") + if podTime.Before(*initTime) { + return true, nil + } + return false, nil + }) + framework.ExpectNoError(err, "time chaos doesn't work as expected") + + By("delete chaos CRD objects") + err = cli.Delete(ctx, timeChaos) + framework.ExpectNoError(err, "failed to delete time chaos") + + By("waiting for assertion recovering") + err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { + podTime, err := getPodChildProcessTimeNS(c, port) + framework.ExpectNoError(err, "failed to get pod time") + // since there is no timechaos now, current pod time should not be earlier + // than the init time + if podTime.Before(*initTime) { + return true, nil + } + return false, nil + }) + framework.ExpectError(err, "wait no timechaos error") + framework.ExpectEqual(err.Error(), wait.ErrWaitTimeout.Error()) + By("success to perform time chaos") +} diff --git a/e2e-test/e2e/config/config.go b/e2e-test/e2e/config/config.go new file mode 100644 index 0000000000..c1cc2de5a5 --- /dev/null +++ b/e2e-test/e2e/config/config.go @@ -0,0 +1,55 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package config + +import ( + "flag" + + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + "k8s.io/kubernetes/test/e2e/framework" + + test "github.com/chaos-mesh/chaos-mesh/e2e-test" +) + +// TestConfig for the test config +var TestConfig = test.NewDefaultConfig() + +// RegisterOperatorFlags registers flags for chaos-mesh. +func RegisterOperatorFlags(flags *flag.FlagSet) { + flags.StringVar(&TestConfig.ManagerImage, "manager-image-registry", "ghcr.io", "chaos-mesh image registry") + flags.StringVar(&TestConfig.ManagerImage, "manager-image", "chaos-mesh/chaos-mesh", "chaos-mesh image") + flags.StringVar(&TestConfig.ManagerTag, "manager-image-tag", "latest", "chaos-mesh image tag") + flags.StringVar(&TestConfig.DaemonImage, "daemon-image-registry", "ghcr.io", "chaos-daemon image registry") + flags.StringVar(&TestConfig.DaemonImage, "daemon-image", "chaos-mesh/chaos-daemon", "chaos-daemon image") + flags.StringVar(&TestConfig.DaemonTag, "daemon-image-tag", "latest", "chaos-daemon image tag") + flags.StringVar(&TestConfig.E2EImage, "e2e-image", "chaos-mesh/e2e-helper:latest", "e2e-helper image") + flags.StringVar(&TestConfig.ChaosCoreDNSImage, "chaos-coredns-image", "chaos-mesh/chaos-coredns:v0.2.6", "chaos-coredns image") + flags.StringVar(&TestConfig.PauseImage, "pause-image", "gcr.io/google-containers/pause:latest", "custom pause container image for pod failure chaos") + flags.BoolVar(&TestConfig.InstallChaosMesh, "install-chaos-mesh", false, "automatically install chaos-mesh") + flags.BoolVar(&TestConfig.EnableDashboard, "enable-dashboard", false, "enable Chaos Dashboard") +} + +// LoadClientRawConfig would provide client raw config +func LoadClientRawConfig() (clientcmdapi.Config, error) { + loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() + loadingRules.ExplicitPath = framework.TestContext.KubeConfig + overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults} + if framework.TestContext.KubeContext != "" { + overrides.CurrentContext = framework.TestContext.KubeContext + } + return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides).RawConfig() +} diff --git a/e2e-test/e2e/config/restclientgetter.go b/e2e-test/e2e/config/restclientgetter.go new file mode 100644 index 0000000000..a95aa77d8f --- /dev/null +++ b/e2e-test/e2e/config/restclientgetter.go @@ -0,0 +1,94 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package config + +import ( + "path/filepath" + "regexp" + "strings" + "time" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/client-go/discovery" + diskcached "k8s.io/client-go/discovery/cached/disk" + "k8s.io/client-go/rest" + "k8s.io/client-go/restmapper" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + "k8s.io/client-go/util/homedir" +) + +var defaultCacheDir = filepath.Join(homedir.HomeDir(), ".kube", "http-cache") + +// simpleRestClientGetter implements genericclioptions.RESTClientGetter +type simpleRestClientGetter struct { + clientcmdapi.Config +} + +// ToRESTConfig returns restconfig +func (getter *simpleRestClientGetter) ToRESTConfig() (*rest.Config, error) { + return getter.ToRawKubeConfigLoader().ClientConfig() +} + +// ToDiscoveryClient returns discovery client +func (getter *simpleRestClientGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { + config, err := getter.ToRESTConfig() + if err != nil { + return nil, err + } + + config.Burst = 100 + + httpCacheDir := defaultCacheDir + discoveryCacheDir := computeDiscoverCacheDir(filepath.Join(homedir.HomeDir(), ".kube", "cache", "discovery"), config.Host) + + return diskcached.NewCachedDiscoveryClientForConfig(config, discoveryCacheDir, httpCacheDir, time.Duration(10*time.Minute)) +} + +// ToRESTMapper returns a restmapper +func (getter *simpleRestClientGetter) ToRESTMapper() (meta.RESTMapper, error) { + discoveryClient, err := getter.ToDiscoveryClient() + if err != nil { + return nil, err + } + + mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) + expander := restmapper.NewShortcutExpander(mapper, discoveryClient) + return expander, nil +} + +// ToRawKubeConfigLoader return kubeconfig loader as-is +func (getter *simpleRestClientGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig { + return clientcmd.NewDefaultClientConfig(getter.Config, &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults}) +} + +// overlyCautiousIllegalFileCharacters matches characters that *might* not be supported. Windows is really restrictive, so this is really restrictive +var overlyCautiousIllegalFileCharacters = regexp.MustCompile(`[^(\w/\.)]`) + +// computeDiscoverCacheDir takes the parentDir and the host and comes up with a "usually non-colliding" name. +func computeDiscoverCacheDir(parentDir, host string) string { + // strip the optional scheme from host if its there: + schemelessHost := strings.Replace(strings.Replace(host, "https://", "", 1), "http://", "", 1) + // now do a simple collapse of non-AZ09 characters. Collisions are possible but unlikely. Even if we do collide the problem is short lived + safeHost := overlyCautiousIllegalFileCharacters.ReplaceAllString(schemelessHost, "_") + return filepath.Join(parentDir, safeHost) +} + +// NewSimpleRESTClientGetter initializes a new genericclioptions.RESTClientGetter from clientcmdapi.Config. +func NewSimpleRESTClientGetter(config clientcmdapi.Config) genericclioptions.RESTClientGetter { + return &simpleRestClientGetter{config} +} diff --git a/e2e-test/e2e/e2e.go b/e2e-test/e2e/e2e.go new file mode 100644 index 0000000000..434e8576bf --- /dev/null +++ b/e2e-test/e2e/e2e.go @@ -0,0 +1,177 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package e2e + +import ( + "context" // load pprof + _ "net/http/pprof" + "os/exec" + "time" + + "github.com/onsi/ginkgo/v2" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + _ "k8s.io/client-go/plugin/pkg/client/auth" + "k8s.io/klog/v2" + _ "k8s.io/kubelet" + "k8s.io/kubernetes/test/e2e/framework" + e2edebug "k8s.io/kubernetes/test/e2e/framework/debug" + e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl" + e2enode "k8s.io/kubernetes/test/e2e/framework/node" + e2epod "k8s.io/kubernetes/test/e2e/framework/pod" + utilnet "k8s.io/utils/net" + + test "github.com/chaos-mesh/chaos-mesh/e2e-test" + e2econfig "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/config" // ensure auth plugins are loaded +) + +const namespaceCleanupTimeout = 15 * time.Minute + +// This is modified from framework.SetupSuite(). +// setupSuite is the boilerplate that can be used to setup ginkgo test suites, on the SynchronizedBeforeSuite step. +// There are certain operations we only want to run once per overall test invocation +// (such as deleting old namespaces, or verifying that all system pods are running. +// Because of the way Ginkgo runs tests in parallel, we must use SynchronizedBeforeSuite +// to ensure that these operations only run on the first parallel Ginkgo node. +func setupSuite(ctx context.Context) { + // Run only on Ginkgo node 1 + + c, err := framework.LoadClientset() + if err != nil { + klog.Fatal("Error loading client: ", err) + } + + // Delete any namespaces except those created by the system. This ensures no + // lingering resources are left over from a previous test run. + if framework.TestContext.CleanStart { + deleted, err := framework.DeleteNamespaces(ctx, c, nil, /* deleteFilter */ + []string{ + metav1.NamespaceSystem, + metav1.NamespaceDefault, + metav1.NamespacePublic, + v1.NamespaceNodeLease, + // kind local path provisioner namespace since 0.7.0 + // https://github.com/kubernetes-sigs/kind/blob/v0.7.0/pkg/build/node/storage.go#L35 + "local-path-storage", + }) + if err != nil { + framework.Failf("Error deleting orphaned namespaces: %v", err) + } + klog.Infof("Waiting for deletion of the following namespaces: %v", deleted) + if err := framework.WaitForNamespacesDeleted(ctx, c, deleted, namespaceCleanupTimeout); err != nil { + framework.Failf("Failed to delete orphaned namespaces %v: %v", deleted, err) + } + } + + timeouts := framework.NewTimeoutContext() + + // In large clusters we may get to this point but still have a bunch + // of nodes without Routes created. Since this would make a node + // unschedulable, we need to wait until all of them are schedulable. + framework.ExpectNoError(e2enode.WaitForAllNodesSchedulable(ctx, c, timeouts.NodeSchedulable)) + + //// If NumNodes is not specified then auto-detect how many are scheduleable and not tainted + //if framework.TestContext.CloudConfig.NumNodes == framework.DefaultNumNodes { + // framework.TestContext.CloudConfig.NumNodes = len(framework.GetReadySchedulableNodesOrDie(c).Items) + //} + + // Ensure all pods are running and ready before starting tests (otherwise, + // cluster infrastructure pods that are being pulled or started can block + // test pods from running, and tests that ensure all pods are running and + // ready will fail). + podStartupTimeout := timeouts.SystemPodsStartup + // TODO: In large clusters, we often observe a non-starting pods due to + // #41007. To avoid those pods preventing the whole test runs (and just + // wasting the whole run), we allow for some not-ready pods (with the + // number equal to the number of allowed not-ready nodes). + if err := e2epod.WaitForPodsRunningReady(ctx, c, metav1.NamespaceSystem, int32(framework.TestContext.MinStartupPods), int32(framework.TestContext.AllowedNotReadyNodes), podStartupTimeout); err != nil { + e2edebug.DumpAllNamespaceInfo(ctx, c, metav1.NamespaceSystem) + e2ekubectl.LogFailedContainers(ctx, c, metav1.NamespaceSystem, framework.Logf) + framework.Failf("Error waiting for all pods to be running and ready: %v", err) + } + + //if err := framework.WaitForDaemonSets(c, metav1.NamespaceSystem, int32(framework.TestContext.AllowedNotReadyNodes), framework.TestContext.SystemDaemonsetStartupTimeout); err != nil { + // framework.Logf("WARNING: Waiting for all daemonsets to be ready failed: %v", err) + //} + + dc := c.DiscoveryClient + + serverVersion, serverErr := dc.ServerVersion() + if serverErr != nil { + framework.Logf("Unexpected server error retrieving version: %v", serverErr) + } + if serverVersion != nil { + framework.Logf("kube-apiserver version: %s", serverVersion.GitVersion) + } +} + +var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { + if e2econfig.TestConfig.InstallChaosMesh { + ginkgo.By("Clear all helm releases") + helmClearCmd := "helm ls --all --short | xargs -n 1 -r helm delete --purge" + if err := exec.Command("sh", "-c", helmClearCmd).Run(); err != nil { + framework.Failf("failed to clear helm releases (cmd: %q, error: %v", helmClearCmd, err) + } + ginkgo.By("Clear non-kubernetes apiservices") + clearNonK8SAPIServicesCmd := "kubectl delete apiservices -l kube-aggregator.kubernetes.io/automanaged!=onstart" + if err := exec.Command("sh", "-c", clearNonK8SAPIServicesCmd).Run(); err != nil { + framework.Failf("failed to clear non-kubernetes apiservices (cmd: %q, error: %v", clearNonK8SAPIServicesCmd, err) + } + + setupSuite(context.Background()) + + // Get clients + oa, ocfg, err := test.BuildOperatorActionAndCfg(e2econfig.TestConfig) + framework.ExpectNoError(err, "failed to create operator action") + oa.CleanCRDOrDie() + err = oa.InstallCRD(ocfg) + framework.ExpectNoError(err, "failed to install crd") + err = oa.DeployOperator(ocfg) + framework.ExpectNoError(err, "failed to install chaos-mesh") + } + return nil +}, func(data []byte) { + // Run on all Ginkgo nodes + setupSuitePerGinkgoNode() +}) + +func setupSuitePerGinkgoNode() { + c, err := framework.LoadClientset() + if err != nil { + klog.Fatal("Error loading client: ", err) + } + framework.TestContext.IPFamily = getDefaultClusterIPFamily(c) + framework.Logf("Cluster IP family: %s", framework.TestContext.IPFamily) +} + +// getDefaultClusterIPFamily obtains the default IP family of the cluster +// using the Cluster IP address of the kubernetes service created in the default namespace +// This unequivocally identifies the default IP family because services are single family +// TODO: dual-stack may support multiple families per service +// but we can detect if a cluster is dual stack because pods have two addresses (one per family) +func getDefaultClusterIPFamily(c kubernetes.Interface) string { + // Get the ClusterIP of the kubernetes service created in the default namespace + svc, err := c.CoreV1().Services(metav1.NamespaceDefault).Get(context.TODO(), "kubernetes", metav1.GetOptions{}) + if err != nil { + framework.Failf("Failed to get kubernetes service ClusterIP: %v", err) + } + + if utilnet.IsIPv6String(svc.Spec.ClusterIP) { + return "ipv6" + } + return "ipv4" +} diff --git a/e2e-test/e2e/e2e_test.go b/e2e-test/e2e/e2e_test.go new file mode 100644 index 0000000000..51b544fb5e --- /dev/null +++ b/e2e-test/e2e/e2e_test.go @@ -0,0 +1,113 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package e2e + +import ( + "flag" + "math/rand" + "os" + "testing" + "time" + + "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + runtimeutils "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/component-base/logs" + "k8s.io/klog/v2" + "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/kubernetes/test/e2e/framework/config" + "k8s.io/kubernetes/test/e2e/framework/testfiles" + + _ "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/chaos" + e2econfig "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/config" // test sources +) + +// handleFlags sets up all flags and parses the command line. +func handleFlags() { + config.CopyFlags(config.Flags, flag.CommandLine) + framework.RegisterCommonFlags(flag.CommandLine) + hackRegisterClusterFlags(flag.CommandLine) + e2econfig.RegisterOperatorFlags(flag.CommandLine) + flag.Parse() +} + +func TestMain(m *testing.M) { + // Register test flags, then parse flags. + handleFlags() + + framework.AfterReadingAllFlags(&framework.TestContext) + + if framework.TestContext.RepoRoot != "" { + testfiles.AddFileSource(testfiles.RootFileSource{Root: framework.TestContext.RepoRoot}) + } + + rand.Seed(time.Now().UnixNano()) + os.Exit(m.Run()) +} + +func TestE2E(t *testing.T) { + RunE2ETests(t) +} + +func RunE2ETests(t *testing.T) { + runtimeutils.ReallyCrash = true + logs.InitLogs() + defer logs.FlushLogs() + + gomega.RegisterFailHandler(framework.Fail) + + // Run tests through the Ginkgo runner with output to console + suite, _ := ginkgo.GinkgoConfiguration() + klog.Infof("Starting e2e run %q on Ginkgo node %d", framework.RunID, suite.ParallelProcess) + + ginkgo.RunSpecs(t, "chaosmesh e2e suit") +} + +// we hack framework.RegisterClusterFlags to avoid redefine flag error +// caused by controller-runtime client +func hackRegisterClusterFlags(flags *flag.FlagSet) { + framework.TestContext.KubeConfig = os.Getenv("KUBECONFIG") + if len(framework.TestContext.KubeConfig) < 1 { + klog.Fatalf("KUBECONFIG ENV NOT SET") + } + flags.BoolVar(&framework.TestContext.VerifyServiceAccount, "e2e-verify-service-account", true, "If true tests will verify the service account before running.") + flags.StringVar(&framework.TestContext.KubeContext, clientcmd.FlagContext, "", "kubeconfig context to use/override. If unset, will use value from 'current-context'") + flags.StringVar(&framework.TestContext.KubeAPIContentType, "kube-api-content-type", "application/vnd.kubernetes.protobuf", "ContentType used to communicate with apiserver") + + flags.StringVar(&framework.TestContext.CertDir, "cert-dir", "", "Path to the directory containing the certs. Default is empty, which doesn't use certs.") + flags.StringVar(&framework.TestContext.RepoRoot, "repo-root", "../../", "Root directory of kubernetes repository, for finding test files.") + flags.StringVar(&framework.TestContext.Provider, "provider", "", "The name of the Kubernetes provider (gce, gke, local, skeleton (the fallback if not set), etc.)") + flags.StringVar(&framework.TestContext.Tooling, "tooling", "", "The tooling in use (kops, gke, etc.)") + flags.StringVar(&framework.TestContext.OutputDir, "e2e-output-dir", "/tmp", "Output directory for interesting/useful test data, like performance data, benchmarks, and other metrics.") + flags.StringVar(&framework.TestContext.Prefix, "prefix", "e2e", "A prefix to be added to cloud resources created during testing.") + flags.StringVar(&framework.TestContext.MasterOSDistro, "master-os-distro", "debian", "The OS distribution of cluster master (debian, ubuntu, gci, coreos, or custom).") + flags.StringVar(&framework.TestContext.NodeOSDistro, "node-os-distro", "debian", "The OS distribution of cluster VM instances (debian, ubuntu, gci, coreos, or custom).") + flags.StringVar(&framework.TestContext.ClusterDNSDomain, "dns-domain", "cluster.local", "The DNS Domain of the cluster.") + + flags.IntVar(&framework.TestContext.MinStartupPods, "minStartupPods", 0, "The number of pods which we need to see in 'Running' state with a 'Ready' condition of true, before we try running tests. This is useful in any cluster which needs some base pod-based services running before it can be used.") + flags.StringVar(&framework.TestContext.EtcdUpgradeStorage, "etcd-upgrade-storage", "", "The storage version to upgrade to (either 'etcdv2' or 'etcdv3') if doing an etcd upgrade test.") + flags.StringVar(&framework.TestContext.EtcdUpgradeVersion, "etcd-upgrade-version", "", "The etcd binary version to upgrade to (e.g., '3.0.14', '2.3.7') if doing an etcd upgrade test.") + flags.StringVar(&framework.TestContext.GCEUpgradeScript, "gce-upgrade-script", "", "Script to use to upgrade a GCE cluster.") + flags.BoolVar(&framework.TestContext.CleanStart, "clean-start", false, "If true, purge all namespaces except default and system before running tests. This serves to Cleanup test namespaces from failed/interrupted e2e runs in a long-lived cluster.") + + nodeKiller := &framework.TestContext.NodeKiller + flags.BoolVar(&nodeKiller.Enabled, "node-killer", false, "Whether NodeKiller should kill any nodes.") + flags.Float64Var(&nodeKiller.FailureRatio, "node-killer-failure-ratio", 0.01, "Percentage of nodes to be killed") + flags.DurationVar(&nodeKiller.Interval, "node-killer-interval", 1*time.Minute, "Time between node failures.") + flags.Float64Var(&nodeKiller.JitterFactor, "node-killer-jitter-factor", 60, "Factor used to jitter node failures.") + flags.DurationVar(&nodeKiller.SimulatedDowntime, "node-killer-simulated-downtime", 10*time.Minute, "A delay between node death and recreation") +} diff --git a/e2e-test/e2e/e2econst/const.go b/e2e-test/e2e/e2econst/const.go new file mode 100644 index 0000000000..7cb5f77b00 --- /dev/null +++ b/e2e-test/e2e/e2econst/const.go @@ -0,0 +1,21 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package e2econst + +const ( + ChaosMeshNamespace = "chaos-mesh" + ChaosControllerManager = "chaos-controller-manager" +) diff --git a/e2e-test/e2e/util/util.go b/e2e-test/e2e/util/util.go new file mode 100644 index 0000000000..c6b1d16e7b --- /dev/null +++ b/e2e-test/e2e/util/util.go @@ -0,0 +1,193 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package util + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + "time" + + apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" + apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" + aggregatorclientset "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset" + "k8s.io/kubernetes/test/e2e/framework" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +// WaitForAPIServicesAvailable waits for apiservices to be available +func WaitForAPIServicesAvailable(client aggregatorclientset.Interface, selector labels.Selector) error { + isAvailable := func(status apiregistrationv1.APIServiceStatus) bool { + if status.Conditions == nil { + return false + } + for _, condition := range status.Conditions { + if condition.Type == apiregistrationv1.Available { + return condition.Status == apiregistrationv1.ConditionTrue + } + } + return false + } + return wait.PollImmediate(5*time.Second, 3*time.Minute, func() (bool, error) { + apiServiceList, err := client.ApiregistrationV1().APIServices().List( + context.TODO(), + metav1.ListOptions{ + LabelSelector: selector.String(), + }) + if err != nil { + return false, err + } + for _, apiService := range apiServiceList.Items { + if !isAvailable(apiService.Status) { + framework.Logf("APIService %q is not available yet", apiService.Name) + return false, nil + } + } + for _, apiService := range apiServiceList.Items { + framework.Logf("APIService %q is available", apiService.Name) + } + return true, nil + }) +} + +// WaitForCRDsEstablished waits for all CRDs to be established +func WaitForCRDsEstablished(client apiextensionsclientset.Interface, selector labels.Selector) error { + isEstablished := func(status apiextensionsv1beta1.CustomResourceDefinitionStatus) bool { + if status.Conditions == nil { + return false + } + for _, condition := range status.Conditions { + if condition.Type == apiextensionsv1beta1.Established { + return condition.Status == apiextensionsv1beta1.ConditionTrue + } + } + return false + } + return wait.PollImmediate(5*time.Second, 3*time.Minute, func() (bool, error) { + crdList, err := client.ApiextensionsV1beta1().CustomResourceDefinitions().List( + context.TODO(), + metav1.ListOptions{ + LabelSelector: selector.String(), + }) + if err != nil { + return false, err + } + for _, crd := range crdList.Items { + if !isEstablished(crd.Status) { + framework.Logf("CRD %q is not established yet", crd.Name) + return false, nil + } + } + for _, crd := range crdList.Items { + framework.Logf("CRD %q is established", crd.Name) + } + return true, nil + }) +} + +// WaitDeploymentReady waits for all pods which controlled by deployment to be ready. +func WaitDeploymentReady(name, namespace string, cli kubernetes.Interface) error { + return wait.Poll(2*time.Second, 5*time.Minute, func() (done bool, err error) { + d, err := cli.AppsV1().Deployments(namespace).Get( + context.TODO(), + name, + metav1.GetOptions{}, + ) + if err != nil { + return false, nil + } + if d.Status.AvailableReplicas != *d.Spec.Replicas { + return false, nil + } + if d.Status.UpdatedReplicas != *d.Spec.Replicas { + return false, nil + } + return true, nil + }) +} + +func PauseChaos(ctx context.Context, cli client.Client, chaos client.Object) error { + var mergePatch []byte + mergePatch, _ = json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "annotations": map[string]string{v1alpha1.PauseAnnotationKey: "true"}, + }, + }) + return cli.Patch(ctx, chaos, client.RawPatch(types.MergePatchType, mergePatch)) +} + +func UnPauseChaos(ctx context.Context, cli client.Client, chaos client.Object) error { + var mergePatch []byte + mergePatch, _ = json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "annotations": map[string]string{v1alpha1.PauseAnnotationKey: "false"}, + }, + }) + return cli.Patch(ctx, chaos, client.RawPatch(types.MergePatchType, mergePatch)) +} + +func WaitE2EHelperReady(c http.Client, port uint16) error { + return wait.Poll(2*time.Second, 5*time.Minute, func() (done bool, err error) { + if _, err = c.Get(fmt.Sprintf("http://localhost:%d/ping", port)); err != nil { + return false, nil + } + return true, nil + }) +} + +func WaitHTTPE2EHelperReady(c http.Client, ip string, port uint16) error { + return wait.Poll(2*time.Second, 5*time.Minute, func() (done bool, err error) { + if _, err = c.Get(fmt.Sprintf("http://%s:%d/ping", ip, port)); err != nil { + framework.Logf("Err : %v , IP : %s", err, ip) + return false, nil + } + return true, nil + }) +} + +func SetupHTTPE2EHelperTLSConfig(c http.Client, ip string, port uint16, tls_port uint16, body []byte) error { + return wait.Poll(2*time.Second, 5*time.Minute, func() (done bool, err error) { + if _, err = c.Post(fmt.Sprintf("http://%s:%d/setup_https", ip, port), "application/json", bytes.NewBuffer(body)); err != nil { + framework.Logf("Err : %v , IP : %s", err, ip) + return false, nil + } + if _, err = c.Get(fmt.Sprintf("https://%s:%d/ping", ip, tls_port)); err != nil { + framework.Logf("Err : %v , IP : %s", err, ip) + return false, nil + } + return true, nil + }) +} + +func WaitHTTPE2EHelperTLSReady(c http.Client, ip string, port uint16) error { + return wait.Poll(2*time.Second, 5*time.Minute, func() (done bool, err error) { + if _, err = c.Get(fmt.Sprintf("https://%s:%d/ping", ip, port)); err != nil { + framework.Logf("Err : %v , IP : %s", err, ip) + return false, nil + } + return true, nil + }) +} diff --git a/e2e-test/go.mod b/e2e-test/go.mod new file mode 100644 index 0000000000..1f3d2cd51b --- /dev/null +++ b/e2e-test/go.mod @@ -0,0 +1,182 @@ +module github.com/chaos-mesh/chaos-mesh/e2e-test + +go 1.20 + +require ( + github.com/chaos-mesh/chaos-mesh v0.0.0-00010101000000-000000000000 + github.com/chaos-mesh/chaos-mesh/api v0.0.0 + github.com/onsi/ginkgo/v2 v2.12.0 + github.com/onsi/gomega v1.27.10 + github.com/pkg/errors v0.9.1 + k8s.io/api v0.28.4 + k8s.io/apiextensions-apiserver v0.28.4 + k8s.io/apimachinery v0.28.4 + k8s.io/cli-runtime v0.28.4 + k8s.io/client-go v0.28.4 + k8s.io/component-base v0.28.4 + k8s.io/klog/v2 v2.100.1 + k8s.io/kube-aggregator v0.28.1 + k8s.io/kubelet v0.28.1 + k8s.io/kubernetes v1.28.2 + k8s.io/pod-security-admission v0.28.1 + k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 + sigs.k8s.io/controller-runtime v0.16.2 +) + +require ( + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/MakeNowJust/heredoc v1.0.0 // indirect + github.com/NYTimes/gziphandler v1.1.1 // indirect + github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect + github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect + github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chai2010/gettext-go v1.0.2 // indirect + github.com/coreos/go-semver v0.3.1 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/emicklei/go-restful/v3 v3.10.1 // indirect + github.com/evanphx/json-patch v5.6.0+incompatible // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect + github.com/fatih/camelcase v1.0.0 // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-errors/errors v1.4.2 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-logr/zapr v1.2.4 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/btree v1.0.1 // indirect + github.com/google/cel-go v0.16.1 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/google/uuid v1.3.1 // indirect + github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect + github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/prometheus/client_golang v1.16.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/spf13/cobra v1.7.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/xlab/treeprint v1.2.0 // indirect + go.etcd.io/etcd/api/v3 v3.5.9 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect + go.etcd.io/etcd/client/v3 v3.5.9 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect + go.opentelemetry.io/otel v1.19.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/otel/sdk v1.19.0 // indirect + go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.opentelemetry.io/proto/otlp v1.0.0 // indirect + go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.25.0 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.12.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/grpc v1.58.3 // indirect + google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiserver v0.28.4 // indirect + k8s.io/cloud-provider v0.0.0 // indirect + k8s.io/component-helpers v0.28.2 // indirect + k8s.io/controller-manager v0.28.2 // indirect + k8s.io/kms v0.28.2 // indirect + k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect + k8s.io/kubectl v0.28.4 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect + sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) + +replace ( + github.com/chaos-mesh/chaos-mesh => ../ + github.com/chaos-mesh/chaos-mesh/api => ../api + k8s.io/api => k8s.io/api v0.28.2 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.28.2 + k8s.io/apimachinery => k8s.io/apimachinery v0.28.2 + k8s.io/apiserver => k8s.io/apiserver v0.28.2 + k8s.io/cli-runtime => k8s.io/cli-runtime v0.28.2 + k8s.io/client-go => k8s.io/client-go v0.28.2 + k8s.io/cloud-provider => k8s.io/cloud-provider v0.28.2 + k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.28.2 + k8s.io/code-generator => k8s.io/code-generator v0.28.2 + k8s.io/component-base => k8s.io/component-base v0.28.2 + k8s.io/component-helpers => k8s.io/component-helpers v0.28.2 + k8s.io/controller-manager => k8s.io/controller-manager v0.28.2 + k8s.io/cri-api => k8s.io/cri-api v0.28.2 + k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.28.2 + k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.28.2 + k8s.io/endpointslice => k8s.io/endpointslice v0.28.2 + k8s.io/kms => k8s.io/kms v0.28.2 + k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.28.2 + k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.28.2 + k8s.io/kube-proxy => k8s.io/kube-proxy v0.28.2 + k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.28.2 + k8s.io/kubectl => k8s.io/kubectl v0.28.2 + k8s.io/kubelet => k8s.io/kubelet v0.28.2 + k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.28.2 + k8s.io/metrics => k8s.io/metrics v0.28.2 + k8s.io/mount-utils => k8s.io/mount-utils v0.28.2 + k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.28.2 + k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.28.2 + k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.28.2 + k8s.io/sample-controller => k8s.io/sample-controller v0.28.2 +) diff --git a/e2e-test/go.sum b/e2e-test/go.sum new file mode 100644 index 0000000000..1daed38ee9 --- /dev/null +++ b/e2e-test/go.sum @@ -0,0 +1,459 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk= +cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= +github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bxcodec/faker v2.0.1+incompatible h1:P0KUpUw5w6WJXwrPfv35oc91i4d8nf40Nwln+M/+faA= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= +github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= +github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= +github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= +github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/cel-go v0.16.1 h1:3hZfSNiAU3KOiNtxuFXVp5WFy4hf/Ly3Sa4/7F8SXNo= +github.com/google/cel-go v0.16.1/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= +github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/onsi/ginkgo/v2 v2.12.0 h1:UIVDowFPwpg6yMUpPjGkYvf06K3RAiJXUhCxEwQVHRI= +github.com/onsi/ginkgo/v2 v2.12.0/go.mod h1:ZNEzXISYlqpb8S36iN71ifqLi3vVD1rVJGvWRCJOUpQ= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= +github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= +github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= +go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= +go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= +go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= +go.etcd.io/etcd/client/v2 v2.305.9 h1:YZ2OLi0OvR0H75AcgSUajjd5uqKDKocQUqROTG11jIo= +go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= +go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= +go.etcd.io/etcd/pkg/v3 v3.5.9 h1:6R2jg/aWd/zB9+9JxmijDKStGJAPFsX3e6BeJkMi6eQ= +go.etcd.io/etcd/raft/v3 v3.5.9 h1:ZZ1GIHoUlHsn0QVqiRysAm3/81Xx7+i2d7nSdWxlOiI= +go.etcd.io/etcd/server/v3 v3.5.9 h1:vomEmmxeztLtS5OEH7d0hBAg4cjVIu9wXuNzUZx2ZA0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= +go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= +go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= +golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= +google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= +k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= +k8s.io/apiextensions-apiserver v0.28.2 h1:J6/QRWIKV2/HwBhHRVITMLYoypCoPY1ftigDM0Kn+QU= +k8s.io/apiextensions-apiserver v0.28.2/go.mod h1:5tnkxLGa9nefefYzWuAlWZ7RZYuN/765Au8cWLA6SRg= +k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= +k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= +k8s.io/apiserver v0.28.2 h1:rBeYkLvF94Nku9XfXyUIirsVzCzJBs6jMn3NWeHieyI= +k8s.io/apiserver v0.28.2/go.mod h1:f7D5e8wH8MWcKD7azq6Csw9UN+CjdtXIVQUyUhrtb+E= +k8s.io/cli-runtime v0.28.2 h1:64meB2fDj10/ThIMEJLO29a1oujSm0GQmKzh1RtA/uk= +k8s.io/cli-runtime v0.28.2/go.mod h1:bTpGOvpdsPtDKoyfG4EG041WIyFZLV9qq4rPlkyYfDA= +k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= +k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= +k8s.io/cloud-provider v0.28.2 h1:9qsYm86hm4bnPgZbl9LE29Zfgjuq3NZR2dgtPioJ40s= +k8s.io/cloud-provider v0.28.2/go.mod h1:40fqf6MtgYho5Eu4gkyLgh5abxU/QKTMTIwBxt4ILyU= +k8s.io/component-base v0.28.2 h1:Yc1yU+6AQSlpJZyvehm/NkJBII72rzlEsd6MkBQ+G0E= +k8s.io/component-base v0.28.2/go.mod h1:4IuQPQviQCg3du4si8GpMrhAIegxpsgPngPRR/zWpzc= +k8s.io/component-helpers v0.28.2 h1:r/XJ265PMirW9EcGXr/F+2yWrLPo2I69KdvcY/h9HAo= +k8s.io/component-helpers v0.28.2/go.mod h1:pF1R5YWQ+sgf0i6EbVm+MQCzkYuqutDUibdrkvAa6aI= +k8s.io/controller-manager v0.28.2 h1:C2RKx+NH3Iw+4yLdTGNJlYUd4cRV1N8tKl4XfqMwuTk= +k8s.io/controller-manager v0.28.2/go.mod h1:7bT6FlTE96Co7QevCtvcVnZZIJSaGj6F7EmyT2Rf3GY= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kms v0.28.2 h1:KhG63LHopCdzs1oKA1j+NWleuIXudgOyCqJo4yi3GaM= +k8s.io/kms v0.28.2/go.mod h1:iAjgIqBrV2+8kmsjbbgUkAyKSuYq5g1dW9knpt6OhaE= +k8s.io/kube-aggregator v0.28.2 h1:tCjAfB1p/v18yD2NpegNQRuahzyA/szFfcRARnpjDeo= +k8s.io/kube-aggregator v0.28.2/go.mod h1:g4hZVjC4KhJtZHV2pyiRBiU6AdBA/sAjh9Y9GJC/SbU= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= +k8s.io/kubectl v0.28.2 h1:fOWOtU6S0smdNjG1PB9WFbqEIMlkzU5ahyHkc7ESHgM= +k8s.io/kubectl v0.28.2/go.mod h1:6EQWTPySF1fn7yKoQZHYf9TPwIl2AygHEcJoxFekr64= +k8s.io/kubelet v0.28.2 h1:wqe5zKtVhNWwtdABU0mpcWVe8hc6VdVvs2kqQridZRw= +k8s.io/kubelet v0.28.2/go.mod h1:rvd0e7T5TjPcfZvy62P90XhFzp0IhPIOy+Pqy3Rtipo= +k8s.io/kubernetes v1.28.2 h1:GhcnYeNTukeaC0dD5BC+UWBvzQsFEpWj7XBVMQptfYc= +k8s.io/kubernetes v1.28.2/go.mod h1:FmB1Mlp9ua0ezuwQCTGs/y6wj/fVisN2sVxhzjj0WDk= +k8s.io/pod-security-admission v0.28.2 h1:3kiOL+gc6auNTGHuQ0hVsGxYu2YO/7DZb0xYR84GxiQ= +k8s.io/pod-security-admission v0.28.2/go.mod h1:gReea39xbhIzf4Ry0FDuiTi8uj1N5R9YXOh8zQSuTxs= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 h1:trsWhjU5jZrx6UvFu4WzQDrN7Pga4a7Qg+zcfcj64PA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2/go.mod h1:+qG7ISXqCDVVcyO8hLn12AKVYYUjM7ftlqsqmrhMZE0= +sigs.k8s.io/controller-runtime v0.16.2 h1:mwXAVuEk3EQf478PQwQ48zGOXvW27UJc8NHktQVuIPU= +sigs.k8s.io/controller-runtime v0.16.2/go.mod h1:vpMu3LpI5sYWtujJOa2uPK61nB5rbwlN7BAB8aSLvGU= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= +sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= +sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= +sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/e2e-test/image/e2e/Dockerfile b/e2e-test/image/e2e/Dockerfile new file mode 100644 index 0000000000..f12e942c6b --- /dev/null +++ b/e2e-test/image/e2e/Dockerfile @@ -0,0 +1,22 @@ +FROM alpine:3.12 + +ENV KUBECTL_VERSION=v1.28.1 +ENV HELM_VERSION=v3.12.3 + +RUN apk update && apk add --no-cache ca-certificates curl git openssl bash +RUN curl https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl \ + -o /usr/local/bin/kubectl && \ + chmod +x /usr/local/bin/kubectl && \ + curl https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz \ + -o helm-${HELM_VERSION}-linux-amd64.tar.gz && \ + tar -zxvf helm-${HELM_VERSION}-linux-amd64.tar.gz && \ + mv linux-amd64/helm /usr/local/bin/helm && \ + rm -rf linux-amd64 && \ + rm helm-${HELM_VERSION}-linux-amd64.tar.gz + + +ADD chaos-mesh /charts/e2e/chaos-mesh +ADD manifests /manifests/e2e + +ADD bin/ginkgo /usr/local/bin/ +ADD bin/e2e.test /usr/local/bin/ diff --git a/test/pkg/fixture/fixture.go b/e2e-test/pkg/fixture/fixture.go similarity index 86% rename from test/pkg/fixture/fixture.go rename to e2e-test/pkg/fixture/fixture.go index 3126cb23b1..7f99d20bcd 100644 --- a/test/pkg/fixture/fixture.go +++ b/e2e-test/pkg/fixture/fixture.go @@ -1,30 +1,31 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package fixture import ( "sort" - "k8s.io/apimachinery/pkg/api/resource" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/pointer" - "github.com/chaos-mesh/chaos-mesh/test/e2e/config" + "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/config" ) // NewCommonNginxPod describe that we use common nginx pod to be tested in our chaos-operator test @@ -199,7 +200,7 @@ func NewStressTestDeployment(name, namespace string, extraLabels map[string]stri }, Limits: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("1"), - corev1.ResourceMemory: resource.MustParse("100M"), + corev1.ResourceMemory: resource.MustParse("150M"), }, }, VolumeMounts: []corev1.VolumeMount{ @@ -281,6 +282,44 @@ func NewIOTestDeployment(name, namespace string) *appsv1.Deployment { } } +// NewHTTPTestDeployment creates a deployment for e2e test +func NewHTTPTestDeployment(name, namespace string) *appsv1.Deployment { + return &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: map[string]string{ + "app": "http", + }, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: pointer.Int32Ptr(1), + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "http", + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app": "http", + }, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Image: config.TestConfig.E2EImage, + ImagePullPolicy: corev1.PullIfNotPresent, + Name: "http", + Command: []string{"/bin/test"}, + }, + }, + }, + }, + }, + } +} + // NewE2EService creates a service for the E2E helper deployment func NewE2EService(name, namespace string) *corev1.Service { return &corev1.Service{ @@ -299,6 +338,11 @@ func NewE2EService(name, namespace string) *corev1.Service { Port: 8080, TargetPort: intstr.IntOrString{IntVal: 8080}, }, + { + Name: "https", + Port: 8081, + TargetPort: intstr.IntOrString{IntVal: 8081}, + }, // Only used in network chaos { Name: "nc-port", diff --git a/e2e-test/types.go b/e2e-test/types.go new file mode 100644 index 0000000000..faef2a453d --- /dev/null +++ b/e2e-test/types.go @@ -0,0 +1,145 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package test + +import ( + "fmt" + "os/exec" + "path/filepath" + "strings" + + apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" + "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" + aggregatorclientset "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset" + "k8s.io/kubernetes/test/e2e/framework" +) + +const ( + imagePullPolicyIfNotPresent = "IfNotPresent" +) + +// OperatorConfig describe the configuration during installing chaos-mesh +type OperatorConfig struct { + Namespace string + ReleaseName string + Manager ManagerConfig + Daemon DaemonConfig + Tag string + DNSImage string + EnableDashboard bool +} + +// ManagerConfig describe the chaos-operator configuration during installing chaos-mesh +type ManagerConfig struct { + ImageRegistry string + ImageRepository string + ImageTag string + ImagePullPolicy string +} + +// DaemonConfig describe the chaos-daemon configuration during installing chaos-mesh +type DaemonConfig struct { + ImageRegistry string + ImageRepository string + ImageTag string + Runtime string + SocketPath string + ImagePullPolicy string +} + +// NewDefaultOperatorConfig create the default configuration for chaos-mesh test +func NewDefaultOperatorConfig() OperatorConfig { + return OperatorConfig{ + Namespace: "chaos-mesh", + ReleaseName: "chaos-mesh", + Tag: "e2e", + Manager: ManagerConfig{ + ImageRegistry: "ghcr.io", + ImageRepository: "chaos-mesh/chaos-mesh", + ImageTag: "latest", + ImagePullPolicy: imagePullPolicyIfNotPresent, + }, + Daemon: DaemonConfig{ + ImageRegistry: "ghcr.io", + ImageRepository: "chaos-mesh/chaos-daemon", + ImageTag: "latest", + ImagePullPolicy: imagePullPolicyIfNotPresent, + Runtime: "containerd", + SocketPath: "/run/containerd/containerd.sock", + }, + DNSImage: "ghcr.io/chaos-mesh/chaos-coredns:v0.2.6", + } +} + +type operatorAction struct { + framework *framework.Framework + kubeCli kubernetes.Interface + aggrCli aggregatorclientset.Interface + apiExtCli apiextensionsclientset.Interface + cfg *Config +} + +func (oi *OperatorConfig) operatorHelmSetValue() string { + set := map[string]string{ + "controllerManager.image.registry": oi.Manager.ImageRegistry, + "controllerManager.image.repository": oi.Manager.ImageRepository, + "controllerManager.image.tag": oi.Manager.ImageTag, + "controllerManager.imagePullPolicy": oi.Manager.ImagePullPolicy, + "chaosDaemon.image.registry": oi.Daemon.ImageRegistry, + "chaosDaemon.image.repository": oi.Daemon.ImageRepository, + "chaosDaemon.image.tag": oi.Daemon.ImageTag, + "chaosDaemon.runtime": oi.Daemon.Runtime, + "chaosDaemon.socketPath": oi.Daemon.SocketPath, + "chaosDaemon.imagePullPolicy": oi.Daemon.ImagePullPolicy, + "dnsServer.create": "true", + "dnsServer.image": oi.DNSImage, + "dashboard.create": fmt.Sprintf("%t", oi.EnableDashboard), + } + arr := make([]string, 0, len(set)) + for k, v := range set { + arr = append(arr, fmt.Sprintf("%s=%s", k, v)) + } + return fmt.Sprintf("\"%s\"", strings.Join(arr, ",")) +} + +func (oa *operatorAction) operatorChartPath(tag string) string { + return oa.chartPath(operatorChartName, tag) +} + +func (oa *operatorAction) chartPath(name string, tag string) string { + return filepath.Join(oa.cfg.ChartDir, tag, name) +} + +func (oa *operatorAction) manifestPath(tag string) string { + return filepath.Join(oa.cfg.ManifestDir, tag) +} + +func (oa *operatorAction) runKubectlOrDie(args ...string) string { + cmd := "kubectl" + klog.Infof("Running '%s %s'", cmd, strings.Join(args, " ")) + out, err := exec.Command(cmd, args...).CombinedOutput() + if err != nil { + klog.Fatalf("Failed to run '%s %s'\nCombined output: %q\nError: %v", cmd, strings.Join(args, " "), string(out), err) + } + klog.Infof("Combined output: %q", string(out)) + return string(out) +} + +func (oa *operatorAction) apiVersions() []string { + stdout := oa.runKubectlOrDie("api-versions") + return strings.Split(stdout, "\n") +} diff --git a/env-images.yaml b/env-images.yaml new file mode 100644 index 0000000000..f97c95bf5c --- /dev/null +++ b/env-images.yaml @@ -0,0 +1,23 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Note: This file should be updated with the new release- branch created. + +# specify which tag of ghcr.io/chaos-mesh/build-env image should be used with the current branch +build-env: + tag: "latest" +# specify which tag of ghcr.io/chaos-mesh/dev-env image should be used with the current branch +dev-env: + tag: "latest" diff --git a/examples/blockchaos/blockchaos-delay-example.yaml b/examples/blockchaos/blockchaos-delay-example.yaml new file mode 100644 index 0000000000..425890ccd8 --- /dev/null +++ b/examples/blockchaos/blockchaos-delay-example.yaml @@ -0,0 +1,27 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: BlockChaos +metadata: + name: hostpath-example-delay +spec: + selector: + labelSelectors: + app: hostpath-example + mode: all + volumeName: hostpath-example + action: delay + delay: + latency: 1s \ No newline at end of file diff --git a/examples/blockchaos/hostpath-persistent-volume.yaml b/examples/blockchaos/hostpath-persistent-volume.yaml new file mode 100644 index 0000000000..e4f0b3b8e6 --- /dev/null +++ b/examples/blockchaos/hostpath-persistent-volume.yaml @@ -0,0 +1,26 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: v1 +kind: PersistentVolume +metadata: + name: hostpath-example +spec: + storageClassName: manual + capacity: + storage: 10Gi + accessModes: + - ReadWriteOnce + hostPath: + path: "/mnt" diff --git a/examples/blockchaos/pod.yaml b/examples/blockchaos/pod.yaml new file mode 100644 index 0000000000..94bf2819ed --- /dev/null +++ b/examples/blockchaos/pod.yaml @@ -0,0 +1,48 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: v1 +kind: Pod +metadata: + name: hostpath-example + labels: + app: hostpath-example +spec: + volumes: + - name: hostpath-example + persistentVolumeClaim: + claimName: hostpath-example + containers: + - name: task-pv-container + image: nginx + ports: + - containerPort: 80 + name: "http-server" + securityContext: + privileged: true + volumeMounts: + - mountPath: "/usr/share/nginx/html" + name: hostpath-example +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: hostpath-example +spec: + storageClassName: manual + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 3Gi diff --git a/examples/burn-cpu.yaml b/examples/burn-cpu.yaml index 9d2731e56a..7783ae6f16 100644 --- a/examples/burn-cpu.yaml +++ b/examples/burn-cpu.yaml @@ -1,19 +1,29 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: StressChaos metadata: name: burn-cpu - namespace: chaos-testing spec: mode: one selector: labelSelectors: "app.kubernetes.io/component": "tikv" - stressors: - cpu: + stressors: + cpu: workers: 1 load: 100 options: ["--cpu 2", "--timeout 600", "--hdd 1"] duration: "30s" - scheduler: - cron: "@every 2m" - diff --git a/examples/cause-pod-oom.yaml b/examples/cause-pod-oom.yaml new file mode 100644 index 0000000000..ef166006ab --- /dev/null +++ b/examples/cause-pod-oom.yaml @@ -0,0 +1,29 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: StressChaos +metadata: + name: pod-oom +spec: + mode: one + selector: + labelSelectors: + "app.kubernetes.io/component": "tikv" + stressors: + memory: + workers: 1 + size: 10GB + oomScoreAdj: -1000 + duration: "30s" diff --git a/examples/container-kill-example.yaml b/examples/container-kill-example.yaml index f3abb22cf6..cdbd83b5ed 100644 --- a/examples/container-kill-example.yaml +++ b/examples/container-kill-example.yaml @@ -1,14 +1,26 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: PodChaos metadata: name: container-kill-example - namespace: chaos-testing spec: action: container-kill mode: one - containerName: "prometheus" selector: labelSelectors: - "app.kubernetes.io/component": "monitor" - scheduler: - cron: "@every 30s" + app.kubernetes.io/component: monitor + containerNames: + - prometheus diff --git a/examples/dashboard/ingress-subpath.yaml b/examples/dashboard/ingress-subpath.yaml new file mode 100644 index 0000000000..a867efda83 --- /dev/null +++ b/examples/dashboard/ingress-subpath.yaml @@ -0,0 +1,35 @@ +# Copyright 2023 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-chaos-dashboard-under-subpath + namespace: chaos-mesh + annotations: + nginx.ingress.kubernetes.io/use-regex: 'true' + nginx.ingress.kubernetes.io/rewrite-target: /$1 + nginx.ingress.kubernetes.io/configuration-snippet: | + sub_filter '' ' '; +spec: + rules: + - http: + paths: + - path: /chaos-mesh/?(.*) + pathType: Prefix + backend: + service: + name: chaos-dashboard + port: + number: 2333 diff --git a/examples/dns-chaos-example.yaml b/examples/dns-chaos-example.yaml index 6854275707..151c25acb4 100644 --- a/examples/dns-chaos-example.yaml +++ b/examples/dns-chaos-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: DNSChaos metadata: name: dns-chaos-example - namespace: chaos-testing spec: action: random mode: all @@ -14,5 +27,3 @@ spec: namespaces: - busybox duration: "50s" - scheduler: - cron: "@every 100s" diff --git a/examples/etcd/etcd-iochaos.yaml b/examples/etcd/etcd-iochaos.yaml index 8ffa0254e9..58a9d7b095 100644 --- a/examples/etcd/etcd-iochaos.yaml +++ b/examples/etcd/etcd-iochaos.yaml @@ -1,18 +1,34 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 -kind: IoChaos +kind: Schedule metadata: name: io-delay-example spec: - action: latency - mode: one - path: "/var/run/etcd/**/*" - selector: - labelSelectors: - app: etcd - volumePath: /var/run/etcd - delay: "100ms" - percent: 50 - duration: "400s" - scheduler: - cron: "@every 10m" - + schedule: '@every 10m' + type: IOChaos + historyLimit: 5 + concurrencyPolicy: Forbid + ioChaos: + action: latency + mode: one + path: /var/run/etcd/**/* + selector: + labelSelectors: + app: etcd + volumePath: /var/run/etcd + delay: 100ms + percent: 50 + duration: 400s diff --git a/examples/etcd/etcd.yaml b/examples/etcd/etcd.yaml index 1ec703c46a..b8df67c01b 100644 --- a/examples/etcd/etcd.yaml +++ b/examples/etcd/etcd.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# --- kind: Deployment apiVersion: apps/v1 @@ -18,7 +32,7 @@ spec: containers: - name: etcd imagePullPolicy: IfNotPresent - image: k8s.gcr.io/etcd:3.4.3-0 + image: registry.k8s.io/etcd:3.4.3-0 args: - /usr/local/bin/etcd - -name=etcd diff --git a/examples/io-attr-example.yaml b/examples/io-attr-example.yaml index 2414721c4d..3b5e213749 100644 --- a/examples/io-attr-example.yaml +++ b/examples/io-attr-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 -kind: IoChaos +kind: IOChaos metadata: name: io-attr-example - namespace: chaos-testing spec: action: attrOverride mode: one @@ -15,5 +28,3 @@ spec: perm: 72 percent: 10 duration: "400s" - scheduler: - cron: "@every 10m" diff --git a/examples/io-delay-example.yaml b/examples/io-delay-example.yaml index 2ae5ff5282..29879e9730 100644 --- a/examples/io-delay-example.yaml +++ b/examples/io-delay-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 -kind: IoChaos +kind: IOChaos metadata: name: io-delay-example - namespace: chaos-testing spec: action: latency mode: one @@ -14,5 +27,3 @@ spec: delay: "10ms" percent: 10 duration: "400s" - scheduler: - cron: "@every 10m" diff --git a/examples/io-errno-example.yaml b/examples/io-errno-example.yaml index 547254b947..031693a894 100644 --- a/examples/io-errno-example.yaml +++ b/examples/io-errno-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 -kind: IoChaos +kind: IOChaos metadata: name: io-errno-example - namespace: chaos-testing spec: action: fault mode: one @@ -14,5 +27,3 @@ spec: errno: 5 percent: 50 duration: "400s" - scheduler: - cron: "@every 10m" diff --git a/examples/jvm/app.yaml b/examples/jvm/app.yaml index cc35c2cf0e..b1bb4b6375 100644 --- a/examples/jvm/app.yaml +++ b/examples/jvm/app.yaml @@ -1,22 +1,28 @@ -apiVersion: apps/v1 -kind: Deployment +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: v1 +kind: Pod metadata: - name: springboot-jvmchaos-demo - namespace: app + name: helloworld spec: - replicas: 1 - selector: - matchLabels: - app: springboot-jvmchaos-demo - template: - metadata: - annotations: - admission-webhook.chaos-mesh.org/request: jvmchaos-sidecar - creationTimestamp: null - labels: - app: springboot-jvmchaos-demo - spec: - containers: - - image: 'gallardot/chaosmesh-jvmchaos-sample:latest' - imagePullPolicy: IfNotPresent - name: springboot-jvmchaos-demo + containers: + - name: helloworld + # source code: https://github.com/WangXiangUSTC/byteman-example/tree/main/example.helloworld + # this application will print log like this below: + # 0. Hello World + # 1. Hello World + # ... + image: xiang13225080/helloworld:v1.0 + imagePullPolicy: IfNotPresent \ No newline at end of file diff --git a/examples/jvm/jvm-cfl-example.yaml b/examples/jvm/jvm-cfl-example.yaml deleted file mode 100644 index 8dec40d41f..0000000000 --- a/examples/jvm/jvm-cfl-example.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: chaos-mesh.org/v1alpha1 -kind: JVMChaos -metadata: - name: jvm-cfl-example - namespace: app -spec: - action: cfl - target: jvm - mode: one - selector: - labelSelectors: - app: springboot-jvmchaos-demo - duration: "30s" - scheduler: - cron: "@every 1m" diff --git a/examples/jvm/jvm-delay4jvm-example.yaml b/examples/jvm/jvm-delay4jvm-example.yaml deleted file mode 100644 index 29576c948f..0000000000 --- a/examples/jvm/jvm-delay4jvm-example.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: chaos-mesh.org/v1alpha1 -kind: JVMChaos -metadata: - name: jvm-delay4jvm-example - namespace: app -spec: - action: delay - target: jvm - flags: - time: "10000" - matchers: - classname: "org.chaosmesh.jvm.Application" - methodname: "hello" - mode: one - selector: - labelSelectors: - app: springboot-jvmchaos-demo - duration: "50s" - scheduler: - cron: "@every 1m" diff --git a/examples/jvm/jvm-delay4servlet-example.yaml b/examples/jvm/jvm-delay4servlet-example.yaml deleted file mode 100644 index bb861e149b..0000000000 --- a/examples/jvm/jvm-delay4servlet-example.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: chaos-mesh.org/v1alpha1 -kind: JVMChaos -metadata: - name: jvm-delay4servlet-example - namespace: app -spec: - action: delay - target: servlet - flags: - time: "10000" - mode: one - selector: - labelSelectors: - app: springboot-jvmchaos-demo - duration: "50s" - scheduler: - cron: "@every 1m" diff --git a/examples/jvm/jvm-exception-example.yaml b/examples/jvm/jvm-exception-example.yaml index 04999f9644..66536ee18c 100644 --- a/examples/jvm/jvm-exception-example.yaml +++ b/examples/jvm/jvm-exception-example.yaml @@ -1,20 +1,27 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: JVMChaos metadata: - name: jvm-exception-example - namespace: app + name: exception spec: - action: tce - target: jvm - flags: - exception: "java.lang.Exception" - matchers: - classname: "org.chaosmesh.jvm.Application" - methodname: "hello" - mode: one + action: exception + class: Main + method: sayhello + exception: java.io.IOException("BOOM") + mode: all selector: - labelSelectors: - app: springboot-jvmchaos-demo - duration: "30s" - scheduler: - cron: "@every 1m" + namespaces: + - helloworld \ No newline at end of file diff --git a/examples/jvm/jvm-oom-example.yaml b/examples/jvm/jvm-oom-example.yaml deleted file mode 100644 index 6fa99c7a5f..0000000000 --- a/examples/jvm/jvm-oom-example.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: chaos-mesh.org/v1alpha1 -kind: JVMChaos -metadata: - name: jvm-oom-example - namespace: app -spec: - action: oom - target: jvm - flags: - area: "HEAP" - wild-mode: "true" - mode: one - selector: - labelSelectors: - app: springboot-jvmchaos-demo - duration: "30s" - scheduler: - cron: "@every 1m" diff --git a/examples/jvm/jvm-return-example.yaml b/examples/jvm/jvm-return-example.yaml index 6a75faa760..7c80f741b1 100644 --- a/examples/jvm/jvm-return-example.yaml +++ b/examples/jvm/jvm-return-example.yaml @@ -1,20 +1,27 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: JVMChaos metadata: - name: jvm-return-example - namespace: app + name: return spec: action: return - target: jvm - flags: - value: "hello chaos mesh!" - matchers: - classname: "org.chaosmesh.jvm.Application" - methodname: "hello" - mode: one + class: Main + method: getnum + value: "9999" + mode: all selector: - labelSelectors: - app: springboot-jvmchaos-demo - duration: "50s" - scheduler: - cron: "@every 1m" + namespaces: + - helloworld \ No newline at end of file diff --git a/examples/jvm/jvm-rule-data-example.yaml b/examples/jvm/jvm-rule-data-example.yaml new file mode 100644 index 0000000000..47bed674c3 --- /dev/null +++ b/examples/jvm/jvm-rule-data-example.yaml @@ -0,0 +1,25 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: JVMChaos +metadata: + name: modify-return +spec: + action: ruleData + ruleData: "RULE modify return value\nCLASS Main\nMETHOD getnum\nAT ENTRY\nIF true\nDO\n return 9999\nENDRULE" + mode: all + selector: + namespaces: + - helloworld \ No newline at end of file diff --git a/examples/jvm/sidecar-template.yaml b/examples/jvm/sidecar-template.yaml deleted file mode 100644 index 6d675500f7..0000000000 --- a/examples/jvm/sidecar-template.yaml +++ /dev/null @@ -1,32 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: jvmchaos-sidecar-template - namespace: chaos-testing - labels: - app.kubernetes.io/component: template -data: - data: | - initContainers: - - name: jvmchaos-initcontainer - image: 'gallardot/chaos-jvm:latest' - command: - - cp - - '-r' - - /bin/sandbox/ - - /opt/jvm-chaos - resources: {} - volumeMounts: - - name: jvm-chaos-vol - mountPath: /opt/jvm-chaos - imagePullPolicy: Always - env: - - name: JAVA_TOOL_OPTIONS - value: >- - -javaagent:/opt/jvm-chaos/sandbox/lib/sandbox-agent.jar="server.ip=0.0.0.0;server.port=10086;" - volumeMounts: - - name: jvm-chaos-vol - mountPath: /opt/jvm-chaos - volumes: - - name: jvm-chaos-vol - emptyDir: {} diff --git a/examples/jvm/sidecar.yaml b/examples/jvm/sidecar.yaml deleted file mode 100644 index de685ca7c1..0000000000 --- a/examples/jvm/sidecar.yaml +++ /dev/null @@ -1,14 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: jvmchaos-sidecar - namespace: app - labels: - app.kubernetes.io/component: webhook -data: - jvmchaos-sidecar: | - name: jvmchaos-sidecar - selector: - labelSelectors: - "app": "springboot-jvmchaos-demo" - template: jvmchaos-sidecar-template diff --git a/examples/network-bandwidth-example.yaml b/examples/network-bandwidth-example.yaml index 54c5c7015d..bf3e47fc41 100644 --- a/examples/network-bandwidth-example.yaml +++ b/examples/network-bandwidth-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: NetworkChaos metadata: name: network-bandwidth-example - namespace: chaos-testing spec: action: bandwidth mode: one @@ -16,5 +29,3 @@ spec: peakrate: 1000000 minburst: 1000000 duration: "10s" - scheduler: - cron: "@every 15s" diff --git a/examples/network-corrupt-example.yaml b/examples/network-corrupt-example.yaml index 5ab1dd474d..267d1f0e16 100644 --- a/examples/network-corrupt-example.yaml +++ b/examples/network-corrupt-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: NetworkChaos metadata: name: network-corrupt-example - namespace: chaos-testing spec: action: corrupt mode: one @@ -13,5 +26,3 @@ spec: corrupt: "40" correlation: "25" duration: "10s" - scheduler: - cron: "@every 15s" \ No newline at end of file diff --git a/examples/network-delay-example.yaml b/examples/network-delay-example.yaml index 39270561ef..4f40de807d 100644 --- a/examples/network-delay-example.yaml +++ b/examples/network-delay-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: NetworkChaos metadata: name: network-delay-example - namespace: chaos-testing spec: action: delay mode: one @@ -14,5 +27,3 @@ spec: correlation: "25" jitter: "90ms" duration: "10s" - scheduler: - cron: "@every 15s" diff --git a/examples/network-delay-with-external-target-example.yaml b/examples/network-delay-with-external-target-example.yaml index f0e4a8de46..091f45acc7 100644 --- a/examples/network-delay-with-external-target-example.yaml +++ b/examples/network-delay-with-external-target-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: NetworkChaos metadata: name: network-delay-example - namespace: chaos-testing spec: action: delay mode: one @@ -18,6 +31,7 @@ spec: - "8.8.8.8" - "www.google.com" - "8.8.0.0/16" + - "1.1.1.1:80" + - "example.com:443" + - "10.0.0.0/8:22" duration: "10s" - scheduler: - cron: "@every 15s" diff --git a/examples/network-delay-with-target-example.yaml b/examples/network-delay-with-target-example.yaml index 65bf9fec4b..c1f91419b0 100644 --- a/examples/network-delay-with-target-example.yaml +++ b/examples/network-delay-with-target-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: NetworkChaos metadata: name: network-delay-example - namespace: chaos-testing spec: action: delay mode: one @@ -25,5 +38,3 @@ spec: "app.kubernetes.io/component": "pool" mode: one duration: "10s" - scheduler: - cron: "@every 15s" diff --git a/examples/network-duplicate-example.yaml b/examples/network-duplicate-example.yaml index f09e1024f4..94fc5c130b 100644 --- a/examples/network-duplicate-example.yaml +++ b/examples/network-duplicate-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: NetworkChaos metadata: name: network-duplicate-example - namespace: chaos-testing spec: action: duplicate mode: one @@ -13,5 +26,3 @@ spec: duplicate: "40" correlation: "25" duration: "10s" - scheduler: - cron: "@every 15s" \ No newline at end of file diff --git a/examples/network-loss-example.yaml b/examples/network-loss-example.yaml index 9bf9748ba2..66791e42c9 100644 --- a/examples/network-loss-example.yaml +++ b/examples/network-loss-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: NetworkChaos metadata: name: network-loss-example - namespace: chaos-testing spec: action: loss mode: one @@ -13,5 +26,3 @@ spec: loss: "25" correlation: "25" duration: "10s" - scheduler: - cron: "@every 15s" \ No newline at end of file diff --git a/examples/network-netem-example.yaml b/examples/network-netem-example.yaml index a833ac0c32..f4772a5ac1 100644 --- a/examples/network-netem-example.yaml +++ b/examples/network-netem-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: NetworkChaos metadata: name: network-netem-example - namespace: chaos-testing spec: action: netem mode: one @@ -17,5 +30,3 @@ spec: loss: "25" correlation: "25" duration: "10s" - scheduler: - cron: "@every 15s" \ No newline at end of file diff --git a/examples/network-netem-with-target-example.yaml b/examples/network-netem-with-target-example.yaml index 68c563aa58..113702f4e0 100644 --- a/examples/network-netem-with-target-example.yaml +++ b/examples/network-netem-with-target-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: NetworkChaos metadata: name: network-netem-example - namespace: chaos-testing spec: action: netem mode: one @@ -23,5 +36,3 @@ spec: "app.kubernetes.io/component": "tikv" mode: one duration: "10s" - scheduler: - cron: "@every 15s" diff --git a/examples/network-partition-example.yaml b/examples/network-partition-example.yaml index 3678e74836..adbea7634d 100644 --- a/examples/network-partition-example.yaml +++ b/examples/network-partition-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: NetworkChaos metadata: name: network-partition-example - namespace: chaos-testing spec: action: partition mode: one @@ -16,5 +29,3 @@ spec: "app.kubernetes.io/component": "tikv" mode: one duration: "10s" - scheduler: - cron: "@every 15s" \ No newline at end of file diff --git a/examples/network-partition-with-external-targets-example.yaml b/examples/network-partition-with-external-targets-example.yaml index e105e01942..31ead30181 100644 --- a/examples/network-partition-with-external-targets-example.yaml +++ b/examples/network-partition-with-external-targets-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: NetworkChaos metadata: name: network-partition-example - namespace: chaos-testing spec: action: partition mode: one @@ -14,6 +27,7 @@ spec: - "8.8.8.8" - "www.google.com" - "8.8.0.0/16" + - "1.1.1.1:80" + - "example.com:443" + - "10.0.0.0/8:22" duration: "10s" - scheduler: - cron: "@every 15s" \ No newline at end of file diff --git a/examples/nginx/http-patch-response.yaml b/examples/nginx/http-patch-response.yaml new file mode 100644 index 0000000000..0703292a71 --- /dev/null +++ b/examples/nginx/http-patch-response.yaml @@ -0,0 +1,33 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +kind: HTTPChaos +apiVersion: chaos-mesh.org/v1alpha1 +metadata: + name: nginx-http-patch +spec: + selector: + namespaces: + - default + labelSelectors: + app: nginx + mode: all + target: Response + patch: + body: + type: JSON + value: '{"status":"Failed","reason":"hacked by Chaos Mesh"}' + port: 80 + path: '*' \ No newline at end of file diff --git a/examples/nginx/nginx.yaml b/examples/nginx/nginx.yaml new file mode 100644 index 0000000000..7ece98f8ce --- /dev/null +++ b/examples/nginx/nginx.yaml @@ -0,0 +1,70 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: example-data +data: + index.json: | + {"app": "Chaos App", "status": "Running"} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx +spec: + replicas: 1 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + volumes: + - name: example-data + configMap: + name: example-data + containers: + - image: nginx:latest + name: nginx + resources: {} + volumeMounts: + - mountPath: /usr/share/nginx/html/index.html + name: example-data + subPath: index.json + ports: + - name: nginx + containerPort: 80 + +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx + labels: + app: nginx +spec: + selector: + app: nginx + ports: + - protocol: TCP + port: 80 + targetPort: 80 diff --git a/examples/physicalmachinechaos/network-delay-physicalmachinechaos-example.yaml b/examples/physicalmachinechaos/network-delay-physicalmachinechaos-example.yaml new file mode 100644 index 0000000000..32c9de952d --- /dev/null +++ b/examples/physicalmachinechaos/network-delay-physicalmachinechaos-example.yaml @@ -0,0 +1,32 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: PhysicalMachineChaos +metadata: + name: physical-network-delay + namespace: chaos-mesh +spec: + action: network-delay + mode: one + selector: + # set the PhysicalMachine object name directly + physicalMachines: + default: # Namespace of PhysicalMachine object + - physical-machine-example # Name of PhysicalMachine object + network-delay: + device: ens33 + ip-address: 140.82.112.3 + latency: 1000ms + duration: '10m' diff --git a/examples/physicalmachinechaos/network-delay-physicalmachinechaos-labelselectors-example.yaml b/examples/physicalmachinechaos/network-delay-physicalmachinechaos-labelselectors-example.yaml new file mode 100644 index 0000000000..2af8ceb267 --- /dev/null +++ b/examples/physicalmachinechaos/network-delay-physicalmachinechaos-labelselectors-example.yaml @@ -0,0 +1,34 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: PhysicalMachineChaos +metadata: + name: physical-network-delay + namespace: chaos-mesh +spec: + action: network-delay + mode: one + selector: + # use label selectors to select PhysicalMachine objects. + namespaces: + - default + labelSelectors: + arch: 'amd64' + region: 'region-a' + network-delay: + device: ens33 + ip-address: 140.82.112.3 + latency: 1000ms + duration: '10m' diff --git a/examples/physicalmachinechaos/physicalmachine-example.yaml b/examples/physicalmachinechaos/physicalmachine-example.yaml new file mode 100644 index 0000000000..309130e188 --- /dev/null +++ b/examples/physicalmachinechaos/physicalmachine-example.yaml @@ -0,0 +1,24 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: PhysicalMachine +metadata: + name: physical-machine-example + labels: + region: region-a + arch: amd64 +spec: + # set the address of chaosd server + address: http://123.123.123.123:31767 diff --git a/examples/pod-failure-example.yaml b/examples/pod-failure-example.yaml index 2470ab88db..6311745fdf 100644 --- a/examples/pod-failure-example.yaml +++ b/examples/pod-failure-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: PodChaos metadata: name: pod-failure-example - namespace: chaos-testing spec: action: pod-failure mode: one @@ -10,5 +23,3 @@ spec: selector: labelSelectors: "app.kubernetes.io/component": "tikv" - scheduler: - cron: "@every 2m" diff --git a/examples/pod-kill-example.yaml b/examples/pod-kill-example.yaml index 2549f9e282..d9186df4c0 100644 --- a/examples/pod-kill-example.yaml +++ b/examples/pod-kill-example.yaml @@ -1,13 +1,24 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: PodChaos metadata: name: pod-kill-example - namespace: chaos-testing spec: action: pod-kill mode: one selector: labelSelectors: "app.kubernetes.io/component": "tikv" - scheduler: - cron: "@every 1m" diff --git a/examples/remote-cluster.yaml b/examples/remote-cluster.yaml new file mode 100644 index 0000000000..d1a8bde0bd --- /dev/null +++ b/examples/remote-cluster.yaml @@ -0,0 +1,25 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: RemoteCluster +metadata: + name: cluster-xxxxxxx +spec: + namespace: "chaos-mesh" + kubeConfig: + secretRef: + name: chaos-mesh-02.kubeconfig + namespace: default + key: kubeconfig \ No newline at end of file diff --git a/examples/remote-cluster/deployment.yaml b/examples/remote-cluster/deployment.yaml new file mode 100644 index 0000000000..d51f654cad --- /dev/null +++ b/examples/remote-cluster/deployment.yaml @@ -0,0 +1,37 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: apps/v1 +kind: Deployment +metadata: + name: web-show + labels: + app: web-show +spec: + replicas: 3 + selector: + matchLabels: + app: web-show + template: + metadata: + labels: + app: web-show + spec: + containers: + - name: web-show + image: ghcr.io/chaos-mesh/web-show + imagePullPolicy: Always + command: + - /usr/local/bin/web-show + - --target-ip=127.0.0.1 diff --git a/examples/remote-cluster/remote-cluster.yaml b/examples/remote-cluster/remote-cluster.yaml new file mode 100644 index 0000000000..a54a9596b1 --- /dev/null +++ b/examples/remote-cluster/remote-cluster.yaml @@ -0,0 +1,26 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: RemoteCluster +metadata: + name: cluster-xxxxxxx +spec: + namespace: "chaos-mesh" + kubeConfig: + secretRef: + name: chaos-mesh-02.kubeconfig + namespace: default + key: kubeconfig + \ No newline at end of file diff --git a/examples/remote-cluster/remote-podchaos.yaml b/examples/remote-cluster/remote-podchaos.yaml new file mode 100644 index 0000000000..a5d6520845 --- /dev/null +++ b/examples/remote-cluster/remote-podchaos.yaml @@ -0,0 +1,26 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: PodChaos +metadata: + name: pod-failure-example +spec: + action: pod-failure + mode: one + duration: "30s" + selector: + labelSelectors: + "app": "web-show" + remoteCluster: cluster-xxxxxxx diff --git a/examples/schedule-podchaos.yaml b/examples/schedule-podchaos.yaml new file mode 100644 index 0000000000..6ef4c052a2 --- /dev/null +++ b/examples/schedule-podchaos.yaml @@ -0,0 +1,29 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: Schedule +metadata: + name: schedule-pod-kill-example +spec: + schedule: "@every 5s" + type: "PodChaos" + historyLimit: 5 + concurrencyPolicy: Forbid + podChaos: + action: "pod-kill" + mode: one + selector: + labelSelectors: + "app.kubernetes.io/component": "tikv" diff --git a/examples/statuscheck-example.yaml b/examples/statuscheck-example.yaml new file mode 100644 index 0000000000..d692d2f61a --- /dev/null +++ b/examples/statuscheck-example.yaml @@ -0,0 +1,25 @@ +# Copyright Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: StatusCheck +metadata: + name: status-check-example +spec: + type: HTTP + http: + url: http://123.123.123.123 + method: GET + criteria: + statusCode: "200" diff --git a/examples/time-chaos-example.yaml b/examples/time-chaos-example.yaml index 78e5d2f2b1..d324f6cbd9 100644 --- a/examples/time-chaos-example.yaml +++ b/examples/time-chaos-example.yaml @@ -1,8 +1,21 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: TimeChaos metadata: name: time-shift-example - namespace: chaos-testing spec: mode: one selector: @@ -10,5 +23,3 @@ spec: "app.kubernetes.io/component": "tikv" timeOffset: "-10m100ns" duration: "30s" - scheduler: - cron: "@every 1m" diff --git a/examples/web-show/deploy.sh b/examples/web-show/deploy.sh index 8ebadd27bb..8b1232b7c0 100755 --- a/examples/web-show/deploy.sh +++ b/examples/web-show/deploy.sh @@ -1,17 +1,20 @@ #!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. +# Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# + + set -e @@ -63,12 +66,6 @@ fi TARGET_IP=$(kubectl get pod -n kube-system -o wide| grep kube-controller | head -n 1 | awk '{print $6}') -if [ ${DOCKER_MIRROR} == "true" ]; then - docker pull dockerhub.azk8s.cn/pingcap/web-show || true - docker tag dockerhub.azk8s.cn/pingcap/web-show pingcap/web-show || true - kind load docker-image pingcap/web-show > /dev/null 2>&1 || true -fi - cat < ./api/v1alpha1 - google.golang.org/grpc => google.golang.org/grpc v1.26.0 - k8s.io/api => k8s.io/api v0.17.0 - k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.17.0 - k8s.io/apimachinery => k8s.io/apimachinery v0.17.1-beta.0 - k8s.io/apiserver => k8s.io/apiserver v0.17.0 - k8s.io/cli-runtime => k8s.io/cli-runtime v0.17.0 - k8s.io/client-go => k8s.io/client-go v0.17.0 - k8s.io/cloud-provider => k8s.io/cloud-provider v0.17.0 - k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.17.0 - k8s.io/code-generator => k8s.io/code-generator v0.17.1-beta.0 - k8s.io/component-base => k8s.io/component-base v0.17.0 - k8s.io/cri-api => k8s.io/cri-api v0.17.1-beta.0 - k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.17.0 - k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.17.0 - k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.17.0 - k8s.io/kube-proxy => k8s.io/kube-proxy v0.17.0 - k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.17.0 - k8s.io/kubectl => k8s.io/kubectl v0.17.0 - k8s.io/kubelet => k8s.io/kubelet v0.17.0 - k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.17.0 - k8s.io/metrics => k8s.io/metrics v0.17.0 - k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.17.0 - vbom.ml/util => github.com/fvbommel/util v0.0.2 +require ( + cloud.google.com/go/compute v1.21.0 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect + github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.23 // indirect + github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/BurntSushi/toml v1.3.2 // indirect + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/MakeNowJust/heredoc v1.0.0 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/Masterminds/sprig/v3 v3.2.3 // indirect + github.com/Masterminds/squirrel v1.5.4 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/hcsshim v0.11.4 // indirect + github.com/agnivade/levenshtein v1.1.1 // indirect + github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect + github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.6 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.1.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 // indirect + github.com/aws/smithy-go v1.3.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bytedance/sonic v1.9.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chai2010/gettext-go v1.0.2 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/containerd/continuity v0.4.2 // indirect + github.com/containerd/fifo v1.1.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/ttrpc v1.2.2 // indirect + github.com/containerd/typeurl/v2 v2.1.1 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/deckarep/golang-set/v2 v2.1.0 // indirect + github.com/denisenkom/go-mssqldb v0.9.0 // indirect + github.com/dimchansky/utfbom v1.1.1 // indirect + github.com/docker/cli v24.0.6+incompatible // indirect + github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/docker/docker-credential-helpers v0.7.0 // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect + github.com/docker/go-metrics v0.0.1 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/emicklei/go-restful/v3 v3.10.1 // indirect + github.com/evanphx/json-patch v5.6.0+incompatible // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect + github.com/fatih/camelcase v1.0.0 // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-errors/errors v1.4.2 // indirect + github.com/go-gorp/gorp/v3 v3.1.0 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/spec v0.20.6 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-sql-driver/mysql v1.6.0 // indirect + github.com/go-stack/stack v1.8.1 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-test/deep v1.0.8 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/google/btree v1.0.1 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect + github.com/google/s2a-go v0.1.4 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect + github.com/googleapis/gax-go/v2 v2.11.0 // indirect + github.com/gorilla/mux v1.8.0 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/gosuri/uitable v0.0.4 // indirect + github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/holiman/uint256 v1.2.3 // indirect + github.com/huandu/xstrings v1.4.0 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/jmoiron/sqlx v1.3.5 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/karrick/godirwalk v1.17.0 // indirect + github.com/klauspost/compress v1.16.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/kr/fs v0.1.0 // indirect + github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect + github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/mattn/go-sqlite3 v2.0.1+incompatible // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/mitchellh/mapstructure v1.4.3 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/moby/sys/sequential v0.5.0 // indirect + github.com/moby/sys/signal v0.7.0 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/onsi/ginkgo v1.16.5 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0-rc5 // indirect + github.com/opencontainers/runc v1.1.12 // indirect + github.com/opencontainers/runtime-spec v1.1.0-rc.1 // indirect + github.com/opencontainers/selinux v1.11.0 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pingcap/check v0.0.0-20191216031241-8a5a85928f12 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect + github.com/romana/rlog v0.0.0-20171115192701-f018bc92e7d7 // indirect + github.com/rubenv/sql-migrate v1.5.2 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shopspring/decimal v1.3.1 // indirect + github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spf13/cast v1.5.0 // indirect + github.com/stretchr/objx v0.5.0 // indirect + github.com/tklauser/go-sysconf v0.3.9 // indirect + github.com/tklauser/numcpus v0.3.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + github.com/vishvananda/netns v0.0.4 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect + github.com/xlab/treeprint v1.2.0 // indirect + github.com/yusufpapurcu/wmi v1.2.2 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect + go.opentelemetry.io/otel v1.19.0 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect + go.uber.org/dig v1.16.1 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.12.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiextensions-apiserver v0.28.4 // indirect + k8s.io/component-base v0.28.4 // indirect + k8s.io/klog/v2 v2.100.1 // indirect + k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect + nhooyr.io/websocket v1.8.6 // indirect + oras.land/oras-go v1.2.4 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect + sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) -go 1.15 +replace ( + github.com/chaos-mesh/chaos-mesh/api => ./api + k8s.io/api => k8s.io/api v0.28.2 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.28.2 + k8s.io/apimachinery => k8s.io/apimachinery v0.28.2 + k8s.io/apiserver => k8s.io/apiserver v0.28.2 + k8s.io/cli-runtime => k8s.io/cli-runtime v0.28.2 + k8s.io/client-go => k8s.io/client-go v0.28.2 + k8s.io/cloud-provider => k8s.io/cloud-provider v0.28.2 + k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.28.2 + k8s.io/code-generator => k8s.io/code-generator v0.28.2 + k8s.io/component-base => k8s.io/component-base v0.28.2 + k8s.io/component-helpers => k8s.io/component-helpers v0.28.2 + k8s.io/controller-manager => k8s.io/controller-manager v0.28.2 + k8s.io/cri-api => k8s.io/cri-api v0.28.2 + k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.28.2 + k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.28.2 + k8s.io/endpointslice => k8s.io/endpointslice v0.28.2 + k8s.io/kms => k8s.io/kms v0.28.2 + k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.28.2 + k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.28.2 + k8s.io/kube-proxy => k8s.io/kube-proxy v0.28.2 + k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.28.2 + k8s.io/kubectl => k8s.io/kubectl v0.28.2 + k8s.io/kubelet => k8s.io/kubelet v0.28.2 + k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.28.2 + k8s.io/metrics => k8s.io/metrics v0.28.2 + k8s.io/mount-utils => k8s.io/mount-utils v0.28.2 + k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.28.2 + k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.28.2 + k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.28.2 + k8s.io/sample-controller => k8s.io/sample-controller v0.28.2 +) diff --git a/go.sum b/go.sum index d6c65da255..e0e909354b 100644 --- a/go.sum +++ b/go.sum @@ -1,737 +1,612 @@ -bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= -bitbucket.org/bertimus9/systemstat v0.0.0-20180207000608-0eeff89b0690/go.mod h1:Ulb78X89vxKYgdL24HMTiXYHlyHEvruOj1ZPlqeNEZM= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3 h1:AVXDdKsrtX33oR9fbCMu/+c1o8Ofjq6Ku/MInaLVg5Y= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk= +cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48 h1:/EMHruHCFXR9xClkGV/t0rmHrdhX4+trQUcBqjwc9xE= code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= -github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= -github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.0 h1:CxTzQrySOxDnKpLjFJeZAS5Qrv/qFPkgLjx5bOAi//I= -github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= -github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= -github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/99designs/gqlgen v0.17.2 h1:yczvlwMsfcVu/JtejqfrLwXuSP0yZFhmcss3caEvHw8= +github.com/99designs/gqlgen v0.17.2/go.mod h1:K5fzLKwtph+FFgh9j7nFbRUdBKvTcGnsta51fsMTn3o= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59MxjQVfjXsBpLy+dbd2/ELV5ofnUkUZBvWSC85sheA= +github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= +github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= +github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk= +github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8= +github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 h1:P6bYXFoao05z5uhOQzbC3Qd8JqF3jUoocoTeIxkp2cA= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.11/go.mod h1:84w/uV8E37feW2NCJ08uT9VBfjfUHpgLVnG2InYD6cg= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 h1:0W/yGmFdTIT77fvdlGZ0LMISoLHFJ7Tx4U0yeB+uFs4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.5/go.mod h1:ADQAXrkgm7acgWVUNamOgh8YNrv4p27l3Wc55oVfpzg= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= +github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= +github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= +github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac= +github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= -github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= -github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q= -github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= -github.com/Microsoft/hcsshim v0.0.0-20190417211021-672e52e9209d h1:u64+IetywsPQ0gJ/4cXBJ/KiXV9xTKRMoaCOzW9PI3g= -github.com/Microsoft/hcsshim v0.0.0-20190417211021-672e52e9209d/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= -github.com/OpenPeeDeeP/depguard v1.0.0/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o= -github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= +github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= +github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Rican7/retry v0.1.0/go.mod h1:FgOROf8P5bebcC1DS0PdOQiqGUridaZvikzUmkFW6gg= -github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= -github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/VictoriaMetrics/fastcache v1.5.2/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= +github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= +github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= +github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= -github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847 h1:rtI0fD4oG/8eVokGVPYJEW1F88p1ZNgXiEIs9thEE4A= -github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7/go.mod h1:LWMyo4iOLWXHGdBki7NIht1kHru/0wM179h+d3g8ATM= -github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go-v2 v0.31.0 h1:TNTDsz+Xq80nYzZPUFS4a2Oyjz9jKHKcTuNAXtcW8b8= -github.com/aws/aws-sdk-go-v2 v0.31.0/go.mod h1:IQw4KL7QIoaNDT3WoEBV1fDlVRhp/WTRteoaplV3SHo= -github.com/aws/aws-sdk-go-v2/config v0.4.0 h1:16lwnZRhleaPbDesZgEJbHxuOv4wy12A372mkhmiktc= -github.com/aws/aws-sdk-go-v2/config v0.4.0/go.mod h1:5uxQPUBCF+TwwWYo2xau4N+rSOS47ZH+QvLbae1Cckc= -github.com/aws/aws-sdk-go-v2/credentials v0.2.0 h1:YDv/0/8BzaZtpS4jfptcyIPh5zlhmIhbM2RtNscn/bo= -github.com/aws/aws-sdk-go-v2/credentials v0.2.0/go.mod h1:U81m6Xb5IpJ66ZnotiG7/6JJFuwrc8q8rWpXQxYP0hI= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v0.1.0 h1:zwhJDxNht/+a0QGy3RCveUFf6REXcmaQIHcYS11m5KY= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v0.1.0/go.mod h1:d3o/QBgbYw2OYmbv/EGYs0zFH47qsCKCTDbaOgdQGH8= -github.com/aws/aws-sdk-go-v2/service/ec2 v0.31.0 h1:WFmkmj3SBb74ahh3/M1FHS6GgQ7uyJKNoUorIWXyYLI= -github.com/aws/aws-sdk-go-v2/service/ec2 v0.31.0/go.mod h1:l0pwXTelza2kR5KczSC7f0HJcgXpROUY+oJ+KvfVkH4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v0.2.0 h1:xeqwfWQGg3hjLMs61PlixdxhU+qqrd7S50j/3kV1j/0= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v0.2.0/go.mod h1:Ef71w/O9Ulhxj8gD9Pq2S0lXMvyNzFLMRuIxWpDRQxk= -github.com/aws/aws-sdk-go-v2/service/sts v0.31.0 h1:iJwlIyswoW4VM8RUmhC3397jdGa6QhMUtUf5daX+/a0= -github.com/aws/aws-sdk-go-v2/service/sts v0.31.0/go.mod h1:gliVu4/DZsKINvBoEcMIlxMIQft/yPYQhnSLxwiWqFM= -github.com/aws/smithy-go v0.5.0 h1:ArsdWUrb1n6/V/REXhuwq2TZv+kuqOBpMlGBd2EkDYM= -github.com/aws/smithy-go v0.5.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= -github.com/bazelbuild/bazel-gazelle v0.18.2/go.mod h1:D0ehMSbS+vesFsLGiD6JXu3mVEzOlfUl8wNnq+x/9p0= -github.com/bazelbuild/bazel-gazelle v0.19.1-0.20191105222053-70208cbdc798/go.mod h1:rPwzNHUqEzngx1iVBfO/2X2npKaT3tqPqqHW6rVsn/A= -github.com/bazelbuild/buildtools v0.0.0-20190731111112-f720930ceb60/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= -github.com/bazelbuild/buildtools v0.0.0-20190917191645-69366ca98f89/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= -github.com/bazelbuild/rules_go v0.0.0-20190719190356-6dae44dc5cab/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antonmedv/expr v1.8.9 h1:O9stiHmHHww9b4ozhPx7T6BK7fXfOCHJ8ybxf0833zw= +github.com/antonmedv/expr v1.8.9/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= +github.com/aws/aws-sdk-go-v2 v1.3.2 h1:RQj8l98yKUm0UV2Wd3w/Ms+TXV9Rs1E6Kr5tRRMfyU4= +github.com/aws/aws-sdk-go-v2 v1.3.2/go.mod h1:7OaACgj2SX3XGWnrIjGlJM22h6yD6MEWKvm7levnnM8= +github.com/aws/aws-sdk-go-v2/config v1.1.1 h1:ZAoq32boMzcaTW9bcUacBswAmHTbvlvDJICgHFZuECo= +github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y= +github.com/aws/aws-sdk-go-v2/credentials v1.1.1 h1:NbvWIM1Mx6sNPTxowHgS2ewXCRp+NGTzUYb/96FZJbY= +github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2 h1:EtEU7WRaWliitZh2nmuxEXrN0Cb8EgPUFGIoTMeqbzI= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.5.0 h1:LG5ozCp5FRKOodR2NPtbn9c/yrSrodTkzOGjRJY5yV8= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.5.0/go.mod h1:3iBezuZtNxZnKX7Zv2JB/lGyGCSYOES8TMq4WSXPBl0= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.6 h1:ldYIsOP4WyjdzW8t6RC/aSieajrlx+3UN3UCZy1KM5Y= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.6/go.mod h1:L0KWr0ASo83PRZu9NaZaDsw3koS6PspKv137DMDZjHo= +github.com/aws/aws-sdk-go-v2/service/sso v1.1.1 h1:37QubsarExl5ZuCBlnRP+7l1tNwZPBSTqpTBrPH98RU= +github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= +github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 h1:TJoIfnIFubCX0ACVeJ0w46HEH5MwjwYN4iFhuYIhfIY= +github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= +github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= +github.com/aws/smithy-go v1.3.1 h1:xJFO4pK0y9J8fCl34uGsSJX5KNnGbdARDlA5BPhXnwE= +github.com/aws/smithy-go v1.3.1/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= -github.com/bruth/assert v0.0.0-20130823105606-de420fa3b72e/go.mod h1:MT8TZkfLPRir91B19sXF7pmKBma+n6ecyjbqgXabchs= -github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= github.com/bxcodec/faker v2.0.1+incompatible h1:P0KUpUw5w6WJXwrPfv35oc91i4d8nf40Nwln+M/+faA= github.com/bxcodec/faker v2.0.1+incompatible/go.mod h1:BNzfpVdTwnFJ6GtfYTcQu6l6rHShT+veBxNCnjCx5XM= -github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E= -github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/prettybench v0.0.0-20150116022406-03b8cfe5406c/go.mod h1:Xe6ZsFhtM8HrDku0pxJ3/Lr51rwykrzgFwpmTzleatY= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.0.1-0.20190104013014-3767db7a7e18/go.mod h1:HD5P3vAIAh+Y2GAxg0PrPN1P8WkepXGpjbUPDHJqqKM= -github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= +github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= +github.com/chaos-mesh/chaos-driver v0.2.1 h1:F/ahUg2Lih6ITOWpwHlo57peLMqPMTFD/WVSzr0cagw= +github.com/chaos-mesh/chaos-driver v0.2.1/go.mod h1:yrsVhX9sXaMDQQ/qBRdcNXlR4Spkcw1Z/vyXMbIuUyE= +github.com/chaos-mesh/fx-logr v0.1.0 h1:PpcZupwNV412MuwTc9VmV0MVV6yfOkJj5OUw/gq8bvo= +github.com/chaos-mesh/fx-logr v0.1.0/go.mod h1:E/YEQAKSnn+vDMjlf7Ju/gZeobSLchNkSReaE68r8eA= github.com/chaos-mesh/k8s_dns_chaos v0.2.0 h1:6GeoVQkuUBI4U8TdlH4R8Jgocq1Y9C4hQUQK2h6Lgl0= github.com/chaos-mesh/k8s_dns_chaos v0.2.0/go.mod h1:CB8grXv5pqxLgiI0HSZxyyykmDRekpd5M7fz+NlOdMs= -github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b/go.mod h1:TrMrLQfeENAPYPRsJuq3jsqdlRh3lvi6trTZJG8+tho= -github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= -github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= -github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= -github.com/container-storage-interface/spec v1.2.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4= -github.com/containerd/cgroups v0.0.0-20200404012852-53ba5634dc0f h1:i00XhARuCBYiclc8aAhOCzR1fHKN2oZzi7XStnv2eoM= -github.com/containerd/cgroups v0.0.0-20200404012852-53ba5634dc0f/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= -github.com/containerd/console v0.0.0-20170925154832-84eeaae905fa/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= -github.com/containerd/containerd v1.0.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.2.3 h1:6TvLXAk7vuAF72J3p6Fcw6c7Z8CDZFbZrHl+XIovyqk= -github.com/containerd/containerd v1.2.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41 h1:kIFnQBO7rQ0XkMe6xEwbybYHBEaWmh/f++laI6Emt7M= -github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= -github.com/containerd/cri v1.11.1 h1:mR8+eNW4zEcbWGTGEpmDd7GzMmK7IMxMSVAZ2aIDKA4= -github.com/containerd/cri v1.11.1/go.mod h1:DavH5Qa8+6jOmeOMO3dhWoqksucZDe06LfuhBz/xPZs= -github.com/containerd/fifo v0.0.0-20191213151349-ff969a566b00 h1:lsjC5ENBl+Zgf38+B0ymougXFp0BaubeIVETltYZTQw= -github.com/containerd/fifo v0.0.0-20191213151349-ff969a566b00/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= -github.com/containerd/typeurl v0.0.0-20190228175220-2a93cfde8c20/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= -github.com/containerd/typeurl v0.0.0-20200115183213-fe1d0d650e42 h1:H4HpszQHIK7mWAG5X6uwgBh2lladSDHHMIwwkaNl860= -github.com/containerd/typeurl v0.0.0-20200115183213-fe1d0d650e42/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= -github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= -github.com/coredns/corefile-migration v1.0.4/go.mod h1:OFwBp/Wc9dJt5cAZzHWMNhK1r5L0p0jDwIBc6j8NC8E= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= -github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28= -github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/containerd/containerd v1.7.11 h1:lfGKw3eU35sjV0aG2eYZTiwFEY1pCzxdzicHP3SZILw= +github.com/containerd/containerd v1.7.11/go.mod h1:5UluHxHTX2rdvYuZ5OJTC5m/KJNs0Zs9wVoJm9zf5ZE= +github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= +github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY= +github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/ttrpc v1.2.2 h1:9vqZr0pxwOF5koz6N0N3kJ0zDHokrcPxIR/ZR2YFtOs= +github.com/containerd/ttrpc v1.2.2/go.mod h1:sIT6l32Ph/H9cvnJsfXM5drIVzTr5A2flTf1G5tYZak= +github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4= +github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= -github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= -github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X6GqbFowYdYdI0L9bwxL07jyPZIdepyZ0= -github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= +github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= +github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= -github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf h1:sh8rkQZavChcmakYiSlqu2425CHyFXLZZnvm7PDpU8M= -github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk= +github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= +github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= +github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc= +github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY= +github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= +github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= +github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= -github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/libnetwork v0.8.0-dev.2.0.20190624125649-f0e46a78ea34/go.mod h1:93m0aTqz6z+g32wla4l4WxTrdtvBRmVzYRkYvasA5Z8= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= -github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= +github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= +github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= -github.com/ethereum/go-ethereum v1.9.8 h1:4KUtrZOt45Ob1yXh0Mv/pPWRib/6B4p2l41nzEsEgVw= -github.com/ethereum/go-ethereum v1.9.8/go.mod h1:N68Ktr8bkyajaEy6D8CSANxkhUxcnVjTmp9sKdKd8OI= -github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= -github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= -github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/ethereum/go-ethereum v1.12.1 h1:1kXDPxhLfyySuQYIfRxVBGYuaHdxNNxevA73vjIwsgk= +github.com/ethereum/go-ethereum v1.12.1/go.mod h1:zKetLweqBR8ZS+1O9iJWI8DvmmD2NzD19apjEWDCsnw= +github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= -github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= -github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fvbommel/util v0.0.2/go.mod h1:n7nJJ4dUdRBvS0OR9FZ9zhHvQJX/3DoYiStK6hUtafs= -github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= +github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= -github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= +github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= +github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= github.com/gin-contrib/pprof v1.3.0 h1:G9eK6HnbkSqDZBYbzG4wrjCsA4e+cvYAHUZw6W+W9K0= github.com/gin-contrib/pprof v1.3.0/go.mod h1:waMjT1H9b179t3CxuG1cV3DHpga6ybizwfBaM5OXaB0= -github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= -github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= -github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-acme/lego v2.5.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M= -github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= -github.com/go-critic/go-critic v0.3.5-0.20190526074819-1df300866540/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= +github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54= -github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= -github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= -github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= -github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= -github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= -github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= -github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= +github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= -github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= -github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= -github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= -github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= -github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ= +github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= -github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= -github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/overalls v0.0.0-20180201144345-22ec1a223b7c/go.mod h1:UqxAgEOt89sCiXlrc/ycnx00LVvUO/eS8tMUkWX4R7w= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.3.0 h1:nZU+7q+yJoFmwvNgv/LnPUkwPal62+b2xXj0AU1Es7o= -github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= -github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= -github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= -github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= -github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg= -github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= -github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU= -github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk= -github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= -github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks= -github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc= -github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= -github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= -github.com/gobuffalo/flect v0.2.0 h1:EWCvMGGxOjsgwlWaP+f4+Hh6yrrte7JeFL2S6b+0hdM= -github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= +github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= +github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= +github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f h1:zlOR3rOlPAVvtfuxGKoghCmop5B0TRyu/ZieziZuGiM= -github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= -github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/googleapis v1.3.2 h1:kX1es4djPJrsDhY7aZKJy7aZasdcB5oSOEphMjSB53c= -github.com/gogo/googleapis v1.3.2/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.0.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= -github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= -github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= -github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8= -github.com/golangci/go-tools v0.0.0-20190318055746-e32c54105b7c/go.mod h1:unzUULGw35sjyOYjUt0jMTXqHlZPpPc6e+xfO4cd6mM= -github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o= -github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= -github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= -github.com/golangci/golangci-lint v1.18.0/go.mod h1:kaqo8l0OZKYPtjNmG4z4HrWLgcYNIJ9B9q3LWri9uLg= -github.com/golangci/gosec v0.0.0-20190211064107-66fb7fc33547/go.mod h1:0qUabqiIQgfmlAmulqxyiGkkyF6/tOGSnY2cnPVwrzU= -github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU= -github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= -github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= -github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= -github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI= -github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= -github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= -github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= -github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= -github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/cadvisor v0.35.0/go.mod h1:1nql6U13uTHaLYB8rLS5x9IJc2qT6Xd/Tr1sTX6NE48= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= +github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= -github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= -github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= +github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U= -github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= -github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= -github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= +github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= +github.com/graph-gophers/graphql-go v0.0.0-20201112095111-7a585a01e04c/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg= -github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.14.1 h1:YuM9SXYy583fxvSOkzCDyBPCtY+/IMSHEG1dKFMLZsA= -github.com/grpc-ecosystem/grpc-gateway v1.14.1/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= -github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/heketi/heketi v9.0.1-0.20190917153846-c2e2a4ab7ab9+incompatible/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o= -github.com/heketi/tests v0.0.0-20151005000721-f3775cbcefd6/go.mod h1:xGMAM8JLi7UkZt1i4FQeQy0R2T8GLUwQhOP5M1gBhy4= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.6 h1:3xi/Cafd1NaoEnS/yDssIiuVeDVywU0QdFGl3aQaQHM= +github.com/hashicorp/golang-lru/v2 v2.0.6/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hasura/go-graphql-client v0.2.0 h1:Ux6NQFkR6RCoNEMRsdJ1Hz0P43TRpLIzAXTXnNcEMxU= +github.com/hasura/go-graphql-client v0.2.0/go.mod h1:ovhXpnBL/+pYmmdYHndovgAc/wmhaXKvKwJETjtMomQ= +github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= +github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= -github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= +github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= +github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/joomcode/errorx v1.0.1 h1:CalpDWz14ZHd68fIqluJasJosAewpz2TFaJALrUxjrk= github.com/joomcode/errorx v1.0.1/go.mod h1:kgco15ekB6cs+4Xjzo7SPeXzx38PbJzBwbnu9qfVNHQ= -github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= +github.com/karrick/godirwalk v1.17.0 h1:b4kY7nqDdioR/6qnbHQyDvmA17u5G1cZ6J+CZXwSWoI= +github.com/karrick/godirwalk v1.17.0/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/gotool v0.0.0-20161130080628-0de1eaf82fa3/go.mod h1:jxZFDH7ILpTPQTk+E2s+z4CUas9lVNjIuKR4c5/zKgM= +github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= -github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/lpabon/godbc v0.1.1/go.mod h1:Jo9QV0cf3U6jZABgiJ2skINAXb9j8m51r07g4KI92ZA= -github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH9J1c9oX6otFSgdUHwUBUizmKlrMjxWnIAjff4m04= -github.com/lucas-clemente/quic-clients v0.1.0/go.mod h1:y5xVIEoObKqULIKivu+gD/LU90pL73bTdtQjPBvtCBk= -github.com/lucas-clemente/quic-go v0.10.2/go.mod h1:hvaRS9IHjFLMq76puFJeWNfmn+H70QZ/CXoxqw9bzao= -github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58= -github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc= +github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= +github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= +github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY= +github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= +github.com/matryer/moq v0.2.3/go.mod h1:9RtPYjTnH1bSBIkpvtHkFN7nbWAnO7oRpdJkEIn6UtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0= github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mesos/mesos-go v0.0.9/go.mod h1:kPYCMQ9gsOXVAle1OsoY4I1+9kPu8GHkf88aV59fDr4= -github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81 h1:QASJXOGm2RZ5Ardbc86qNFvby9AqkLDibfChMtAg5QM= -github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= -github.com/mgechev/revive v1.0.2-0.20200225072153-6219ca02fffb h1:EabZ4SffLYB6FcYN8VDMk1TCMahjhEhEqKcOxBNbPmY= -github.com/mgechev/revive v1.0.2-0.20200225072153-6219ca02fffb/go.mod h1:E9j8UNyHeYo/uUXIIUOAehxf5B69UwZ5u3qj7wEn8J0= -github.com/mholt/certmagic v0.6.2-0.20190624175158-6a42ef9fe8c2/go.mod h1:g4cOPxcjV0oFq3qwpjSA30LReKD8AoIfwAY9VvG35NY= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY= -github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= -github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/mitchellh/mapstructure v1.2.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= +github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI= +github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mozilla/tls-observatory v0.0.0-20180409132520-8791a200eb40/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= -github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= -github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/nbutton23/zxcvbn-go v0.0.0-20160627004424-a22cb81b2ecd/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= -github.com/nbutton23/zxcvbn-go v0.0.0-20171102151520-eafdab6b0663/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= -github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.4.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.3.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.12.0 h1:UIVDowFPwpg6yMUpPjGkYvf06K3RAiJXUhCxEwQVHRI= +github.com/onsi/ginkgo/v2 v2.12.0/go.mod h1:ZNEzXISYlqpb8S36iN71ifqLi3vVD1rVJGvWRCJOUpQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= -github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU4LguQVtc= -github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= -github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= +github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss= +github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8= +github.com/opencontainers/runtime-spec v1.1.0-rc.1 h1:wHa9jroFfKGQqFHj0I1fMRKLl0pfj+ynAqBxo3v6u9w= +github.com/opencontainers/runtime-spec v1.1.0-rc.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= +github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.3.0 h1:e5+lF2E4Y2WCIxBefVowBuB0iHrUH4HZ8q+6mGF7fJc= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pelletier/go-toml v1.3.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8/go.mod h1:B1+S9LNcuMyLH/4HMTViQOJevkGiik3wW2AN9zb2fNQ= github.com/pingcap/check v0.0.0-20191216031241-8a5a85928f12 h1:rfD9v3+ppLPzoQBgZev0qYCpegrwyFx/BUpkApEiKdY= github.com/pingcap/check v0.0.0-20191216031241-8a5a85928f12/go.mod h1:PYMCGwN0JHjoqGr3HrZoD+b8Tgx8bKnArhSq8YVzUMc= @@ -740,588 +615,496 @@ github.com/pingcap/errors v0.11.5-0.20190809092503-95897b64e011 h1:58naV4XMEqm0h github.com/pingcap/errors v0.11.5-0.20190809092503-95897b64e011/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pingcap/failpoint v0.0.0-20200210140405-f8f9fb234798 h1:6DMbRqPI1qzQ8N1xc3+nKY8IxSACd9VqQKkRVvbyoIg= github.com/pingcap/failpoint v0.0.0-20200210140405-f8f9fb234798/go.mod h1:DNS3Qg7bEDhU6EXNHF+XSv/PGznQaMJ5FWvctpm6pQI= +github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 h1:AJD9pZYm72vMgPcQDww9rkZ1DnWfl0pXV3BOWlkYIjA= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= -github.com/pingcap/log v0.0.0-20200117041106-d28c14d3b1cd h1:CV3VsP3Z02MVtdpTMfEgRJ4T9NGgGTxdHpJerent7rM= -github.com/pingcap/log v0.0.0-20200117041106-d28c14d3b1cd/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.4 h1:Lb0RYJCmgUcBgZosfoi9Y9sbl6+LJgOIgk/2Y4YjMFg= +github.com/pkg/sftp v1.13.4/go.mod h1:LzqnAvaD5TWeNBsZpfKxSYn1MbjWwOsCIAFFJbpIsK8= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/pquerna/ffjson v0.0.0-20180717144149-af8b230fcd20/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= +github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= -github.com/quobyte/api v0.1.2/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI= -github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= -github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= -github.com/robertkrimen/otto v0.0.0-20170205013659-6a77b7cbc37d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= -github.com/robfig/cron v1.1.0 h1:jk4/Hud3TTdcrJgUOBgsqrZBarcxl6ADIjSC2iniwLY= -github.com/robfig/cron v1.1.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/retailnext/iptables_exporter v0.1.0 h1:3s+6bK0AzwwhT6R/5/8sOejDBROd+KkOHikEynMOWIM= +github.com/retailnext/iptables_exporter v0.1.0/go.mod h1:Gu8Unq1643kG+B6abj8eghNoxoa48jrlNEneXzTiTyI= +github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00 h1:8DPul/X0IT/1TNMIxoKLwdemEOBBHDC/K4EB16Cw5WE= -github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521 h1:3hxavr+IHMsQBrYUPQM5v0CgENFktkkbg1sfpgM3h20= -github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= -github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= -github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/romana/ipset v1.0.0 h1:CELryXKTlypCeW/fqqUee/bBIfwjvFn4jBGnWV+UuOY= +github.com/romana/ipset v1.0.0/go.mod h1:AeXLBaoBOJKSqnrqAkmNgoNaF6PjtERU9jijfTA6AV4= +github.com/romana/rlog v0.0.0-20171115192701-f018bc92e7d7 h1:jkvpcEatpwuMF5O5LVxTnehj6YZ/aEZN4NWD/Xml4pI= +github.com/romana/rlog v0.0.0-20171115192701-f018bc92e7d7/go.mod h1:KTrHyWpO1sevuXPZwyeZc72ddWRFqNSKDFl7uVWKpg0= +github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0= +github.com/rubenv/sql-migrate v1.5.2/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sergi/go-diff v1.0.1-0.20180205163309-da645544ed44 h1:tB9NOR21++IjLyVx3/PCPhWMwqGNCMQEH96A6dMZ/gc= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sanity-io/litter v1.2.0/go.mod h1:JF6pZUFgu2Q0sBZ+HSV35P8TVPI1TTzEwyu9FXAw2W4= github.com/sergi/go-diff v1.0.1-0.20180205163309-da645544ed44/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7 h1:80VN+vGkqM773Br/uNNTSheo3KatTgV8IpjIKjvVLng= -github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 h1:udFKJ0aHUL60LboW/A+DfgoHVedieIzIXE8uylPue0U= -github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= -github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= -github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd h1:ug7PpSOB5RBPK1Kg6qskGBoP3Vnj/aNYFTznWvlkGo0= github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= -github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= -github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= -github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= -github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= -github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= -github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= -github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 h1:PyYN9JH5jY9j6av01SpfRMb+1DWg/i3MbGOKPxJ2wjM= -github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= -github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0= -github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= -github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= -github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s= -github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= -github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8= -github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= -github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/thecodeteam/goscaleio v0.1.0/go.mod h1:68sdkZAsK8bvEwBlbQnlLS+xU+hvLYM/iQ8KXej1AwM= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc h1:yUaosFVTJwnltaHbSNC3i82I92quFs+OFPRl8kNMVwo= -github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.5.3 h1:8mWmHLolIbrhJJTflsaFoZzRBYVmEE7JZGIq08EiC0Q= +github.com/swaggo/gin-swagger v1.5.3/go.mod h1:3XJKSfHjDMB5dBo/0rrTXidPmgLeqsX89Yp4uA50HpI= +github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ= +github.com/swaggo/swag v1.8.7 h1:2K9ivTD3teEO+2fXV6zrZKDqk5IuU2aJtBDo8U7omWU= +github.com/swaggo/swag v1.8.7/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk= +github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo= +github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= +github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ= +github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= -github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k= -github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= -github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= -github.com/vishvananda/netlink v1.0.0 h1:bqNY2lgheFIu1meHUFSH3d7vG93AFyqg3oGbJCOJgSM= -github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= -github.com/vishvananda/netns v0.0.0-20171111001504-be1fbeda1936 h1:J9gO8RJCAFlln1jsvRba/CWVUnMHwObklfxxjErl1uk= -github.com/vishvananda/netns v0.0.0-20171111001504-be1fbeda1936/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= -github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= -github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/vektah/gqlparser/v2 v2.4.0/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0= +github.com/vektah/gqlparser/v2 v2.4.5 h1:C02NsyEsL4TXJB7ndonqTfuQOL4XPIu0aAWugdmTgmc= +github.com/vektah/gqlparser/v2 v2.4.5/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0= +github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= +github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= +github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= +github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yookoala/realpath v1.0.0/go.mod h1:gJJMA9wuX7AcqLy1+ffPatSCySA1FQ2S8Ya9AIoYBpE= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/dig v1.9.0 h1:pJTDXKEhRqBI8W7rU7kwT5EgyRZuSMVSFcZolOvKK9U= -go.uber.org/dig v1.9.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= -go.uber.org/fx v1.12.0 h1:+1+3Cz9M0dFMPy9SW9XUIUHye8bnPUm7q7DroNGWYG4= -go.uber.org/fx v1.12.0/go.mod h1:egT3Kyg1JFYQkvKLZ3EsykxkNrZxgXS+gKoKo7abERY= -go.uber.org/goleak v0.10.0 h1:G3eWbSNIskeRqtsN/1uI5B+eP73y3JUuBsv9AZjehb4= -go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/dig v1.16.1 h1:+alNIBsl0qfY0j6epRubp/9obgtrObRAc5aD+6jbWY8= +go.uber.org/dig v1.16.1/go.mod h1:557JTAUZT5bUK0SvCwikmLPPtdQhfvLYtO5tJgQSbnk= +go.uber.org/fx v1.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY= +go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= -go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= -golang.org/x/build v0.0.0-20190927031335-2835ba2e683f/go.mod h1:fYw7AShPAhGMdXqA9gRadk/CcMsvLlClpE5oBwnS3dM= -golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180426230345-b49d69b5da94/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= +go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190424203555-c05e17bb3b2d/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd h1:GGJVjV8waZKRHrgwvtH66z9ZGVurTD1MT0n1Bb+q4aM= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180112015858-5ccada7d0a7b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190502183928-7f726cade0ab/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200320220750-118fecf932d8 h1:1+zQlQqEEhUeStBTi653GZAnAuivZq/2hz+Iz+OP7rg= -golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20171026204733-164713f0dfce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180117170059-2c42eef0765b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190122071731-054c452bb702/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.0.0-20170915090833-1cbadb444a80/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20170915040203-e531a2a1c15f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190121143147-24cd39ecf745/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190122202912-9c309ee22fab/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190909030654-5b82db07426d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191107010934-f79515f33823/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191114200427-caa0b0f7d508/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200309202150-20ab64c0d93f h1:NbrfHxef+IfdI86qCgO/1Siq1BuMH2xG0NqgvCguRhQ= -golang.org/x/tools v0.0.0-20200309202150-20ab64c0d93f/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200815165600-90abf76919f3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= +golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0= -gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= -gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0 h1:Q3Ui3V3/CVinFWFiW39Iw0kMuVrRzYX0wN6OPFp0lTA= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= +google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a h1:Ob5/580gVHBJZgXnff1cZDbG+xLtMVE5mDRTe+nIsX4= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= +google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/gometalinter.v2 v2.0.12/go.mod h1:NDRytsqEZyolNuAgTzJkZMkSQM7FIKyzVzGhjB/qfYo= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c/go.mod h1:3HH7i1SgMqlzxCcBmUHW657sD4Kvv9sC3HpL3YukzwA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= -gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190213234257-ec84240a7772/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= -gopkg.in/square/go-jose.v2 v2.2.2 h1:orlkJ3myw8CN1nVQHBFfloD+L3egixIa4FvUP6RosSA= -gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= -gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.0.0/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966 h1:B0J02caTR6tpSJozBJyiAzT6CtBzjclw4pgm9gg8Ys0= -gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/gotestsum v0.3.5/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY= -grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +helm.sh/helm/v3 v3.13.3 h1:0zPEdGqHcubehJHP9emCtzRmu8oYsJFRrlVF3TFj8xY= +helm.sh/helm/v3 v3.13.3/go.mod h1:3OKO33yI3p4YEXtTITN2+4oScsHeQe71KuzhlZ+aPfg= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM= -k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= -k8s.io/apiextensions-apiserver v0.17.0 h1:+XgcGxqaMztkbbvsORgCmHIb4uImHKvTjNyu7b8gRnA= -k8s.io/apiextensions-apiserver v0.17.0/go.mod h1:XiIFUakZywkUl54fVXa7QTEHcqQz9HG55nHd1DCoHj8= -k8s.io/apimachinery v0.17.1-beta.0 h1:0Wl/KpAiFOMe9to5h8x2Y6JnjV+BEWJiTcUk1Vx7zdE= -k8s.io/apimachinery v0.17.1-beta.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apiserver v0.17.0 h1:XhUix+FKFDcBygWkQNp7wKKvZL030QUlH1o8vFeSgZA= -k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= -k8s.io/cli-runtime v0.17.0 h1:XEuStbJBHCQlEKFyTQmceDKEWOSYHZkcYWKp3SsQ9Hk= -k8s.io/cli-runtime v0.17.0/go.mod h1:1E5iQpMODZq2lMWLUJELwRu2MLWIzwvMgDBpn3Y81Qo= -k8s.io/client-go v0.17.0 h1:8QOGvUGdqDMFrm9sD6IUFl256BcffynGoe80sxgTEDg= -k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= -k8s.io/cloud-provider v0.17.0 h1:BQZPD1Ja/vnTOj1GKI9/wSpd3qgIDZp9q2NAS3568Ac= -k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= -k8s.io/cluster-bootstrap v0.17.0/go.mod h1:KnxktBWGyKlBDaHLC8zzu0EPt/HJ9Lcs7bNM2WvUHSs= -k8s.io/code-generator v0.17.1-beta.0/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= -k8s.io/component-base v0.17.0 h1:BnDFcmBDq+RPpxXjmuYnZXb59XNN9CaFrX8ba9+3xrA= -k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= -k8s.io/cri-api v0.17.1-beta.0 h1:fE6pn9XSkRjaqZdqVW3RiSrT9GaKCDVj0S8AWsZ7hCI= -k8s.io/cri-api v0.17.1-beta.0/go.mod h1:BzAkbBHHp81d+aXzbiIcUbilLkbXa40B8mUHOk6EX3s= -k8s.io/csi-translation-lib v0.17.0 h1:8hwWJDMOBCAogaWXtNWy0dYGQ2dZYzOnOzjQMiDaY+E= -k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/heapster v1.2.0-beta.1/go.mod h1:h1uhptVXMwC8xtZBYsPXKVi8fpdlYkTs6k949KozGrM= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-aggregator v0.17.0 h1:2/15hPpXp11GvQmtLeTlNP6WeZnmebs/uxckzZS3P9c= -k8s.io/kube-aggregator v0.17.0/go.mod h1:Vw104PtCEuT12WTVuhRFWCHXGiVqXsTzFtrvoaHxpk4= -k8s.io/kube-controller-manager v0.17.0/go.mod h1:uewKsjSm/Kggbn+BmimupXDDEikKQv6rX8ShiLiuXTw= -k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= -k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kube-proxy v0.17.0/go.mod h1:pecyGyajk667mTTCT0vMP7Oh3bQMUHvEW+Z5pZUjYxU= -k8s.io/kube-scheduler v0.17.0/go.mod h1:mZVsEg++qnq6xWm9DTh2bw9v2i9XPdkEQGDafcjG6PE= -k8s.io/kubectl v0.17.0 h1:xD4EWlL+epc/JTO1gvSjmV9yiYF0Z2wiHK2DIek6URY= -k8s.io/kubectl v0.17.0/go.mod h1:jIPrUAW656Vzn9wZCCe0PC+oTcu56u2HgFD21Xbfk1s= -k8s.io/kubelet v0.17.0/go.mod h1:e/JBCxucKuEV6JO6zYW+e72ib9eMsGO2Fah3iT5tiiI= -k8s.io/kubernetes v1.17.2 h1:g1UFZqFQsYx88xMUks4PKC6tsNcekxe0v06fcVGRwVE= -k8s.io/kubernetes v1.17.2/go.mod h1:NbNV+69yL3eKiKDJ+ZEjqOplN3BFXKBeunzkoOy8WLo= -k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= -k8s.io/metrics v0.17.0/go.mod h1:EH1D3YAwN6d7bMelrElnLhLg72l/ERStyv2SIQVt6Do= -k8s.io/repo-infra v0.0.1-alpha.1/go.mod h1:wO1t9WaB99V80ljbeENTnayuEEwNZt7gECYh/CEyOJ8= -k8s.io/sample-apiserver v0.17.0/go.mod h1:SAkguNIe/gJik7VlkFu62oGlWltW3c0mAP9WQYUMEJo= -k8s.io/system-validators v1.0.4/go.mod h1:HgSgTg4NAGNoYYjKsUyk52gdNi2PVDswQ9Iyn66R7NI= -k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= -k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= -modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= -modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= -modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= -modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= -mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= -mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= -mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34/go.mod h1:H6SUd1XjIs+qQCyskXg5OFSrilMRUkD8ePJpHKDPaeY= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -sigs.k8s.io/controller-runtime v0.4.0 h1:wATM6/m+3w8lj8FXNaO6Fs/rq/vqoOjO1Q116Z9NPsg= -sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns= -sigs.k8s.io/controller-tools v0.2.5 h1:kH7HKWed9XO42OTxyhUtqyImiefdZV2Q9Jbrytvhf18= -sigs.k8s.io/controller-tools v0.2.5/go.mod h1:+t0Hz6tOhJQCdd7IYO0mNzimmiM9sqMU0021u6UCF2o= -sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= -sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= -sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= -sigs.k8s.io/testing_frameworks v0.1.2 h1:vK0+tvjF0BZ/RYFeZ1E6BYBwHJJXhjuZ3TdsEKH+UQM= -sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= +k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= +k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= +k8s.io/apiextensions-apiserver v0.28.2 h1:J6/QRWIKV2/HwBhHRVITMLYoypCoPY1ftigDM0Kn+QU= +k8s.io/apiextensions-apiserver v0.28.2/go.mod h1:5tnkxLGa9nefefYzWuAlWZ7RZYuN/765Au8cWLA6SRg= +k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= +k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= +k8s.io/apiserver v0.28.2 h1:rBeYkLvF94Nku9XfXyUIirsVzCzJBs6jMn3NWeHieyI= +k8s.io/apiserver v0.28.2/go.mod h1:f7D5e8wH8MWcKD7azq6Csw9UN+CjdtXIVQUyUhrtb+E= +k8s.io/cli-runtime v0.28.2 h1:64meB2fDj10/ThIMEJLO29a1oujSm0GQmKzh1RtA/uk= +k8s.io/cli-runtime v0.28.2/go.mod h1:bTpGOvpdsPtDKoyfG4EG041WIyFZLV9qq4rPlkyYfDA= +k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= +k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= +k8s.io/component-base v0.28.2 h1:Yc1yU+6AQSlpJZyvehm/NkJBII72rzlEsd6MkBQ+G0E= +k8s.io/component-base v0.28.2/go.mod h1:4IuQPQviQCg3du4si8GpMrhAIegxpsgPngPRR/zWpzc= +k8s.io/cri-api v0.28.2 h1:RzDo9YY9tkWhAx9/UZEcn6ug1WcvDhU3eA1YLevFreI= +k8s.io/cri-api v0.28.2/go.mod h1:xXygwvSOGcT/2KXg8sMYTHns2xFem3949kCQn5IS1k4= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= +k8s.io/kubectl v0.28.2 h1:fOWOtU6S0smdNjG1PB9WFbqEIMlkzU5ahyHkc7ESHgM= +k8s.io/kubectl v0.28.2/go.mod h1:6EQWTPySF1fn7yKoQZHYf9TPwIl2AygHEcJoxFekr64= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY= +oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +sigs.k8s.io/controller-runtime v0.16.2 h1:mwXAVuEk3EQf478PQwQ48zGOXvW27UJc8NHktQVuIPU= +sigs.k8s.io/controller-runtime v0.16.2/go.mod h1:vpMu3LpI5sYWtujJOa2uPK61nB5rbwlN7BAB8aSLvGU= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= +sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= +sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= +sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/hack/boilerplate/boilerplate.generatego.txt b/hack/boilerplate/boilerplate.generatego.txt index b072c9c813..56cd5a6b5c 100644 --- a/hack/boilerplate/boilerplate.generatego.txt +++ b/hack/boilerplate/boilerplate.generatego.txt @@ -4,9 +4,11 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// \ No newline at end of file diff --git a/hack/boilerplate/boilerplate.go.txt b/hack/boilerplate/boilerplate.go.txt deleted file mode 100644 index 27c335d130..0000000000 --- a/hack/boilerplate/boilerplate.go.txt +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright YEAR Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. diff --git a/hack/boilerplate/boilerplate.gomock.txt b/hack/boilerplate/boilerplate.gomock.txt deleted file mode 100644 index 2a9727366f..0000000000 --- a/hack/boilerplate/boilerplate.gomock.txt +++ /dev/null @@ -1,12 +0,0 @@ -Copyright Chaos Mesh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file diff --git a/hack/boilerplate/boilerplate.py b/hack/boilerplate/boilerplate.py deleted file mode 100755 index cafee0356c..0000000000 --- a/hack/boilerplate/boilerplate.py +++ /dev/null @@ -1,239 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2015 The Kubernetes Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import print_function - -import argparse -import datetime -import difflib -import glob -import os -import re -import sys - -parser = argparse.ArgumentParser() -parser.add_argument( - "filenames", - help="list of files to check, all files if unspecified", - nargs='*') - -rootdir = os.path.dirname(__file__) + "/../../" -rootdir = os.path.abspath(rootdir) -parser.add_argument( - "--rootdir", default=rootdir, help="root directory to examine") - -default_boilerplate_dir = os.path.join(rootdir, "hack/boilerplate") -parser.add_argument( - "--boilerplate-dir", default=default_boilerplate_dir) - -parser.add_argument( - "-v", "--verbose", - help="give verbose output regarding why a file does not pass", - action="store_true") - -args = parser.parse_args() - -verbose_out = sys.stderr if args.verbose else open("/dev/null", "w") - - -def get_refs(): - refs = {} - - for path in glob.glob(os.path.join(args.boilerplate_dir, "boilerplate.*.txt")): - extension = os.path.basename(path).split(".")[1] - - ref_file = open(path, 'r') - ref = ref_file.read().splitlines() - ref_file.close() - refs[extension] = ref - - return refs - - -def is_generated_file(filename, data, regexs): - for d in skipped_ungenerated_files: - if d in filename: - return False - - p = regexs["generated"] - return p.search(data) - - -def file_passes(filename, refs, regexs): - try: - f = open(filename, 'r') - except Exception as exc: - print("Unable to open %s: %s" % (filename, exc), file=verbose_out) - return False - - data = f.read() - f.close() - - # determine if the file is automatically generated - generated = is_generated_file(filename, data, regexs) - - basename = os.path.basename(filename) - extension = file_extension(filename) - if generated: - if extension == "go": - extension = "generatego" - elif extension == "bzl": - extension = "generatebzl" - - if extension != "": - ref = refs[extension] - else: - ref = refs[basename] - - # remove extra content from the top of files - if extension == "go" or extension == "generatego": - p = regexs["go_build_constraints"] - (data, found) = p.subn("", data, 1) - elif extension in ["sh", "py"]: - p = regexs["shebang"] - (data, found) = p.subn("", data, 1) - - data = data.splitlines() - - # if our test file is smaller than the reference it surely fails! - if len(ref) > len(data): - print('File %s smaller than reference (%d < %d)' % - (filename, len(data), len(ref)), - file=verbose_out) - return False - - # trim our file to the same number of lines as the reference file - data = data[:len(ref)] - - p = regexs["year"] - for d in data: - if p.search(d): - if generated: - print('File %s has the YEAR field, but it should not be in generated file' % - filename, file=verbose_out) - else: - print('File %s has the YEAR field, but missing the year of date' % - filename, file=verbose_out) - return False - - if not generated: - # Replace all occurrences of the regex "2014|2015|2016|2017|2018" with "YEAR" - p = regexs["date"] - for i, d in enumerate(data): - (data[i], found) = p.subn('YEAR', d) - if found != 0: - break - - # if we don't match the reference at this point, fail - if ref != data: - print("Header in %s does not match reference, diff:" % - filename, file=verbose_out) - if args.verbose: - print(file=verbose_out) - for line in difflib.unified_diff(ref, data, 'reference', filename, lineterm=''): - print(line, file=verbose_out) - print(file=verbose_out) - return False - - return True - - -def file_extension(filename): - return os.path.splitext(filename)[1].split(".")[-1].lower() - - -skipped_dirs = [] - -# list all the files contain 'DO NOT EDIT', but are not generated -skipped_ungenerated_files = ['hack/boilerplate/boilerplate.py'] - - -def normalize_files(files): - newfiles = [] - for pathname in files: - if any(x in pathname for x in skipped_dirs): - continue - newfiles.append(pathname) - for i, pathname in enumerate(newfiles): - if not os.path.isabs(pathname): - newfiles[i] = os.path.join(args.rootdir, pathname) - return newfiles - - -def get_files(extensions): - files = [] - if len(args.filenames) > 0: - files = args.filenames - else: - for root, dirs, walkfiles in os.walk(args.rootdir): - # don't visit certain dirs. This is just a performance improvement - # as we would prune these later in normalize_files(). But doing it - # cuts down the amount of filesystem walking we do and cuts down - # the size of the file list - for d in skipped_dirs: - if d in dirs: - dirs.remove(d) - - for name in walkfiles: - pathname = os.path.join(root, name) - files.append(pathname) - - files = normalize_files(files) - outfiles = [] - for pathname in files: - basename = os.path.basename(pathname) - extension = file_extension(pathname) - if extension in extensions or basename in extensions: - outfiles.append(pathname) - return outfiles - - -def get_dates(): - years = datetime.datetime.now().year - return '(%s)' % '|'.join((str(year) for year in range(2014, years+1))) - - -def get_regexs(): - regexs = {} - # Search for "YEAR" which exists in the boilerplate, but shouldn't in the real thing - regexs["year"] = re.compile('YEAR') - # get_dates return 2014, 2015, 2016, 2017, or 2018 until the current year as a regex like: "(2014|2015|2016|2017|2018)"; - # company holder names can be anything - regexs["date"] = re.compile(get_dates()) - # strip // +build \n\n build constraints - regexs["go_build_constraints"] = re.compile( - r"^(// \+build.*\n)+\n", re.MULTILINE) - # strip #!.* from scripts - regexs["shebang"] = re.compile(r"^(#!.*\n)\n*", re.MULTILINE) - # Search for generated files - regexs["generated"] = re.compile('DO NOT EDIT') - return regexs - - -def main(): - regexs = get_regexs() - refs = get_refs() - filenames = get_files(refs.keys()) - - for filename in filenames: - if not file_passes(filename, refs, regexs): - print(filename, file=sys.stdout) - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/hack/boilerplate/boilerplate.sh.txt b/hack/boilerplate/boilerplate.sh.txt deleted file mode 100644 index 3dca2c5b6e..0000000000 --- a/hack/boilerplate/boilerplate.sh.txt +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright YEAR Chaos Mesh Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# See the License for the specific language governing permissions and -# limitations under the License. diff --git a/hack/download-image.sh b/hack/download-image.sh new file mode 100755 index 0000000000..fae4e7ebd7 --- /dev/null +++ b/hack/download-image.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This script should work with the github action in `.github/workflows/upload_image_pr.yml` + +set -e + +function usage() { + cat <<'EOF' +This command downloads and imports the chaos-mesh image from the github artifacts + +Usage: hack/download-image.sh + + -h show this message and exit + -r the github repository which running the github actions + -i download the artifact related with this action run id + +EOF +} + +function download_image() { + local github_repository=$1 + local github_run_id=$2 + + mkdir -p .cache/ + + local ARTIFACT_URL=$(curl \ + -H "Accept: application/vnd.github.v3+json" \ + https://api.github.com/repos/"$github_repository"/actions/runs/"$github_run_id"/artifacts 2>/dev/null |\ + jq -r ".artifacts[0].archive_download_url") + local TOKEN=$(echo url=https://github.com/"$github_repository"|\ + gh auth git-credential get|\ + grep password|\ + cut -b 10-) + + curl -L \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: token $TOKEN" \ + "$ARTIFACT_URL" > .cache/chaos-mesh-images.zip + unzip -o -d .cache/ .cache/chaos-mesh-images.zip + + for IMAGE in "chaos-mesh" "chaos-daemon" "chaos-dashboard" + do + docker image import .cache/$IMAGE.tar ghcr.io/chaos-mesh/$IMAGE:latest &>/dev/null + echo "Image ghcr.io/chaos-mesh/$IMAGE:latest loaded" + done +} + +function check_executable_exists() { + while [[ $# -gt 0 ]]; do + local executable=$1 + if ! command -v "$executable" >/dev/null 2>&1; then + echo "Error: $executable is not installed" + exit 1 + fi + + shift + done +} + +GITHUB_REPOSITORY="" +GITHUB_ACTION_ID="" + +if [ $# -eq 0 ] + then + usage + exit 1 +fi + +check_executable_exists gh jq unzip curl + +while [[ $# -gt 0 ]]; do + case $1 in + -r) + GITHUB_REPOSITORY=$2 + shift 2 + ;; + -i) + GITHUB_ACTION_ID=$2 + shift 2 + ;; + -h) + usage + exit 0 + ;; + *) + echo "unknown flag or option $1" + usage + exit 1 + ;; + esac +done + +download_image "$GITHUB_REPOSITORY $GITHUB_ACTION_ID" diff --git a/hack/e2e.sh b/hack/e2e.sh index 179b3e1788..f3d7c0024d 100755 --- a/hack/e2e.sh +++ b/hack/e2e.sh @@ -1,17 +1,18 @@ #!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. +# Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# # # E2E entrypoint script. @@ -22,7 +23,7 @@ set -o nounset set -o pipefail ROOT=$(unset CDPATH && cd $(dirname "${BASH_SOURCE[0]}")/.. && pwd) -cd $ROOT +cd "$ROOT" source "${ROOT}/hack/lib.sh" @@ -33,7 +34,7 @@ Usage: hack/e2e.sh [-h] -- [extra test args] -h show this message and exit Environments: PROVIDER Kubernetes provider, e.g. kind, gke, eks, defaults: kind - DOCKER_REGISTRY image docker registry + IMAGE_REGISTRY image docker registry IMAGE_TAG image tag SKIP_BUILD skip building binaries SKIP_IMAGE_BUILD skip build and push images @@ -91,7 +92,7 @@ hack::ensure_kubetest2 echo "ensured kubetest2" PROVIDER=${PROVIDER:-kind} -DOCKER_REGISTRY=${DOCKER_REGISTRY:-localhost:5000} +IMAGE_REGISTRY=${IMAGE_REGISTRY:-ghcr.io} IMAGE_TAG=${IMAGE_TAG:-latest} CLUSTER=${CLUSTER:-chaos-mesh} KUBECONFIG=${KUBECONFIG:-~/.kube/config} @@ -102,7 +103,7 @@ SKIP_DOWN=${SKIP_DOWN:-} SKIP_DUMP=${SKIP_DUMP:-} SKIP_TEST=${SKIP_TEST:-} KIND_DATA_HOSTPATH=${KIND_DATA_HOSTPATH:-none} -KUBE_VERSION=${KUBE_VERSION:-v1.12.10} +KUBE_VERSION=${KUBE_VERSION:-v1.20.7} KUBE_WORKERS=${KUBE_WORKERS:-3} DOCKER_IO_MIRROR=${DOCKER_IO_MIRROR:-} GCR_IO_MIRROR=${GCR_IO_MIRROR:-} @@ -111,7 +112,7 @@ RUNNER_SUITE_NAME=${RUNNER_SUITE_NAME:-} ARTIFACTS=${ARTIFACTS:-} echo "PROVIDER: $PROVIDER" -echo "DOCKER_REGISTRY: $DOCKER_REGISTRY" +echo "IMAGE_REGISTRY: $IMAGE_REGISTRY" echo "IMAGE_TAG: $IMAGE_TAG" echo "CLUSTER: $CLUSTER" echo "KUBECONFIG: $KUBECONFIG" @@ -128,17 +129,19 @@ echo "QUAY_IO_MIRROR: $QUAY_IO_MIRROR" echo "ARTIFACTS: $ARTIFACTS" echo "KUBE_WORKERS: $KUBE_WORKERS" -# https://github.com/kubernetes-sigs/kind/releases/tag/v0.8.1 +# https://github.com/kubernetes-sigs/kind/releases/tag/v0.11.1 declare -A kind_node_images kind_node_images["v1.11.10"]="kindest/node:v1.11.10@sha256:74c8740710649a3abb169e7f348312deff88fc97d74cfb874c5095ab3866bb42" kind_node_images["v1.12.10"]="kindest/node:v1.12.10@sha256:faeb82453af2f9373447bb63f50bae02b8020968e0889c7fa308e19b348916cb" kind_node_images["v1.13.12"]="kindest/node:v1.13.12@sha256:214476f1514e47fe3f6f54d0f9e24cfb1e4cda449529791286c7161b7f9c08e7" -kind_node_images["v1.14.10"]="kindest/node:v1.14.10@sha256:6cd43ff41ae9f02bb46c8f455d5323819aec858b99534a290517ebc181b443c6" -kind_node_images["v1.15.11"]="kindest/node:v1.15.11@sha256:6cc31f3533deb138792db2c7d1ffc36f7456a06f1db5556ad3b6927641016f50" -kind_node_images["v1.16.9"]="kindest/node:v1.16.9@sha256:7175872357bc85847ec4b1aba46ed1d12fa054c83ac7a8a11f5c268957fd5765" -kind_node_images["v1.17.5"]="kindest/node:v1.17.5@sha256:ab3f9e6ec5ad8840eeb1f76c89bb7948c77bbf76bcebe1a8b59790b8ae9a283a" -kind_node_images["v1.18.2"]="kindest/node:v1.18.2@sha256:7b27a6d0f2517ff88ba444025beae41491b016bc6af573ba467b70c5e8e0d85f" -kind_node_images["v1.20.2"]="kindest/node:v1.20.2@sha256:8f7ea6e7642c0da54f04a7ee10431549c0257315b3a634f6ef2fecaaedb19bab" +# the following node images support amd64 and arm64 +kind_node_images["v1.14.10"]="kindest/node:v1.14.10@sha256:f8a66ef82822ab4f7569e91a5bccaf27bceee135c1457c512e54de8c6f7219f8" +kind_node_images["v1.15.12"]="kindest/node:v1.15.12@sha256:b920920e1eda689d9936dfcf7332701e80be12566999152626b2c9d730397a95" +kind_node_images["v1.16.15"]="kindest/node:v1.16.15@sha256:83067ed51bf2a3395b24687094e283a7c7c865ccc12a8b1d7aa673ba0c5e8861" +kind_node_images["v1.17.17"]="kindest/node:v1.17.17@sha256:66f1d0d91a88b8a001811e2f1054af60eef3b669a9a74f9b6db871f2f1eeed00" +kind_node_images["v1.18.19"]="kindest/node:v1.18.19@sha256:7af1492e19b3192a79f606e43c35fb741e520d195f96399284515f077b3b622c" +kind_node_images["v1.20.7"]="kindest/node:v1.20.7@sha256:cbeaf907fc78ac97ce7b625e4bf0de16e3ea725daf6b04f930bd14c67c671ff9" +kind_node_images["v1.22.1"]="kindest/node:v1.22.1@sha256:100b3558428386d1372591f8d62add85b900538d94db8e455b66ebaf05a3ca3a" function e2e::image_build() { if [ -n "$SKIP_BUILD" ]; then @@ -149,15 +152,15 @@ function e2e::image_build() { echo "info: skip building and pushing images" return fi - DOCKER_REGISTRY=${DOCKER_REGISTRY} GOOS=linux GOARCH=amd64 make image-chaos-mesh-e2e - DOCKER_REGISTRY=${DOCKER_REGISTRY} make image-chaos-mesh - DOCKER_REGISTRY=${DOCKER_REGISTRY} make image-chaos-daemon - DOCKER_REGISTRY=${DOCKER_REGISTRY} make image-e2e-helper + IMAGE_REGISTRY=${IMAGE_REGISTRY} GOOS=linux GOARCH=amd64 make image-chaos-mesh-e2e + IMAGE_REGISTRY=${IMAGE_REGISTRY} make image-chaos-mesh + IMAGE_REGISTRY=${IMAGE_REGISTRY} make image-chaos-daemon + IMAGE_REGISTRY=${IMAGE_REGISTRY} make image-e2e-helper } function e2e::create_kindconfig() { local tmpfile=${1} - cat < $tmpfile + cat < "$tmpfile" kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 kubeadmConfigPatches: @@ -197,31 +200,31 @@ kubeadmConfigPatches: v: "4" EOF if [ -n "$DOCKER_IO_MIRROR" -o -n "$GCR_IO_MIRROR" -o -n "$QUAY_IO_MIRROR" ]; then -cat <> $tmpfile +cat <> "$tmpfile" containerdConfigPatches: - |- EOF if [ -n "$DOCKER_IO_MIRROR" ]; then -cat <> $tmpfile +cat <> "$tmpfile" [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] endpoint = ["$DOCKER_IO_MIRROR"] EOF fi if [ -n "$GCR_IO_MIRROR" ]; then -cat <> $tmpfile +cat <> "$tmpfile" [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"] endpoint = ["$GCR_IO_MIRROR"] EOF fi if [ -n "$QUAY_IO_MIRROR" ]; then -cat <> $tmpfile +cat <> "$tmpfile" [plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"] endpoint = ["$QUAY_IO_MIRROR"] EOF fi fi # control-plane - cat <> $tmpfile + cat <> "$tmpfile" nodes: - role: control-plane EOF @@ -231,8 +234,8 @@ EOF exit 1 fi local hostWorkerPath="${KIND_DATA_HOSTPATH}/control-plane" - test -d $hostWorkerPath || mkdir $hostWorkerPath - cat <> $tmpfile + test -d "$hostWorkerPath" || mkdir "$hostWorkerPath" + cat <> "$tmpfile" extraMounts: - containerPath: /mnt/disks/ hostPath: "$hostWorkerPath" @@ -240,8 +243,8 @@ EOF EOF fi # workers - for ((i = 1; i <= $KUBE_WORKERS; i++)) { - cat <> $tmpfile + for ((i = 1; i <= "$KUBE_WORKERS"; i++)) { + cat <> "$tmpfile" - role: worker EOF if [[ "$KIND_DATA_HOSTPATH" != "none" ]]; then @@ -251,7 +254,7 @@ EOF fi local hostWorkerPath="${KIND_DATA_HOSTPATH}/worker${i}" test -d $hostWorkerPath || mkdir $hostWorkerPath - cat <> $tmpfile + cat <> "$tmpfile" extraMounts: - containerPath: /mnt/disks/ hostPath: "$hostWorkerPath" @@ -264,7 +267,7 @@ EOF e2e::image_build kubetest2_args=( - $PROVIDER + "$PROVIDER" ) if [ -n "$RUNNER_SUITE_NAME" ]; then @@ -288,9 +291,9 @@ fi if [ "$PROVIDER" == "kind" ]; then tmpfile=$(mktemp) trap "test -f $tmpfile && rm $tmpfile" EXIT - e2e::create_kindconfig $tmpfile + e2e::create_kindconfig "$tmpfile" echo "info: print the contents of kindconfig" - cat $tmpfile + cat "$tmpfile" image="" for v in ${!kind_node_images[*]}; do if [[ "$KUBE_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ && "$KUBE_VERSION" == "$v" ]]; then @@ -305,7 +308,7 @@ if [ "$PROVIDER" == "kind" ]; then echo "error: no image for $KUBE_VERSION, exit" exit 1 fi - kubetest2_args+=(--image-name $image) + kubetest2_args+=(--image-name "$image") kubetest2_args+=( # add some retires because kind may fail to start the cluster when the # load is high @@ -319,8 +322,7 @@ fi export PROVIDER export CLUSTER export KUBECONFIG -export E2E_IMAGE=${DOCKER_REGISTRY}/pingcap/chaos-mesh-e2e:${IMAGE_TAG} -export DOCKER_REGISTRY=${DOCKER_REGISTRY} +export IMAGE_REGISTRY=${IMAGE_REGISTRY} export IMAGE_TAG=${IMAGE_TAG} export PATH=$OUTPUT_BIN:$PATH @@ -328,9 +330,9 @@ if [ -n "${ARTIFACTS}" ]; then export REPORT_DIR=${ARTIFACTS} fi -if [ -n "${ARTIFACTS}" -a -z "$SKIP_DUMP" ]; then +if [ -n "${ARTIFACTS}" ] && [ -z "$SKIP_DUMP" ]; then kubetest2_args+=(--dump) fi -echo "info: run 'kubetest2 ${kubetest2_args[@]} -- hack/run-e2e.sh $@'" +echo "info: run kubetest2" "${kubetest2_args[@]}" " -- hack/run-e2e.sh $*" $KUBETSTS2_BIN ${kubetest2_args[@]} -- hack/run-e2e.sh "$@" diff --git a/hack/embed_ui_assets.sh b/hack/embed_ui_assets.sh index 988fc64ddf..21cfa62d13 100755 --- a/hack/embed_ui_assets.sh +++ b/hack/embed_ui_assets.sh @@ -1,27 +1,18 @@ #!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. +# Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - -# This script embeds UI assets into Golang source file. UI assets must be already built -# before calling this script. -# -# Available flags: # -# NO_ASSET_BUILD_TAG=1 -# No build tags will be included in the generated source code. -# ASSET_BUILD_TAG=X -# Customize the build tag of the generated source code. If unspecified, build tag will be "ui_server". set -euo pipefail @@ -36,25 +27,19 @@ export GOBIN=$PROJECT_DIR/bin export PATH=$GOBIN:$PATH echo "+ Preflight check" -if [ ! -d "ui/build" ]; then +if [ ! -d "ui/app/build" ]; then echo " - Error: UI assets must be built first" exit 1 fi -if [ "${NO_ASSET_BUILD_TAG:-}" = "1" ]; then - BUILD_TAG_PARAMETER="" -else - BUILD_TAG_PARAMETER=${ASSET_BUILD_TAG:-ui_server} -fi - echo "+ Embed UI assets" # OSX related -DS_Store=ui/build/.DS_Store +DS_Store=ui/app/build/.DS_Store [ -f $DS_Store ] && rm $DS_Store -go run tools/assets_generate/main.go $BUILD_TAG_PARAMETER +go run tools/assets_generate/main.go ui_server -HANDLER_PATH=pkg/uiserver/embedded_assets_handler.go +HANDLER_PATH=pkg/dashboard/uiserver/embedded_assets_handler.go mv assets_vfsdata.go $HANDLER_PATH echo " - Assets handler written to $HANDLER_PATH" diff --git a/hack/env-image-tag.sh b/hack/env-image-tag.sh new file mode 100755 index 0000000000..748e44898c --- /dev/null +++ b/hack/env-image-tag.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This script would report the tag of build-env and dev-env to use based on configuration file env-images.yaml. +# +# Usage: +# On master branch: +# ./hack/env-image-tag.sh build-env, output: latest +# ./hack/env-image-tag.sh dev-env, output: latest +# On release-2.1 branch: +# ./hack/env-image-tag.sh build-env, output: release-2.1 +# ./hack/env-image-tag.sh dev-env, output: release-2.1 + +set -euo pipefail + +DIR="$( cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd )" +PROJECT_DIR="$(dirname "$DIR")" + +if [[ "$#" == "0" ]]; then + echo "Usage: $0 " + exit 0 +fi + +if [[ "$1" == "dev-env" || "$1" == "build-env" ]]; then + docker run -i --rm mikefarah/yq:4.24.5 ".$1.tag" < "$PROJECT_DIR"/env-images.yaml + exit 0 +fi + +echo "Error: $1 is not a valid env-image name, available: dev-env, build-env" +exit 1 diff --git a/hack/generate_swagger_spec.sh b/hack/generate_swagger_spec.sh index 7ff55cdd01..a89d5d60b9 100755 --- a/hack/generate_swagger_spec.sh +++ b/hack/generate_swagger_spec.sh @@ -1,37 +1,35 @@ #!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. +# Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# -# This script generates API client from the swagger annotation in the Golang server code. +# This script call swag converts Go annotations to Swagger Documentation. +# +# See https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module set -euo pipefail DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" PROJECT_DIR="$(dirname "$DIR")" -# See https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module - cd $PROJECT_DIR export GOBIN=$PROJECT_DIR/bin export PATH=$GOBIN:$PATH -echo "+ Install swagger tools" -go install github.com/swaggo/swag/cmd/swag - -echo "+ Clean up go mod" -go mod tidy +echo "+ Install swaggo/swag" +go install github.com/swaggo/swag/cmd/swag@v1.8.7 echo "+ Generate swagger spec" -swag init -g cmd/chaos-dashboard/main.go +swag init -g cmd/chaos-dashboard/main.go --output pkg/dashboard/swaggerdocs --pd --parseInternal diff --git a/hack/kind-cluster-build.sh b/hack/kind-cluster-build.sh index 4aa465c3bb..634c1982d0 100755 --- a/hack/kind-cluster-build.sh +++ b/hack/kind-cluster-build.sh @@ -1,17 +1,18 @@ #!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. +# Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# set -e @@ -28,12 +29,12 @@ Options: -h,--help prints the usage message -n,--name name of the Kubernetes cluster, default value: kind -c,--nodeNum the count of the cluster nodes, default value: 3 - -k,--k8sVersion version of the Kubernetes cluster, default value: v1.15.6 + -k,--k8sVersion version of the Kubernetes cluster, default value: v1.20.7 -v,--volumeNum the volumes number of each kubernetes node, default value: 5 -r,--registryName the name of local docker registry, default value: registry -p,--registryPort the published port of local docker registry, default value: 5000 Usage: - $0 --name testCluster --nodeNum 4 --k8sVersion v1.15.6 + $0 --name testCluster --nodeNum 4 --k8sVersion v1.20.7 EOF } @@ -86,7 +87,7 @@ done clusterName=${clusterName:-kind} nodeNum=${nodeNum:-3} -k8sVersion=${k8sVersion:-v1.20.2} +k8sVersion=${k8sVersion:-v1.20.7} volumeNum=${volumeNum:-5} registryName=${registryName:-registry} registryPort=${registryPort:-5000} @@ -151,14 +152,14 @@ nodes: - role: control-plane EOF -for ((i=0;i<${nodeNum};i++)) +for ((i=0;i> ${configFile} - role: worker extraMounts: EOF - for ((k=1;k<=${volumeNum};k++)) + for ((k=1;k<=volumeNum;k++)) do mkdir -p ${data_dir}/worker${i}/vol${k} cat <> ${configFile} @@ -189,14 +190,14 @@ set -e ${KUBECTL_BIN} apply -f ${ROOT}/manifests/local-volume-provisioner.yaml -$KUBECTL_BIN create ns chaos-testing +$KUBECTL_BIN create ns chaos-mesh echo "############# success create cluster:[${clusterName}] #############" echo "To start using your cluster, run:" echo " export KUBECONFIG=${kubeconfigPath}" echo "" -echo < #include #include @@ -11,9 +27,8 @@ int main(int argc, char* argv[]) { pause(); int ret = execvp(argv[1], &argv[1]); - if (ret == -1) { + if (ret != 0) { fprintf(stderr, "%s", strerror(errno)); - return -1; } - return 0; + return ret; } diff --git a/hack/prepare-e2e.sh b/hack/prepare-e2e.sh index 02d62c4c30..befeb15d99 100755 --- a/hack/prepare-e2e.sh +++ b/hack/prepare-e2e.sh @@ -1,17 +1,18 @@ #!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. +# Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# # # This script runs before all e2e jobs to prepare shared files. diff --git a/hack/protoc/Dockerfile b/hack/protoc/Dockerfile deleted file mode 100644 index 20a795575e..0000000000 --- a/hack/protoc/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM golang:1.14.4-alpine3.12 - -ARG HTTPS_PROXY -ARG HTTP_PROXY - -ENV GO111MODULE on -ENV PROTOC_VERSION 3.12.3 - -RUN apk add --no-cache wget unzip protoc protobuf-dev make bash - -RUN go get github.com/golang/protobuf/protoc-gen-go@v1.2.0 - -RUN mkdir /.cache -RUN chmod -R 777 /.cache diff --git a/hack/run-e2e.sh b/hack/run-e2e.sh index e4ce3a8336..93f8ecefce 100755 --- a/hack/run-e2e.sh +++ b/hack/run-e2e.sh @@ -1,17 +1,18 @@ #!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. +# Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# set -o errexit set -o nounset @@ -30,7 +31,7 @@ hack::ensure_kind PROVIDER=${PROVIDER:-} CLUSTER=${CLUSTER:-} IMAGE_TAG=${IMAGE_TAG:-} -E2E_IMAGE=${E2E_IMAGE:-localhost:5000/pingcap/chaos-mesh-e2e:latest} +E2E_IMAGE=${E2E_IMAGE:-ghcr.io/chaos-mesh/chaos-mesh-e2e:latest} KUBECONFIG=${KUBECONFIG:-$HOME/.kube/config} KUBECONTEXT=${KUBECONTEXT:-kind-chaos-mesh} REPORT_DIR=${REPORT_DIR:-} @@ -42,10 +43,10 @@ GINKGO_PARALLEL=${GINKGO_PARALLEL:-n} # set to 'y' to run tests in parallel GINKGO_NO_COLOR=${GINKGO_NO_COLOR:-n} GINKGO_STREAM=${GINKGO_STREAM:-y} SKIP_GINKGO=${SKIP_GINKGO:-} -# We don't delete namespace on failure by default for easier debugging in local development. +# We don't finalizers namespace on failure by default for easier debugging in local development. # TODO support this feature DELETE_NAMESPACE_ON_FAILURE=${DELETE_NAMESPACE_ON_FAILURE:-false} -DOCKER_REGISTRY=${DOCKER_REGISTRY:-localhost:5000} +IMAGE_REGISTRY=${IMAGE_REGISTRY:-ghcr.io} if [ -z "$KUBECONFIG" ]; then echo "error: KUBECONFIG is required" @@ -61,32 +62,32 @@ echo "KUBECONTEXT: $KUBECONTEXT" echo "REPORT_DIR: $REPORT_DIR" echo "REPORT_PREFIX: $REPORT_PREFIX" echo "DELETE_NAMESPACE_ON_FAILURE: $DELETE_NAMESPACE_ON_FAILURE" -echo "DOCKER_REGISTRY: $DOCKER_REGISTRY" +echo "IMAGE_REGISTRY: $IMAGE_REGISTRY" function e2e::image_load() { local images=( - pingcap/chaos-mesh - pingcap/chaos-daemon - pingcap/e2e-helper + chaos-mesh/chaos-mesh + chaos-mesh/chaos-daemon + chaos-mesh/e2e-helper ) if [ "$PROVIDER" == "kind" ]; then local nodes=$($KIND_BIN get nodes --name $CLUSTER | grep -v 'control-plane$') echo $nodes - echo "info: load images ${images[@]}" + echo "info: load images" "${images[@]}" for image in ${images[@]}; do - $KIND_BIN load docker-image --name $CLUSTER ${DOCKER_REGISTRY}/$image:$IMAGE_TAG --nodes $(hack::join ',' ${nodes[@]}) + $KIND_BIN load docker-image --name $CLUSTER ${IMAGE_REGISTRY}/$image:$IMAGE_TAG --nodes $(hack::join ',' ${nodes[@]}) done # bypassing docker pull rate limit inner the kind container: kindest/node has no credentials - # pingcap/coredns:latest, nginx:latest and gcr.io/google-containers/pause:latest is required for test + # ghcr.io/chaos-mesh/chaos-coredns:v0.2.6, nginx:latest and gcr.io/google-containers/pause:latest is required for test # we suppose that you could pull this image on your host docker - echo "info: load images pingcap/coredns:latest, nginx:latest and gcr.io/google-containers/pause:latest" - docker pull pingcap/coredns:v0.2.0 + echo "info: load images ghcr.io/chaos-mesh/chaos-coredns:v0.2.6, nginx:latest and gcr.io/google-containers/pause:latest" + docker pull ghcr.io/chaos-mesh/chaos-coredns:v0.2.6 docker pull nginx:latest docker pull gcr.io/google-containers/pause:latest - $KIND_BIN load docker-image --name $CLUSTER pingcap/coredns:v0.2.0 --nodes $(hack::join ',' ${nodes[@]}) - $KIND_BIN load docker-image --name $CLUSTER nginx:latest --nodes $(hack::join ',' ${nodes[@]}) - $KIND_BIN load docker-image --name $CLUSTER gcr.io/google-containers/pause:latest --nodes $(hack::join ',' ${nodes[@]}) + $KIND_BIN load docker-image --name "$CLUSTER" ghcr.io/chaos-mesh/chaos-coredns:v0.2.6 --nodes "$(hack::join ',' ${nodes[@]})" + $KIND_BIN load docker-image --name "$CLUSTER" nginx:latest --nodes "$(hack::join ',' ${nodes[@]})" + $KIND_BIN load docker-image --name "$CLUSTER" gcr.io/google-containers/pause:latest --nodes "$(hack::join ',' ${nodes[@]})" fi } @@ -136,11 +137,13 @@ e2e_args=( ${ginkgo_args[@]:-} /usr/local/bin/e2e.test -- - --manager-image="${DOCKER_REGISTRY}/pingcap/chaos-mesh" + --manager-image-registry="${IMAGE_REGISTRY}" + --manager-image="chaos-mesh/chaos-mesh" --manager-image-tag="${IMAGE_TAG}" - --daemon-image="${DOCKER_REGISTRY}/pingcap/chaos-daemon" + --daemon-image-registry="${IMAGE_REGISTRY}" + --daemon-image="chaos-mesh/chaos-daemon" --daemon-image-tag="${IMAGE_TAG}" - --e2e-image="${DOCKER_REGISTRY}/pingcap/e2e-helper:${IMAGE_TAG}" + --e2e-image="${IMAGE_REGISTRY}/chaos-mesh/e2e-helper:${IMAGE_TAG}" --install-chaos-mesh ) @@ -159,11 +162,11 @@ docker_args=( --net=host --privileged -v /:/rootfs - -v $ROOT:$ROOT - -w $ROOT - -v $KUBECONFIG:/etc/kubernetes/admin.conf:ro + -v "$ROOT":"$ROOT" + -w "$ROOT" + -v "$KUBECONFIG":/etc/kubernetes/admin.conf:ro --env KUBECONFIG=/etc/kubernetes/admin.conf - --env KUBECONTEXT=$KUBECONTEXT + --env KUBECONTEXT="$KUBECONTEXT" ) if [ -n "$REPORT_DIR" ]; then @@ -172,9 +175,9 @@ if [ -n "$REPORT_DIR" ]; then --report-prefix="${REPORT_PREFIX}" ) docker_args+=( - -v $REPORT_DIR:$REPORT_DIR + -v "$REPORT_DIR":"$REPORT_DIR" ) fi -echo "info: docker ${docker_args[@]} $E2E_IMAGE ${e2e_args[@]}" +echo "info: docker" "${docker_args[@]}" $E2E_IMAGE "${e2e_args[@]}" docker ${docker_args[@]} $E2E_IMAGE ${e2e_args[@]} diff --git a/hack/update-kubernetes-library.sh b/hack/update-kubernetes-library.sh new file mode 100644 index 0000000000..4b39dc5f17 --- /dev/null +++ b/hack/update-kubernetes-library.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +set -euo pipefail + +VERSION=${1#"v"} +if [ -z "$VERSION" ]; then + echo "Must specify version!" + exit 1 +fi +MODS=($( + curl -sS https://raw.githubusercontent.com/kubernetes/kubernetes/v${VERSION}/go.mod | + sed -n 's|.*k8s.io/\(.*\) => ./staging/src/k8s.io/.*|k8s.io/\1|p' +)) +for MOD in "${MODS[@]}"; do + V=$( + go mod download -json "${MOD}@kubernetes-${VERSION}" | + sed -n 's|.*"Version": "\(.*\)".*|\1|p' + ) + go mod edit "-replace=${MOD}=${MOD}@${V}" +done +go get "k8s.io/kubernetes@v${VERSION}" diff --git a/hack/update_install_script.sh b/hack/update_install_script.sh index a3f2a10417..ca4493ae6c 100755 --- a/hack/update_install_script.sh +++ b/hack/update_install_script.sh @@ -1,25 +1,29 @@ #!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. +# Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# tmp_file="chaos-mesh.yaml" tmp_install_script="install.sh.bak" install_script="install.sh" -helm template chaos-mesh helm/chaos-mesh --namespace=chaos-testing \ - --set controllerManager.hostNetwork=true,chaosDaemon.hostNetwork=true,dashboard.securityMode=false \ - > ${tmp_file} +helm template chaos-mesh helm/chaos-mesh --namespace=chaos-mesh \ + --set controllerManager.hostNetwork=true \ + --set controllerManager.chaosdSecurityMode=false \ + --set chaosDaemon.hostNetwork=true \ + --set chaosDaemon.mtls.enabled=false \ + --set dashboard.securityMode=false > ${tmp_file} sed -i.bak '/helm/d' $tmp_file sed -i.bak '/Helm/d' $tmp_file @@ -28,14 +32,16 @@ sed -i.bak 's/ca.crt:.*/ca.crt: \"\$\{CA_BUNDLE\}\"/g' $tmp_file sed -i.bak 's/tls.crt:.*/tls.crt: \"\$\{TLS_CRT\}\"/g' $tmp_file sed -i.bak 's/tls.key:.*/tls.key: \"\$\{TLS_KEY\}\"/g' $tmp_file sed -i.bak 's/caBundle:.*/caBundle: \"\$\{CA_BUNDLE\}\"/g' $tmp_file -sed -i.bak 's/mountPath: \/var\/run\/docker.sock/mountPath: \$\{mountPath\}/g' $tmp_file -sed -i.bak 's/path: \/var\/run\/docker.sock/path: \$\{socketPath\}/g' $tmp_file +sed -i.bak 's/\/host-run\/docker.sock/\/host-run\/$\{socketName\}/g' $tmp_file +sed -i.bak 's/path: \/var\/run/path: \$\{socketDir\}/g' $tmp_file sed -i.bak 's/- docker/- $\{runtime\}/g' $tmp_file sed -i.bak 's/hostNetwork: true/hostNetwork: \$\{host_network\}/g' $tmp_file -sed -i.bak 's/pingcap\/chaos-mesh:.*/\${DOCKER_REGISTRY_PREFIX}\/pingcap\/chaos-mesh:\$\{VERSION_TAG\}/g' $tmp_file -sed -i.bak 's/pingcap\/chaos-daemon:.*/\${DOCKER_REGISTRY_PREFIX}\/pingcap\/chaos-daemon:\$\{VERSION_TAG\}/g' $tmp_file -sed -i.bak 's/pingcap\/chaos-dashboard:.*/\${DOCKER_REGISTRY_PREFIX}\/pingcap\/chaos-dashboard:\$\{VERSION_TAG\}/g' $tmp_file +sed -i.bak 's/ghcr.io\/chaos-mesh\/chaos-mesh:.*/\${IMAGE_REGISTRY_PREFIX}\/chaos-mesh\/chaos-mesh:\$\{VERSION_TAG\}/g' $tmp_file +sed -i.bak 's/ghcr.io\/chaos-mesh\/chaos-daemon:.*/\${IMAGE_REGISTRY_PREFIX}\/chaos-mesh\/chaos-daemon:\$\{VERSION_TAG\}/g' $tmp_file +sed -i.bak 's/ghcr.io\/chaos-mesh\/chaos-dashboard:.*/\${IMAGE_REGISTRY_PREFIX}\/chaos-mesh\/chaos-dashboard:\$\{VERSION_TAG\}/g' $tmp_file sed -i.bak 's/value: UTC/value: \$\{timezone\}/g' $tmp_file +sed -i.bak 's/app.kubernetes.io\/version: 0.0.0/app.kubernetes.io\/version: $\{VERSION_TAG##v\}/g' $tmp_file + mv $tmp_file $tmp_file.bak cat < $tmp_file @@ -43,7 +49,7 @@ cat < $tmp_file apiVersion: v1 kind: Namespace metadata: - name: chaos-testing + name: chaos-mesh EOF cat $tmp_file.bak >> $tmp_file diff --git a/hack/verify-boilerplate.sh b/hack/verify-boilerplate.sh deleted file mode 100755 index 1e74afdf6d..0000000000 --- a/hack/verify-boilerplate.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# See the License for the specific language governing permissions and -# limitations under the License. - -set -o errexit -set -o nounset -set -o pipefail - -ROOT=$(unset CDPATH && cd $(dirname "${BASH_SOURCE[0]}")/.. && pwd) -cd $ROOT - -boiler="${ROOT}/hack/boilerplate/boilerplate.py" - -# ignored files is a list of files we should ignore, e.g. k8s script. -# one file per line -ignored_files='./hack/cherry_pick_pull.sh -hack/generate-internal-groups.sh' - -files=($(find . -type f -not \( \ - -path './hack/boilerplate/*' \ - -o -path './.git/*' \ - -o -path './.*/*' \ - -o -path './vendor/*' \ - -o -path './ui/*' \ - -o -path '*/Makefile' \ - -o -path '*/Dockerfile' \ - -o -path './images/*' \ - -o -path './pkg/uiserver/embedded_assets_handler.go' \ - -o -path '*/pb/*' \ - -o -path '*/*.deepcopy.go' \ - \) | grep -v -F "$ignored_files" -)) - -files_need_boilerplate=() -while IFS=$'\n' read -r line; do - files_need_boilerplate+=( "$line" ) -done < <("${boiler}" "${files[@]}") - -# Run boilerplate check -if [[ ${#files_need_boilerplate[@]} -gt 0 ]]; then - for file in "${files_need_boilerplate[@]}"; do - echo "Boilerplate header is wrong for: ${file}" >&2 - done - exit 1 -fi diff --git a/hack/version.sh b/hack/version.sh index 3917ceb17b..b98fc8a019 100755 --- a/hack/version.sh +++ b/hack/version.sh @@ -1,26 +1,28 @@ #!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. +# Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# set -euo pipefail function chaos_mesh::version::get_version_vars() { if [[ -n ${GIT_COMMIT-} ]] || GIT_COMMIT=$(git rev-parse "HEAD^{commit}" 2>/dev/null); then # Use git describe to find the version based on tags. - if [[ -n ${GIT_VERSION-} ]] || GIT_VERSION=$(git describe --tags --abbrev=14 "${GIT_COMMIT}^{commit}" 2>/dev/null); then - DASHES_IN_VERSION=$(echo "${GIT_VERSION}" | sed "s/[^-]//g") - if [[ "${DASHES_IN_VERSION}" != "" ]] ; then + # --always would show the unique abbr commit as fallback. + if [[ -n ${GIT_VERSION-} ]] || GIT_VERSION=$(git describe --always --tags --abbrev=14 "${GIT_COMMIT}^{commit}" 2>/dev/null); then + # if current commit is not on a certain tag + if ! git describe --tags --exact-match >/dev/null 2>&1 ; then # GIT_VERSION=gitBranch-gitCommitHash IFS='-' read -ra GIT_ARRAY <<< "$GIT_VERSION" GIT_VERSION=$(git rev-parse --abbrev-ref HEAD)-${GIT_ARRAY[${#GIT_ARRAY[@]}-1]} diff --git a/helm/chaos-mesh/Chart.yaml b/helm/chaos-mesh/Chart.yaml index 9bae4de6d9..c7b3e7c79a 100644 --- a/helm/chaos-mesh/Chart.yaml +++ b/helm/chaos-mesh/Chart.yaml @@ -1,15 +1,51 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: v2 -appVersion: "v0.9.0" -description: Chaos Mesh® is a cloud-native Chaos Engineering platform that orchestrates chaos on Kubernetes environments. +appVersion: "0.0.0" +description: Chaos Mesh is a cloud-native Chaos Engineering platform that orchestrates chaos on Kubernetes environments. home: https://chaos-mesh.org -icon: https://raw.githubusercontent.com/pingcap/chaos-mesh/master/static/logo.svg +icon: https://raw.githubusercontent.com/chaos-mesh/chaos-mesh/master/static/logo.svg sources: - - https://github.com/pingcap/chaos-mesh + - https://github.com/chaos-mesh/chaos-mesh name: chaos-mesh -version: v0.2.0 +version: "0.0.0" keywords: - chaos-engineering - resiliency - fault-injection - kubernetes - testing +maintainers: + - name: cwen0 + email: cwen@pingcap.com + - name: YangKeao + email: yangkeao@chunibyo.icu + - name: dcalvin + email: wenghao@pingcap.com + - name: yeya24 + email: yb532204897@gmail.com + - name: Gallardot + email: tttick@gmail.com +annotations: + # Use this annotation to indicate that this chart version contains security updates, boolean string. + artifacthub.io/containsSecurityUpdates: "false" + # Use this annotation to indicate that your chart represents an operator, boolean string. + artifacthub.io/operator: "true" + # Use this annotation to indicate the capabilities of the operator your chart provides. It must be one of the following options: basic install, seamless upgrades, full lifecycle, deep insights or auto pilot. + artifacthub.io/operatorCapabilities: "Seamless Upgrades" + # Use this annotation to indicate that this chart version is a pre-release. + artifacthub.io/prerelease: "true" + # Use this annotation to indicate the chart’s license, string. + artifacthub.io/license: "Apache-2.0" diff --git a/helm/chaos-mesh/README.md b/helm/chaos-mesh/README.md index d1f991aeb1..3a3291a06f 100644 --- a/helm/chaos-mesh/README.md +++ b/helm/chaos-mesh/README.md @@ -8,109 +8,181 @@ This chart bootstraps a [Chaos Mesh](https://github.com/chaos-mesh/chaos-mesh) d ## Deploy -Before deploying Chaos Mesh, make sure you have installed the [Prerequisites](https://chaos-mesh.org/docs/user_guides/installation#prerequisites). And then follow the [install-by-helm](https://chaos-mesh.org/docs/user_guides/installation#install-by-helm) doc step by step. +Before deploying Chaos Mesh, make sure you have installed the [Prerequisites](https://chaos-mesh.org/docs/production-installation-using-helm#prerequisites). And then follow the [install-by-helm](https://chaos-mesh.org/docs/production-installation-using-helm#install-chaos-mesh-using-helm) doc step by step. ## Configuration The following tables list the configurable parameters of the Chaos Mesh chart and their default values. -| Parameter | Description | Default | -|--------------------------------------------|----------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------| +| Parameter | Description | Default | +| --- | --- | --- | | `nameOverride` | | `` | | `fullnameOverride` | | `` | -| `clusterScoped` | whether chaos-mesh should manage kubernetes cluster wide chaos.Also see rbac.create and controllerManager.serviceAccount | `true` | -| `rbac.create` | | `true` | +| `customLabels` | Customized labels that will be tagged on all the resources of Chaos Mesh | `{}` | +| `clusterScoped` | Whether chaos-mesh should manage kubernetes cluster wide chaos.Also see rbac.create and controllerManager.serviceAccount | `true` | +| `rbac.create` | Creating rbac API Objects. Also see clusterScoped and controllerManager.serviceAccount | `true` | | `timezone` | The timezone where controller-manager, chaos-daemon and dashboard uses. For example: `UTC`, `Asia/Shanghai` | `UTC` | -| `enableProfiling` | A flag to enable pprof in controller-manager and chaos-daemon | `true` | -| `controllerManager.hostNetwork` | running chaos-controller-manager on host network | `false` | +| `enableProfiling` | A flag to enable pprof in controller-manager and chaos-daemon | `true` | +| `enableCtrlServer` | A flag to enable ctrlserver which provides service to chaosctl in controller-manager. | `true` | +| `images.registry` | The global container registry for the images, you could replace it with your self-hosted container registry. | `ghcr.io` | +| `images.tag` | The global image tag (for example, semiVer with prefix v, or latest). | `latest` | +| `imagePullSecrets` | Global Docker registry secret names as an array | [] (does not add image pull secrets to deployed pods) | +| `controllerManager.securityContext` | Pod securityContext if needed | `{}` | +| `controllerManager.hostNetwork` | Running chaos-controller-manager on host network | `false` | | `controllerManager.allowHostNetworkTesting` | Allow testing on `hostNetwork` pods | `false` | | `controllerManager.serviceAccount` | The serviceAccount for chaos-controller-manager | `chaos-controller-manager` | +| `controllerManager.serviceAccountAnnotations` | ServiceAccount annotations for chaos-controller-manager | `{}` | +| `controllerManager.serviceAccountCreate` | Create the serviceAccount for chaos-controller-manager | `true` | | `controllerManager.priorityClassName` | Custom priorityClassName for using pod priorities | `` | -| `controllerManager.replicaCount` | Replicas for chaos-controller-manager | `1` | -| `controllerManager.image` | docker image for chaos-controller-manager | `pingcap/chaos-mesh:latest` | +| `controllerManager.replicaCount` | Replicas for chaos-controller-manager | `3` | +| `controllerManager.image.registry` | Override global registry, empty value means using the global images.registry | `` | +| `controllerManager.image.repository` | Repository part for image of chaos-controller-manager | `chaos-mesh/chaos-mesh` | +| `controllerManager.image.tag` | Override global tag, empty value means using the global images.tag | `` | | `controllerManager.imagePullPolicy` | Image pull policy | `Always` | -| `controllerManager.service.type` | Kubernetes Service type | `ClusterIP` | -| `controllerManager.resources` | CPU/Memory resource requests/limits for chaos-controller-manager pod | `requests: { cpu: "250m", memory: "512Mi" }, limits:{ cpu: "500m", memory: "1024Mi" }` | -| `controllerManager.nodeSelector` | Node labels for chaos-controller-manager pod assignment | `{}` | -| `controllerManager.tolerations` | Toleration labels for chaos-controller-manager pod assignment | `[]` | -| `controllerManager.affinity` | Map of chaos-controller-manager node/pod affinities | `{}` | -| `controllerManager.podAnnotations` | Pod annotations of chaos-controller-manager | `{}`| -| `controllerManager.enableFilterNamespace` | If enabled, only pods in the namespace annotated with `"chaos-mesh.org/inject": "enabled"` will be injected | false | -| `chaosDaemon.image` | docker image for chaos-daemon | `pingcap/chaos-mesh:latest` | -| `chaosDaemon.imagePullPolicy` | image pull policy | `Always` | +| `controllerManager.enableFilterNamespace` | If enabled, only pods in the namespace annotated with `"chaos-mesh.org/inject": "enabled"` could be injected | false | +| `controllerManager.service.type` | Kubernetes Service type for service chaos-controller-manager | `ClusterIP` | +| `controllerManager.resources` | CPU/Memory resource requests/limits for chaos-controller-manager pod | `{requests: { cpu: "25m", memory: "256Mi" }, limits:{}}` | +| `controllerManager.nodeSelector` | Node labels for chaos-controller-manager pod assignment | `{}` | +| `controllerManager.tolerations` | Toleration labels for chaos-controller-manager pod assignment | `[]` | +| `controllerManager.affinity` | Map of chaos-controller-manager node/pod affinities | `{}` | +| `controllerManager.podAnnotations` | Pod annotations of chaos-controller-manager | `{}` | +| `controllerManager.enabledControllers` | A list of controllers to enable. "\*" enables all controllers by default. | `["*"]` | +| `controllerManager.enabledWebhooks` | A list of webhooks to enable. "\*" enables all webhooks by default. | `["*"]` | +| `controllerManager.podChaos.podFailure.pauseImage` | Custom Pause Container Image for Pod Failure Chaos | `gcr.io/google-containers/pause:latest` | +| `controllerManager.leaderElection.enabled` | Enable leader election for controller manager. | `true` | +| `controllerManager.leaderElection.leaseDuration` | The duration that non-leader candidates will wait to force acquire leadership. This is measured against time of last observed ack. | `15s` | +| `controllerManager.leaderElection.renewDeadline` | The duration that the acting control-plane will retry refreshing leadership before giving up. | `10s` | +| `controllerManager.leaderElection.retryPeriod` | The duration the LeaderElector clients should wait between tries of actions. | `2s` | +| `controllerManager.chaosdSecurityMode` | Enabled for mTLS connection between chaos-controller-manager and chaosd | `true` | +| `chaosDaemon.image.registry` | Override global registry, empty value means using the global images.registry | `` | +| `chaosDaemon.image.repository` | Repository part for image of chaos-daemon | `chaos-mesh/chaos-daemon` | +| `chaosDaemon.image.tag` | Override global tag, empty value means using the global images.tag | `` | +| `chaosDaemon.imagePullPolicy` | Image pull policy | `Always` | | `chaosDaemon.grpcPort` | The port which grpc server listens on | `31767` | | `chaosDaemon.httpPort` | The port which http server listens on | `31766` | -| `chaosDaemon.env` | chaosDaemon envs | `{}` | -| `chaosDaemon.hostNetwork` | running chaosDaemon on host network | `false` | +| `chaosDaemon.env` | Extra chaosDaemon envs | `{}` | +| `chaosDaemon.securityContext` | Pod securityContext if needed | `{}`| +| `chaosDaemon.hostNetwork` | Running chaosDaemon on host network | `false` | +| `chaosDaemon.mtls.enabled` | Enable mtls on the grpc connection between chaos-controller-manager and chaos-daemon | `true` | | `chaosDaemon.privileged` | Run chaos-daemon container in privileged mode. If it is set to false, chaos-daemon will be run in some specified capabilities. capabilities: SYS_PTRACE, NET_ADMIN, MKNOD, SYS_CHROOT, SYS_ADMIN, KILL, IPC_LOCK | `true` | | `chaosDaemon.priorityClassName` | Custom priorityClassName for using pod priorities | `` | | `chaosDaemon.podAnnotations` | Pod annotations of chaos-daemon | `{}` | -| `chaosDaemon.runtime` | Runtime specifies which container runtime to use. Currently we only supports docker and containerd. | `docker` | -| `chaosDaemon.socketPath` | Specifies the container runtime socket | `/var/run/docker.sock` | +| `chaosDaemon.serviceAccount` | ServiceAccount name for chaos-daemon | `chaos-daemon` | +| `chaosDaemon.serviceAccountAnnotations` | ServiceAccount annotations for chaos-daemon | `{}` | +| `chaosDaemon.podSecurityPolicy` | Specify PodSecurityPolicy(psp) on chaos-daemon pods | `false`| +| `chaosDaemon.runtime` | Runtime specifies which container runtime to use. Currently we only supports docker, containerd and CRI-O. | `docker` | +| `chaosDaemon.socketPath` | Specifiesthe path of container runtime socket on the host. | `/var/run/docker.sock` | +| `chaosDaemon.resources` | CPU/Memory resource requests/limits for chaosDaemon container | `{}` | +| `chaosDaemon.nodeSelector` | Node labels for chaos-daemon pod assignment | `{}` | | `chaosDaemon.tolerations` | Toleration labels for chaos-daemon pod assignment | `[]` | -| `chaosDaemon.resources` | CPU/Memory resource requests/limits for chaosDaemon container | `requests: { cpu: "250m", memory: "512Mi" }, limits:{ cpu: "500m", memory: "1024Mi" }` | -| `bpfki.create` | Enable chaos-kernel | `false` | -| `bpfki.image` | Docker image for chaos-kernel | `pingcap/chaos-kernel:latest` | -| `bpfki.imagePullPolicy` | Image pull policy | `Always` | -| `bpfki.grpcPort` | The port which grpc server listens on | `50051` | -| `bpfki.resources` | CPU/Memory resource requests/limits for chaos-kernel container | `requests: { cpu: "250m", memory: "512Mi" }, limits:{ cpu: "500m", memory: "1024Mi" }` | -| `dashboard.create` | Enable chaos-dashboard | `false` | -| `dashboard.serviceAccount` | The serviceAccount for chaos-dashboard | `chaos-dashboard` | +| `chaosDaemon.affinity` | Map of chaos-daemon node/pod affinities | `{}` | +| `chaosDaemon.updateStrategy` | Specify DaemonSetUpdateStrategy for chaos-daemon | `{}` | +| `chaosDaemon.service.scrape.enabled` | Enable metric scraping from Promethues by annotations | `true` | +| `dashboard.create` | Enable chaos-dashboard | `true` | +| `dashboard.databaseSecretName` | Optional, the secret name that has `DATABASE_DATASOURCE` defined | `` | +| `dashboard.rootUrl` | Specify the base url for openid/oauth2 (like GCP Auth Integration) callback URL. | `http://localhost:2333` | +| `dashboard.securityContext` | Pod securityContext if needed | `{}` | +| `dashboard.hostNetwork` | Running chaos-dashboard on host network | `false` | +| `dashboard.replicaCount` | Replicas of chaos-dashboard | `1` | | `dashboard.priorityClassName` | Custom priorityClassName for using pod priorities | `` | -| `dashboard.image` | Docker image for chaos-dashboard | `pingcap/chaos-dashboard:latest` | +| `dashboard.serviceAccount` | The serviceAccount for chaos-dashboard | `chaos-dashboard` | +| `dashboard.image.registry` | Override global registry, empty value means using the global images.registry | `` | +| `dashboard.image.repository` | Repository part for image of chaos-dashboard | `chaos-mesh/chaos-dashboard` | +| `dashboard.image.tag` | Override global tag, empty value means using the global images.tag | `` | | `dashboard.imagePullPolicy` | Image pull policy | `Always` | -| `dashboard.nodeSelector` | Node labels for chaos-dashboard pod assignment | `{}` | +| `dashboard.securityMode` | Require user to provide credentials on Chaos Dashboard, instead of using chaos-dashboard service account | `true` | +| `dashboard.gcpSecurityMode` | Enable GCP Authentication Integration, see: for more details | `false` | +| `dashboard.gcpClientId` | GCP app's client ID with GCP Authentication Integration | `` | +| `dashboard.gcpClientSecret` | GCP app's client secret with GCP Authentication Integration | `` | +| `dashboard.nodeSelector` | Node labels for chaos-dashboard pod assignment | `{}` | | `dashboard.tolerations` | Toleration labels for chaos-dashboard pod assignment | `[]` | | `dashboard.affinity` | Map of chaos-dashboard node/pod affinities | `{}` | | `dashboard.podAnnotations` | Deployment chaos-dashboard annotations | `{}` | -| `dashboard.resources` | CPU/Memory resource requests/limits for chaos-dashboard pod | `requests: { cpu: "250m", memory: "512Mi" }, limits:{ cpu: "500m", memory: "1024Mi" }` | -| `dashboard.persistentVolume.enable` | Enable storage volume for chaos-dashboard. If you are using SQLite as your DB for Chaos Dashboard, it is recommended to enable persistence| `false` | -| `dashboard.persistentVolume.existingClaim` | Use the existing PVC for persisting chaos event| `` | +| `dashboard.service.annotations` | Service annotations for the dashboard | `{}` | +| `dashboard.service.type` | Service type of the service created for exposing the dashboard | `NodePort` | +| `dashboard.service.clusterIP` | Set the `clusterIP` of the dashboard service if the type is `ClusterIP` | `nil` | +| `dashboard.service.nodePort` | Set the `nodePort` of the dashboard service if the type is `NodePort` | `nil` | +| `dashboard.resources` | CPU/Memory resource requests/limits for chaos-dashboard pod | `requests: { cpu: "25m", memory: "256Mi" }, limits:{}` | +| `dashboard.persistentVolume.enabled` | Enable storage volume for chaos-dashboard. If you are using SQLite as your DB for Chaos Dashboard, it is recommended to enable persistence | `false` | +| `dashboard.persistentVolume.existingClaim` | Use the existing PVC for persisting chaos event | `` | | `dashboard.persistentVolume.size` | Chaos Dashboard data Persistent Volume size | `8Gi` | | `dashboard.persistentVolume.storageClassName` | Chaos Dashboard data Persistent Volume Storage Class | `standard` | | `dashboard.persistentVolume.mountPath` | Chaos Dashboard data Persistent Volume mount root path | `/data` | -| `dashboard.persistentVolume.subPath` | Subdirectory of Chaos Dashboard data Persistent Volume to mount | `` | -| `dashboard.service.annotations` | Service annotations for the dashboard | `{}` | -| `dashboard.service.type` | Service type of the service created for exposing the dashboard | `NodePort` | -| `dashboard.service.clusterIP` | Set the `clusterIP` of the dashboard service if the type is `ClusterIP` | `nil` | -| `dashboard.service.nodePort` | Set the `nodePort` of the dashboard service if the type is `NodePort` | `nil` | +| `dashboard.persistentVolume.subPath` | Subdirectory of Chaos Dashboard data Persistent Volume to mount | `` | | `dashboard.env` | The keys within the `env` map are mounted as environment variables on the Chaos Dashboard pod | `` | -| `dashboard.env.LISTEN_HOST` | | `0.0.0.0` | -| `dashboard.env.LISTEN_PORT` | | `2333` | -| `dashboard.env.DATABASE_DRIVER`| The db drive used for Chaos Dashboard, support db: sqlite3, mysql| `sqlite3` | -| `dashboard.env.DATABASE_DATASOURCE`| The db dsn used for Chaos Dashboard | `/data/core.sqlite` | -| `dashboard.ingress.enabled` | Enable the use of the ingress controller to access the dashboard | `false` | -| `dashboard.ingress.certManager` | Enable Cert-Manager for ingress | `false` | -| `dashboard.ingress.annotations` | Annotations for the dashboard Ingress | `{}` | -| `dashboard.ingress.hosts[0].name` | Hostname to your dashboard installation | `dashboard.local` | -| `dashboard.ingress.hosts[0].paths` | Path within the url structure | `["/"]` | -| `dashboard.ingress.hosts[0].tls` | Utilize TLS backend in ingress | `false` | -| `dashboard.ingress.hosts[0].tlsHosts` | Array of TLS hosts for ingress record (defaults to `ingress.hosts[0].name` if `nil`) | `nil` | -| `dashboard.ingress.hosts[0].tlsSecret` | TLS Secret (certificates) | `dashboard.local-tls` | +| `dashboard.env.LISTEN_HOST` | The address which chaos-dashboard would listen on. | `0.0.0.0` | +| `dashboard.env.LISTEN_PORT` | The port which chaos-dashboard would listen on. | `2333` | +| `dashboard.env.METRIC_HOST` | The address which metrics endpoints would listen on. | `0.0.0.0` | +| `dashboard.env.METRIC_PORT` | The address which metrics endpoints would listen on. | `2334` | +| `dashboard.env.DATABASE_DRIVER` | The db driver used for Chaos Dashboard, support db: sqlite3, mysql, postgres | `sqlite3` | +| `dashboard.env.DATABASE_DATASOURCE` | (**Deprecated**, use `dashboard.databaseSecretName` instead) Database DSN used for Chaos Dashboard | `/data/core.sqlite` | +| `dashboard.env.CLEAN_SYNC_PERIOD` | Set the sync period to clean up archived data | `12h` | +| `dashboard.env.TTL_EVENT` | Set TTL of archived event data | `168h` | +| `dashboard.env.TTL_EXPERIMENT` | Set TTL of archived experiment data | `336h` | +| `dashboard.env.TTL_SCHEDULE` | Set TTL of archived schedule data | `336h` | +| `dashboard.env.TTL_WORKFLOW` | Set TTL of archived workflow data | `336h` | +| `dashboard.ingress.enabled` | Enable the use of the ingress controller to access the dashboard | `false` | +| `dashboard.ingress.certManager` | Enable Cert-Manager for ingress | `false` | +| `dashboard.ingress.annotations` | Annotations for the dashboard Ingress | `{}` | +| `dashboard.ingress.hosts[0].name` | Hostname to your dashboard installation | `dashboard.local` | +| `dashboard.ingress.hosts[0].tls` | Utilize TLS backend in ingress | `false` | +| `dashboard.ingress.hosts[0].tlsHosts` | Array of TLS hosts for ingress record (defaults to `ingress.hosts[0].name` if `nil`) | `nil` | +| `dashboard.ingress.hosts[0].tlsSecret` | TLS Secret (certificates) | `dashboard.local-tls` | +| `dashboard.ingress.paths` | Paths that map requests to chaos dashboard | `["/"]` | +| `dashboard.ingress.apiVersionOverrides` | Override apiVersion of ingress rendered by this helm chart | `` | +| `dashboard.ingress.ingressClassName` | Defines which ingress controller will implement the resource | `` | +| `dnsServer.create` | Enable DNS Server which required by DNSChaos | `true` | +| `dnsServer.serviceAccount` | Name of serviceaccount for chaos-dns-server. | `chaos-dns-server` | +| `dnsServer.image.registry` | Override global registry, empty value means using the global images.registry | `` | +| `dnsServer.image.repository` | Repository part for image of chaos-dns-server | `chaos-mesh/chaos-coredns` | +| `dnsServer.image.tag` | Override global tag, empty value means using the global images.tag | `v0.2.6` | +| `dnsServer.imagePullPolicy` | Image pull policy | `IfNotPresent` | +| `dnsServer.priorityClassName` | Customized priorityClassName for chaos-dns-server | `` | +| `dnsServer.nodeSelector` | Node labels for chaos-dns-server pod assignment | `` | +| `dnsServer.tolerations` | Toleration labels for chaos-dns-server pod assignment | `[]` | +| `dnsServer.podAnnotations` | Pod annotations of chaos-dns-server | `` | +| `dnsServer.name` | The service name of chaos-dns-server | `chaos-mesh-dns-server` | +| `dnsServer.grpcPort` | Grpc port for chaos-dns-server | `9288` | +| `dnsServer.resources` | CPU/Memory resource requests/limits for chaos-dns-server pod | `requests: { cpu: "100m", memory: "70Mi" }, limits:{}` | +| `dnsServer.env.LISTEN_HOST` | The address of chaos-dns-server listen on | `0.0.0.0` | +| `dnsServer.env.LISTEN_PORT` | The port of chaos-dns-server listen on | `53` | | `prometheus.create` | Enable prometheus | `false` | | `prometheus.serviceAccount` | The serviceAccount for prometheus | `prometheus` | -| `prometheus.priorityClassName` | Custom priorityClassName for using pod priorities | `` | | `prometheus.image` | Docker image for prometheus | `prom/prometheus:v2.15.2` | | `prometheus.imagePullPolicy` | Image pull policy | `IfNotPresent` | +| `prometheus.priorityClassName` | Custom priorityClassName for using pod priorities | `` | | `prometheus.nodeSelector` | Node labels for prometheus pod assignment | `{}` | | `prometheus.tolerations` | Toleration labels for prometheus pod assignment | `[]` | | `prometheus.affinity` | Map of prometheus node/pod affinities | `{}` | | `prometheus.podAnnotations` | Deployment prometheus annotations | `{}` | -| `prometheus.resources` | CPU/Memory resource requests/limits for prometheus pod | `requests: { cpu: "250m", memory: "512Mi" }, limits:{ cpu: "500m", memory: "1024Mi" }` | +| `prometheus.resources` | CPU/Memory resource requests/limits for prometheus pod | `requests: { cpu: "250m", memory: "512Mi" }, limits:{ cpu: "500m", memory: "1024Mi" }` | | `prometheus.service.type` | Kubernetes Service type | `ClusterIP` | -| `prometheus.volume.storage` | | `2Gi` | -| `prometheus.volume.storageClassName` | | `standard` | +| `prometheus.volume.storage` | Storage size of PVC | `2Gi` | +| `prometheus.volume.storageClassName` | Storage class of PVC | `standard` | | `webhook.certManager.enabled` | Setup the webhook using cert-manager | `false` | -| `webhook.FailurePolicy` | Defines how unrecognized errors and timeout errors from the admission webhook are handled | `Ignore` | -| `webhook.CRDS` | Define a list of chaos types that implement admission webhook | `[podchaos,iochaos,timechaos,networkchaos,kernelchaos]` | +| `webhook.timeoutSeconds` | Timeout for admission webhooks in seconds | `5` | +| `webhook.FailurePolicy` | Defines how unrecognized errors and timeout errors from the admission webhook are handled | `Fail` | +| `webhook.CRDS` | Define a list of chaos types that implement admission webhook | `[podchaos,iochaos,timechaos,networkchaos,kernelchaos,stresschaos,awschaos,azurechaos,gcpchaos,dnschaos,jvmchaos,schedule,workflow,httpchaos,bnlockchaos,physicalmachinechaos,phsicalmachine,statuscheck]` | +| `bpfki.create` | Enable chaos-kernel | `false` | +| `bpfki.image.registry` | Override global registry, empty value means using the global images.registry | `` | +| `bpfki.image.repository` | Repository part for image of chaos-kernel | `chaos-mesh/chaos-kernel` | +| `bpfki.image.tag` | Override global tag, empty value means using the global images.tag | `` | +| `bpfki.imagePullPolicy` | Image pull policy | `IfNotPresent` | +| `bpfki.grpcPort` | The port which grpc server listens on | `50051` | +| `bpfki.resources` | CPU/Memory resource requests/limits for chaos-kernel container | `{}` | +| `chaosDlv.enable` | Create sidecar remote debugging container | `false` | +| `chaosDlv.image.registry` | Override global registry, empty value means using the global images.registry | `false` | +| `chaosDlv.repository` | Repository part for image of chaos-dlv | `chaos-mesh/chaos-dlv` | +| `chaosDlv.tag` | Override global tag, empty value means using the global images.tag | `false` | +| `chaosDlv.imagePullPolicy` | Image pull policy | `IfNotPresent` | Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, ```console # helm 2.X -helm install helm/chaos-mesh --name=chaos-mesh --namespace=chaos-testing --set dashboard.create=true +helm install helm/chaos-mesh --name=chaos-mesh --namespace=chaos-mesh # helm 3.X -helm install chaos-mesh helm/chaos-mesh --namespace=chaos-testing --set dashboard.create=true +helm install chaos-mesh helm/chaos-mesh --namespace=chaos-mesh ``` The above command enable the Chaos Dashboard. @@ -119,9 +191,9 @@ Alternatively, a YAML file that specifies the values for the parameters can be p ```console # helm 2.X -helm install helm/chaos-mesh --name=chaos-mesh --namespace=chaos-testing -f values.yaml +helm install helm/chaos-mesh --name=chaos-mesh --namespace=chaos-mesh -f values.yaml # helm 3.X -helm install chaos-mesh helm/chaos-mesh --namespace=chaos-testing -f values.yaml +helm install chaos-mesh helm/chaos-mesh --namespace=chaos-mesh -f values.yaml ``` > **Tip**: You can use the default [values.yaml](values.yaml) @@ -130,16 +202,20 @@ helm install chaos-mesh helm/chaos-mesh --namespace=chaos-testing -f values.yaml ### Using cert-manager for certificate management -[Cert-manager](https://github.com/jetstack/cert-manager) may be the default in the K8s world for certificate management now.If you want to install Cert-manager using the [Helm](https://helm.sh) package manager, please refer to the [official documents](https://github.com/jetstack/cert-manager/tree/master/deploy/charts/cert-manager). +[Cert-manager](https://github.com/jetstack/cert-manager) may be the default in the K8s world for certificate management now. If you want to install Cert-manager using the [Helm](https://helm.sh) package manager, please refer to the [official documents](https://github.com/jetstack/cert-manager/tree/master/deploy/charts/cert-manager). Example for deploy Cert-manager ```bash -kubectl create namespace cert-manager -kubectl apply --validate=false -f https://raw.githubusercontent.com/jetstack/cert-manager/v0.13.1/deploy/manifests/00-crds.yaml helm repo add jetstack https://charts.jetstack.io helm repo update -helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v0.13.1 + +# if Kubernetes > 1.18/Helm 3.2 +helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.6.1 --set installCRDs=true + +# else +kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.6.1/cert-manager.crds.yaml +helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.6.1 ``` In case you want to using Cert-manager for certificate management, you can use the `webhook.certManager.enabled` property. @@ -156,9 +232,9 @@ In case your Cert-manager's option `enable-certificate-owner-ref` is true, it me The Cert-manager's option `enable-certificate-owner-ref` refer to the following: -> https://github.com/jetstack/cert-manager/issues/296 +> > -> https://github.com/jetstack/cert-manager/pull/819 +> You can install your Cert-manager looks like this. diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_awschaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_awschaos.yaml index ecb4fdea6c..f84ade0532 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_awschaos.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_awschaos.yaml @@ -1,166 +1,174 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: awschaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: AwsChaos - listKind: AwsChaosList + kind: AWSChaos + listKind: AWSChaosList plural: awschaos singular: awschaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: AwsChaos is the Schema for the awschaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: AwsChaosSpec is the content of the specification for an AwsChaos - properties: - action: - description: 'Action defines the specific aws chaos action. Supported - action: ec2-stop / ec2-restart / detach-volume Default action: ec2-stop' - enum: - - ec2-stop - - ec2-restart - - detach-volume - type: string - awsRegion: - description: AwsRegion defines the region of aws. - type: string - deviceName: - description: DeviceName indicates the name of the device. Needed in - detach-volume. - type: string - duration: - description: Duration represents the duration of the chaos action. - type: string - ec2Instance: - description: Ec2Instance indicates the ID of the ec2 instance. - type: string - endpoint: - description: Endpoint indicates the endpoint of the aws server. Just - used it in test now. - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. - type: string - volumeID: - description: EbsVolume indicates the ID of the EBS volume. Needed in - detach-volume. - type: string - required: - - action - - awsRegion - - ec2Instance - type: object - status: - description: AwsChaosStatus represents the status of an AwsChaos - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: AWSChaos is the Schema for the awschaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AWSChaosSpec is the content of the specification for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. Supported + action: ec2-stop / ec2-restart / detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. Needed in + detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws server. Just + used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. Needed + in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + status: + description: AWSChaosStatus represents the status of an AWSChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_azurechaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_azurechaos.yaml new file mode 100644 index 0000000000..9db34d55c1 --- /dev/null +++ b/helm/chaos-mesh/crds/chaos-mesh.org_azurechaos.yaml @@ -0,0 +1,175 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: azurechaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: AzureChaos + listKind: AzureChaosList + plural: azurechaos + singular: azurechaos + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: AzureChaos is the Schema for the azurechaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AzureChaosSpec is the content of the specification for an + AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. Supported + action: vm-stop / vm-restart / disk-detach Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the data disk. + Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. It + is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + status: + description: AzureChaosStatus represents the status of an AzureChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_blockchaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_blockchaos.yaml new file mode 100644 index 0000000000..68ebcde0fe --- /dev/null +++ b/helm/chaos-mesh/crds/chaos-mesh.org_blockchaos.yaml @@ -0,0 +1,286 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: blockchaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: BlockChaos + listKind: BlockChaosList + plural: blockchaos + singular: blockchaos + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: BlockChaos is the Schema for the blockchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BlockChaosSpec is the content of the specification for a + BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. Supported + action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every io request. + type: string + type: object + duration: + description: Duration represents the duration of the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + status: + description: BlockChaosStatus represents the status of a BlockChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + ids: + additionalProperties: + type: integer + description: InjectionIds always specifies the number of injected + chaos action + type: object + required: + - experiment + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_dnschaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_dnschaos.yaml index 1534e925a8..34e6f0730e 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_dnschaos.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_dnschaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: dnschaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,249 +12,267 @@ spec: listKind: DNSChaosList plural: dnschaos singular: dnschaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: DNSChaos is the Schema for the networkchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a pod chaos experiment - properties: - action: - description: 'Action defines the specific DNS chaos action. Supported - action: error, random Default action: error' - enum: - - error - - random - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - patterns: - description: "Choose which domain names to take effect, support the - placeholder ? and wildcard *, or the Specified domain name. Note: - \ 1. The wildcard * must be at the end of the string. For example, - chaos-*.org is invalid. 2. if the patterns is empty, will take - effect on all the domain names. For example: \t\tThe value is [\"google.com\", - \"github.*\", \"chaos-mes?.org\"], \t\twill take effect on \"google.com\", - \"github.com\" and \"chaos-mesh.org\"" - items: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: DNSChaos is the Schema for the networkchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a pod chaos experiment + properties: + action: + description: 'Action defines the specific DNS chaos action. Supported + action: error, random Default action: error' + enum: + - error + - random type: string - type: array - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, support the + placeholder ? and wildcard *, or the Specified domain name. Note: + 1. The wildcard * must be at the end of the string. For example, + chaos-*.org is invalid. 2. if the patterns is empty, will take effect + on all the domain names. For example: The value is ["google.com", + "github.*", "chaos-mes?.org"], will take effect on "google.com", + "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - status: - description: Most recently observed status of the chaos experiment about - pods - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + status: + description: Most recently observed status of the chaos experiment about + pods + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_gcpchaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_gcpchaos.yaml index 0991c9e978..fa35da0505 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_gcpchaos.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_gcpchaos.yaml @@ -1,165 +1,177 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: gcpchaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: GcpChaos - listKind: GcpChaosList + kind: GCPChaos + listKind: GCPChaosList plural: gcpchaos singular: gcpchaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: GcpChaos is the Schema for the gcpchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: GcpChaosSpec is the content of the specification for a GcpChaos - properties: - action: - description: 'Action defines the specific gcp chaos action. Supported - action: node-stop / node-reset / disk-loss Default action: node-stop' - enum: - - node-stop - - node-reset - - disk-loss - type: string - deviceName: - description: The device name of the disk to detach. Needed in disk-loss. - type: string - duration: - description: Duration represents the duration of the chaos action. - type: string - instance: - description: Instance defines the name of the instance - type: string - project: - description: Project defines the name of gcp project. - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. It is - used for GCP credentials. - type: string - zone: - description: Zone defines the zone of gcp project. - type: string - required: - - action - - instance - - project - - zone - type: object - status: - description: GcpChaosStatus represents the status of a GcpChaos - properties: - attachedDiskString: - description: The attached disk info string. Needed in disk-loss. - type: string - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: GCPChaos is the Schema for the gcpchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: GCPChaosSpec is the content of the specification for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. Supported + action: node-stop / node-reset / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed in disk-loss. + items: type: string - nextStart: - description: Next time when this action will be applied again - format: date-time + type: array + duration: + description: Duration represents the duration of the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. It + is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + status: + description: GCPChaosStatus represents the status of a GCPChaos + properties: + attachedDiskStrings: + description: The attached disk info strings. Needed in disk-loss. + items: type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: array + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_httpchaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_httpchaos.yaml index b504cfa49c..d1784fad72 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_httpchaos.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_httpchaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: httpchaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,269 +12,384 @@ spec: listKind: HTTPChaosList plural: httpchaos singular: httpchaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: HTTPChaos is the Schema for the HTTPchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: delay | abort | mixed Default action: delay' - enum: - - delay - - abort - - mixed - type: string - duration: - description: Duration represents the duration of the chaos action. It - is required when the action is `PodFailureAction`. 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". - type: string - headers: - description: Specifies how the header match will be performed to route - the request. - items: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: HTTPChaos is the Schema for the HTTPchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status code in + response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal numbers, + each with optional fraction and a unit suffix, such as "300ms", + "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", + "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + method: + description: Method is a rule to select target by http method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. properties: - exact_match: - type: string - invert_match: - type: string - name: - type: string - prefix_match: - type: string - present_match: - type: string - range_match: - type: string - regex_match: + body: + description: Body is a rule to patch message body of target. + properties: + type: + description: Type represents the patch type, only support + `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers of target. + For example: `[["Set-Cookie", ""], ["Set-Cookie", + ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries of target(Request + only). For example: `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri path in http request. + type: string + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents in target. + properties: + body: + description: Body is a rule to replace http message body in target. + format: byte type: string - safe_regex_match: + code: + description: Code is a rule to replace http status code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers of target. + The key-value pairs represent header name and header value pairs. + type: object + method: + description: Method is a rule to replace http method in request. type: string - suffix_match: + path: + description: Path is rule to to replace uri path in http request. type: string - required: - - name + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries in http + request. For example, with value `{ "foo": "unknown" }`, the + `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object type: object - type: array - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - percent: - description: 'Percent defines the percentage of injection errors and - provides a number from 0-100. default: 100.' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + request_headers: + additionalProperties: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + description: RequestHeaders is a rule to select target by http headers + in request. The key-value pairs represent header name and header + value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target by http headers + in response. The key-value pairs represent header name and header + value pairs. + type: object + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos if + there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file in secret, + `ca.crt` for example type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: + certName: + description: CertName represents the data name of cert file in + secret, `tls.crt` for example type: string - type: array - nodeSelectors: - additionalProperties: + keyName: + description: KeyName represents the data name of key file in secret, + `tls.key` for example type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: + secretName: + description: SecretName represents the name of required secret + resource type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: + secretNamespace: + description: SecretNamespace represents the namespace of required + secret resource type: string - type: array - pods: - additionalProperties: - items: + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + status: + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. + status: + type: string + type: + type: string + required: + - status + - type type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. IF `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - status: - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + instances: + additionalProperties: + format: int64 + type: integer + description: Instances always specifies podhttpchaos generation or + empty + type: object + required: + - experiment + type: object + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_iochaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_iochaos.yaml index d944dd1981..a6aaef0723 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_iochaos.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_iochaos.yaml @@ -1,378 +1,399 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: iochaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: IoChaos - listKind: IoChaosList + kind: IOChaos + listKind: IOChaosList plural: iochaos singular: iochaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: IoChaos is the Schema for the iochaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: IoChaosSpec defines the desired state of IoChaos - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: latency / fault / attrOverride / mistake' - enum: - - latency - - fault - - attrOverride - - mistake - type: string - attr: - description: Attr defines the overrided attribution - properties: - atime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - blocks: - format: int64 - type: integer - ctime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - gid: - format: int32 - type: integer - ino: - format: int64 - type: integer - kind: - description: FileType represents type of a file - type: string - mtime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - nlink: - format: int32 - type: integer - perm: - type: integer - rdev: - format: int32 - type: integer - size: - format: int64 - type: integer - uid: - format: int32 - type: integer - type: object - containerName: - description: ContainerName indicates the target container to inject - iochaos in - type: string - delay: - description: Delay defines the value of I/O chaos action delay. A delay - string is a possibly signed sequence of decimal numbers, each with - optional fraction and a unit suffix, such as "300ms". Valid time units - are "ns", "us" (or "µs"), "ms", "s", "m", "h". - type: string - duration: - description: Duration represents the duration of the chaos action. It - is required when the action is `PodFailureAction`. 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". - type: string - errno: - description: 'Errno defines the error code that returned by I/O action. - refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' - format: int32 - type: integer - methods: - description: 'Methods defines the I/O methods for injecting I/O chaos - action. default: all I/O methods.' - items: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: IOChaos is the Schema for the iochaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake type: string - type: array - mistake: - description: Mistake defines what types of incorrectness are injected - to IO operations - properties: - filling: - description: Filling determines what is filled in the miskate data. - enum: - - zero - - random - type: string - maxLength: - description: Max length of each wrong data segment in bytes - format: int64 - minimum: 1 - type: integer - maxOccurrences: - description: There will be [1, MaxOccurrences] segments of wrong - data. - format: int64 - minimum: 1 - type: integer - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - path: - description: Path defines the path of files for injecting I/O chaos - action. - type: string - percent: - description: 'Percent defines the percentage of injection errors and - provides a number from 0-100. default: 100.' - type: integer - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: - type: string - type: array + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer required: - - key - - operator + - nsec + - sec type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action delay. A + delay string is a possibly signed sequence of decimal numbers, each + with optional fraction and a unit suffix, such as "300ms". Valid + time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that returned by I/O action. + refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting I/O chaos + action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness are injected + to IO operations + properties: + filling: + description: Filling determines what is filled in the mistake + data. + enum: + - zero + - random type: string - type: array - pods: - additionalProperties: + maxLength: + description: Max length of each wrong data segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments of wrong + data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting I/O chaos + action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection errors and + provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. IF `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - volumePath: - description: VolumePath represents the mount path of injected volume - type: string - required: - - action - - mode - - selector - - volumePath - type: object - status: - description: IoChaosStatus defines the observed state of IoChaos - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + status: + description: IOChaosStatus defines the observed state of IOChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + instances: + additionalProperties: + format: int64 + type: integer + description: Instances always specifies podiochaos generation or empty + type: object + required: + - experiment + type: object + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_jvmchaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_jvmchaos.yaml index cb6a5671f8..1ed95aa1b9 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_jvmchaos.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_jvmchaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: jvmchaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,266 +12,311 @@ spec: listKind: JVMChaosList plural: jvmchaos singular: jvmchaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: JVMChaos is the Schema for the jvmchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: JVMChaosSpec defines the desired state of JVMChaos - properties: - action: - description: 'Action defines the specific jvm chaos action. Supported - action: delay;return;script;cfl;oom;ccf;tce;cpf;tde;tpf' - enum: - - delay - - return - - script - - cfl - - oom - - ccf - - tce - - cpf - - tde - - tpf - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - flags: - additionalProperties: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: JVMChaos is the Schema for the jvmchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. Supported + action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql type: string - description: Flags represents the flags of action - type: object - matchers: - additionalProperties: + class: + description: Java class type: string - description: Matchers represents the matching rules for the target - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + type: array + cpuCount: + description: the CPU core number needs to use, only set it when action + is stress + type: integer + database: + description: the match database default value is "", means match all + database + type: string + duration: + description: Duration represents the duration of the chaos action + type: string + exception: + description: the exception which needs to throw for action `exception` + or the exception message needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', unit ms or + the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it when action + is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support 5.X.X(set + to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will generate + one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. type: string - type: array - required: - - key - - operator + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - target: - description: 'Target defines the specific jvm chaos target. Supported - target: servlet;psql;jvm;jedis;http;dubbo;rocketmq;tars;mysql;druid;redisson;rabbitmq;mongodb' - enum: - - servlet - - psql - - jvm - - jedis - - http - - dubbo - - rocketmq - - tars - - mysql - - druid - - redisson - - rabbitmq - - mongodb - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the % of pods to do chaos action - type: string - required: - - action - - mode - - selector - - target - type: object - status: - description: JVMChaosStatus defines the observed state of JVMChaos - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + sqlType: + description: the match sql type default value is "", means match all + SQL type. The value can be 'select', 'insert', 'update', 'delete', + 'replace'. + type: string + table: + description: the match table default value is "", means match all + table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + status: + description: JVMChaosStatus defines the observed state of JVMChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_kernelchaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_kernelchaos.yaml index 6217f3f022..c2a656c5c3 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_kernelchaos.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_kernelchaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: kernelchaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,298 +12,313 @@ spec: listKind: KernelChaosList plural: kernelchaos singular: kernelchaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: KernelChaos is the Schema for the kernelchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a kernel chaos experiment - properties: - duration: - description: Duration represents the duration of the chaos action - type: string - failKernRequest: - description: FailKernRequest defines the request of kernel injection - properties: - callchain: - description: 'Callchain indicate a special call chain, such as: ext4_mount -> - mount_subtree -> ... -> should_failslab With - an optional set of predicates and an optional set of parameters, - which used with predicates. You can read call chan and predicate - examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples - to learn more. If no special call chain, just keep Callchain empty, - which means it will fail at any call chain with slab alloc (eg: - kmalloc).' - items: - description: Frame defines the function signature and predicate - in function's body - properties: - funcname: - description: Funcname can be find from kernel source or `/proc/kallsyms`, - such as `ext4_mount` - type: string - parameters: - description: Parameters is used with predicate, for example, - if you want to inject slab error in `d_alloc_parallel(struct - dentry *parent, const struct qstr *name)` with a special - name `bananas`, you need to set it to `struct dentry *parent, - const struct qstr *name` otherwise omit it. - type: string - predicate: - description: Predicate will access the arguments of this Frame, - example with Parameters's, you can set it to `STRNCMP(name->name, - "bananas", 8)` to make inject only with it, or omit it to - inject for all d_alloc_parallel call chain. - type: string - type: object - type: array - failtype: - description: 'FailType indicates what to fail, can be set to ''0'' - / ''1'' / ''2'' If `0`, indicates slab to fail (should_failslab) - If `1`, indicates alloc_page to fail (should_fail_alloc_page) - If `2`, indicates bio to fail (should_fail_bio) You can read: 1. - https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html 2. - http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt - to learn more' - format: int32 - maximum: 2 - minimum: 0 - type: integer - headers: - description: 'Headers indicates the appropriate kernel headers you - need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so on' - items: - type: string - type: array - probability: - description: Probability indicates the fails with probability. If - you want 1%, please set this field with 1. - format: int32 - maximum: 100 - minimum: 0 - type: integer - times: - description: Times indicates the max times of fails. - format: int32 - minimum: 0 - type: integer - required: - - failtype - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + versions: + - additionalPrinterColumns: + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: KernelChaos is the Schema for the kernelchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a kernel chaos experiment + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call chain, such as: + ext4_mount -> mount_subtree -> ... -> should_failslab With an + optional set of predicates and an optional set of parameters, + which used with predicates. You can read call chan and predicate + examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep Callchain + empty, which means it will fail at any call chain with slab + alloc (eg: kmalloc).' + items: + description: Frame defines the function signature and predicate + in function's body + properties: + funcname: + description: Funcname can be find from kernel source or + `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, for example, + if you want to inject slab error in `d_alloc_parallel(struct + dentry *parent, const struct qstr *name)` with a special + name `bananas`, you need to set it to `struct dentry *parent, + const struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments of this + Frame, example with Parameters's, you can set it to `STRNCMP(name->name, + "bananas", 8)` to make inject only with it, or omit it + to inject for all d_alloc_parallel call chain. type: string - type: array - required: - - key - - operator + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be set to ''0'' + / ''1'' / ''2'' If `0`, indicates slab to fail (should_failslab) + If `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) You can read: + 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel headers + you need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - failKernRequest - - mode - - selector - type: object - status: - description: Most recently observed status of the kernel chaos experiment - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + status: + description: Most recently observed status of the kernel chaos experiment + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_networkchaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_networkchaos.yaml index e66fc2b5d7..2913abf211 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_networkchaos.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_networkchaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: networkchaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,474 +12,509 @@ spec: listKind: NetworkChaosList plural: networkchaos singular: networkchaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: NetworkChaos is the Schema for the networkchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a pod chaos experiment - properties: - action: - description: 'Action defines the specific network chaos action. Supported - action: partition, netem, delay, loss, duplicate, corrupt Default - action: delay' - enum: - - netem - - delay - - loss - - duplicate - - corrupt - - partition - - bandwidth - type: string - bandwidth: - description: Bandwidth represents the detail about bandwidth control - action - properties: - buffer: - description: Buffer is the maximum amount of bytes that tokens can - be available for instantaneously. - format: int32 - minimum: 1 - type: integer - limit: - description: Limit is the number of bytes that can be queued waiting - for tokens to become available. - format: int32 - minimum: 1 - type: integer - minburst: - description: Minburst specifies the size of the peakrate bucket. - For perfect accuracy, should be set to the MTU of the interface. If - a peakrate is needed, but some burstiness is acceptable, this - size can be raised. A 3000 byte minburst allows around 3mbit/s - of peakrate, given 1000 byte packets. - format: int32 - minimum: 0 - type: integer - peakrate: - description: Peakrate is the maximum depletion rate of the bucket. - The peakrate does not need to be set, it is only necessary if - perfect millisecond timescale shaping is required. - format: int64 - minimum: 0 - type: integer - rate: - description: Rate is the speed knob. Allows bps, kbps, mbps, gbps, - tbps unit. bps means bytes per second. - type: string - required: - - buffer - - limit - - rate - type: object - corrupt: - description: Corrupt represents the detail about corrupt action - properties: - correlation: - type: string - corrupt: - type: string - required: - - correlation - - corrupt - type: object - delay: - description: Delay represents the detail about delay action - properties: - correlation: - type: string - jitter: - type: string - latency: - type: string - reorder: - description: ReorderSpec defines details of packet reorder. - properties: - correlation: - type: string - gap: - type: integer - reorder: - type: string - required: - - correlation - - gap - - reorder - type: object - required: - - latency - type: object - direction: - description: Direction represents the direction, this applies on netem - and network partition action - enum: - - to - - from - - both - - "" - type: string - duplicate: - description: DuplicateSpec represents the detail about loss action - properties: - correlation: - type: string - duplicate: - type: string - required: - - correlation - - duplicate - type: object - duration: - description: Duration represents the duration of the chaos action - type: string - externalTargets: - description: ExternalTargets represents network targets outside k8s - items: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: NetworkChaos is the Schema for the networkchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a pod chaos experiment + properties: + action: + description: 'Action defines the specific network chaos action. Supported + action: partition, netem, delay, loss, duplicate, corrupt Default + action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth type: string - type: array - loss: - description: Loss represents the detail about loss action - properties: - correlation: - type: string - loss: - type: string - required: - - correlation - - loss - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: + bandwidth: + description: Bandwidth represents the detail about bandwidth control + action + properties: + buffer: + description: Buffer is the maximum amount of bytes that tokens + can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be queued waiting + for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate bucket. + For perfect accuracy, should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness is acceptable, this + size can be raised. A 3000 byte minburst allows around 3mbit/s + of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of the bucket. + The peakrate does not need to be set, it is only necessary if + perfect millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, gbit, + tbit, bps, kbps, mbps, gbps, tbps unit. bps means bytes per + second. type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. properties: - key: - description: key is the label key that the selector applies - to. + correlation: type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. + gap: + type: integer + reorder: type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: - type: string - type: array required: - - key - - operator + - gap + - reorder type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies on netem + and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss action + properties: + correlation: type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: + duplicate: type: string - type: array - nodeSelectors: - additionalProperties: + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: + loss: type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, gbit, + tbit, bps, kbps, mbps, gbps, tbps unit. bps means bytes per + second. type: string - type: array - pods: - additionalProperties: - items: + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - target: - description: Target represents network target, this applies on netem - and network partition action - properties: - mode: - description: TargetMode defines the target selector mode - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - - "" - type: string - selector: - description: TargetSelector defines the target selector - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. + type: array + required: + - key + - operator type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: items: type: string type: array - pods: - additionalProperties: + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this applies on netem + and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: TargetValue is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - mode - - selector - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - status: - description: Most recently observed status of the chaos experiment about - pods - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device to be affected + in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + status: + description: Most recently observed status of the chaos experiment about + pods + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + instances: + additionalProperties: + format: int64 + type: integer + description: Instances always specifies podnetworkchaos generation + or empty + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_physicalmachinechaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_physicalmachinechaos.yaml new file mode 100644 index 0000000000..dba9ead76d --- /dev/null +++ b/helm/chaos-mesh/crds/chaos-mesh.org_physicalmachinechaos.yaml @@ -0,0 +1,1091 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: physicalmachinechaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: PhysicalMachineChaos + listKind: PhysicalMachineChaosList + plural: physicalmachinechaos + singular: physicalmachinechaos + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: PhysicalMachineChaos is the Schema for the physical machine chaos + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a physical machine chaos experiment + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one of Address + and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock on which to + act. More clock description in linux kernel can be found in + man page of clock_getres, clock_gettime, clock_settime. Muti + clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. if path not + provided, payload will read/write from/into a temp file, temp + file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will write into + the file path. support unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. if path not + provided, payload will read/write from/into a temp file, temp + file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write into + the file path. support unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. if path not + provided, payload will read/write from/into a temp file, temp + file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write into + the file path. support unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the file. + type: string + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http status code + in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by http status code + in response + type: string + delay: + description: Delay represents the delay of the target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", means match + all database + type: string + exception: + description: The exception which needs to throw for action `exception` + or the exception message needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' or the + latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", means match + all SQL type. The value can be 'select', 'insert', 'update', + 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, will + use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set it when + action is stress + type: integer + mem-type: + description: the memory type need to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: + tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can be accepted, + others will be dropped. only set when the IPProtocol is tcp, + used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: + tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), ms, s, + m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf with this + value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or µs), ms, s, + m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: + tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP address + type: string + rate: + description: The speed of network traffic, allows bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: + tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can be accepted, + others will be dropped. only set when the IPProtocol is tcp, + used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values can be + 'from', 'to'. 'from' means packets coming from the 'IPAddress' + or 'Hostname' and going to your server, 'to' means packets originating + from your server and going to the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of the original + value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string keys and a set + values that used to select physical machines. The key defines + the namespace which physical machine belong, and each value + is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. 0 is + effectively a sleep (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, default + is the total available memory. One can specify the size as % + of total available memory or in units of B, KB/KiB, MB/MiB, + GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of physical machines to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of physical machines + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do chaos + action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + status: + description: Most recently observed status of the chaos experiment + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_physicalmachines.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_physicalmachines.yaml new file mode 100644 index 0000000000..2ce402edd5 --- /dev/null +++ b/helm/chaos-mesh/crds/chaos-mesh.org_physicalmachines.yaml @@ -0,0 +1,47 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: physicalmachines.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: PhysicalMachine + listKind: PhysicalMachineList + plural: physicalmachines + singular: physicalmachine + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PhysicalMachine is the Schema for the physical machine API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a physical machine + properties: + address: + description: Address represents the address of the physical machine + type: string + required: + - address + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_podchaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_podchaos.yaml index 1fc747fdcc..fd9dd23ddb 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_podchaos.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_podchaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: podchaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,255 +12,263 @@ spec: listKind: PodChaosList plural: podchaos singular: podchaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: PodChaos is the control script`s spec. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a pod chaos experiment - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: pod-kill / pod-failure / container-kill Default action: pod-kill' - enum: - - pod-kill - - pod-failure - - container-kill - type: string - containerName: - description: ContainerName indicates the name of the container. Needed - in container-kill. - type: string - duration: - description: Duration represents the duration of the chaos action. It - is required when the action is `PodFailureAction`. 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". - type: string - gracePeriod: - description: GracePeriod is used in pod-kill action. It represents the - duration in seconds before the pod should be deleted. Value must be - non-negative integer. The default value is zero that indicates delete - immediately. - format: int64 - minimum: 0 - type: integer - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PodChaos is the control script`s spec. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a pod chaos experiment + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: pod-kill / pod-failure / container-kill Default action: + pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + type: array + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It represents + the duration in seconds before the pod should be deleted. Value + must be non-negative integer. The default value is zero that indicates + delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. IF `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - status: - description: Most recently observed status of the chaos experiment about - pods - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + status: + description: Most recently observed status of the chaos experiment about + pods + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_podhttpchaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_podhttpchaos.yaml new file mode 100644 index 0000000000..889162287c --- /dev/null +++ b/helm/chaos-mesh/crds/chaos-mesh.org_podhttpchaos.yaml @@ -0,0 +1,237 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: podhttpchaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: PodHttpChaos + listKind: PodHttpChaosList + plural: podhttpchaos + singular: podhttpchaos + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PodHttpChaos is the Schema for the podhttpchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PodHttpChaosSpec defines the desired state of PodHttpChaos. + properties: + rules: + description: Rules are a list of injection rule for http request. + items: + description: PodHttpChaosRule defines the injection rule for http. + properties: + actions: + description: Actions contains rules to inject target. + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, + such as "300ms", "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of + target. + properties: + type: + description: Type represents the patch type, only + support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], + ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", "bar"], + ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http message + body in target. + format: byte + type: string + code: + description: Code is a rule to replace http status code + in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header name + and header value pairs. + type: object + method: + description: Method is a rule to replace http method + in request. + type: string + path: + description: Path is rule to to replace uri path in + http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": + "unknown" }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + type: object + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + selector: + description: Selector contains the rules to select target. + properties: + code: + description: Code is a rule to select target by http status + code in response. + format: int32 + type: integer + method: + description: Method is a rule to select target by http method + in request. + type: string + path: + description: Path is a rule to select target by uri path + in http request. + type: string + port: + description: Port is a rule to select server listening on + specific port. + format: int32 + type: integer + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target by + http headers in request. The key-value pairs represent + header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target + by http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + type: object + source: + description: Source represents the source of current rules + type: string + target: + description: Target is the object to be selected and injected, + . + type: string + required: + - actions + - port + - selector + - target + type: object + type: array + tls: + description: TLS is the tls config, will be override if there are + multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file in secret, + `ca.crt` for example + type: string + certName: + description: CertName represents the data name of cert file in + secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of key file in secret, + `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required secret + resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace of required + secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + type: object + status: + description: PodHttpChaosStatus defines the actual state of PodHttpChaos. + properties: + failedMessage: + type: string + observedGeneration: + format: int64 + type: integer + pid: + description: Pid represents a running tproxy process id. + format: int64 + type: integer + startTime: + description: StartTime represents the start time of a tproxy process. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_podiochaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_podiochaos.yaml index ded2239c36..b48e851305 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_podiochaos.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_podiochaos.yaml @@ -1,207 +1,207 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: podiochaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: PodIoChaos - listKind: PodIoChaosList + kind: PodIOChaos + listKind: PodIOChaosList plural: podiochaos singular: podiochaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: PodIoChaos is the Schema for the podiochaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: PodIoChaosSpec defines the desired state of IoChaos - properties: - actions: - description: Actions are a list of IoChaos actions - items: - description: IoChaosAction defines an possible action of IoChaos - properties: - atime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - blocks: - format: int64 - type: integer - ctime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - faults: - description: Faults represents the fault to inject - items: - description: IoFault represents the fault to inject and their - weight + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PodIOChaos is the Schema for the podiochaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PodIOChaosSpec defines the desired state of IOChaos + properties: + actions: + description: Actions are a list of IOChaos actions + items: + description: IOChaosAction defines a possible action of IOChaos + properties: + atime: + description: Timespec represents a time properties: - errno: - format: int32 + nsec: + format: int64 type: integer - weight: - format: int32 + sec: + format: int64 type: integer required: - - errno - - weight + - nsec + - sec type: object - type: array - gid: - format: int32 - type: integer - ino: - format: int64 - type: integer - kind: - description: FileType represents type of a file - type: string - latency: - description: Latency represents the latency to inject - type: string - methods: - description: Methods represents the method that the action will - inject in - items: + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + faults: + description: Faults represents the fault to inject + items: + description: IoFault represents the fault to inject and their + weight + properties: + errno: + format: int32 + type: integer + weight: + format: int32 + type: integer + required: + - errno + - weight + type: object + type: array + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + latency: + description: Latency represents the latency to inject type: string - type: array - mistake: - description: MistakeSpec represents the mistake to inject - properties: - filling: - description: Filling determines what is filled in the miskate - data. - enum: - - zero - - random + methods: + description: Methods represents the method that the action will + inject in + items: type: string - maxLength: - description: Max length of each wrong data segment in bytes - format: int64 - minimum: 1 - type: integer - maxOccurrences: - description: There will be [1, MaxOccurrences] segments of - wrong data. - format: int64 - minimum: 1 - type: integer - type: object - mtime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - nlink: - format: int32 - type: integer - path: - description: Path represents a glob of injecting path - type: string - percent: - description: Percent represents the percent probability of injecting - this action - type: integer - perm: - type: integer - rdev: - format: int32 - type: integer - size: - format: int64 - type: integer - source: - description: Source represents the source of current rules - type: string - type: - description: IoChaosType represents the type of an IoChaos Action - type: string - uid: - format: int32 - type: integer - required: - - path - - percent - - type - type: object - type: array - container: - description: 'TODO: support multiple different container to inject in - one pod' - type: string - pid: - description: Pid represents a running toda process id - format: int64 - type: integer - startTime: - description: StartTime represents the start time of a toda process - format: int64 - type: integer - volumeMountPath: - description: 'VolumeMountPath represents the target mount path It must - be a root of mount path now. TODO: search the mount parent of any - path automatically. TODO: support multiple different volume mount - path in one pod' - type: string - required: - - volumeMountPath - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: array + mistake: + description: MistakeSpec represents the mistake to inject + properties: + filling: + description: Filling determines what is filled in the mistake + data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + path: + description: Path represents a glob of injecting path + type: string + percent: + description: Percent represents the percent probability of injecting + this action + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + source: + description: Source represents the source of current rules + type: string + type: + description: IOChaosType represents the type of IOChaos Action + type: string + uid: + format: int32 + type: integer + required: + - path + - percent + - type + type: object + type: array + container: + description: 'TODO: support multiple different container to inject + in one pod' + type: string + volumeMountPath: + description: 'VolumeMountPath represents the target mount path It + must be a root of mount path now. TODO: search the mount parent + of any path automatically. TODO: support multiple different volume + mount path in one pod' + type: string + required: + - volumeMountPath + type: object + status: + properties: + failedMessage: + type: string + observedGeneration: + format: int64 + type: integer + pid: + description: Pid represents a running toda process id + format: int64 + type: integer + startTime: + description: StartTime represents the start time of a toda process + format: int64 + type: integer + type: object + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: + status: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_podnetworkchaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_podnetworkchaos.yaml index e4ffdf8f2b..2b226e8017 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_podnetworkchaos.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_podnetworkchaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: podnetworkchaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,272 +12,253 @@ spec: listKind: PodNetworkChaosList plural: podnetworkchaos singular: podnetworkchaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: PodNetworkChaos is the Schema for the PodNetworkChaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a pod chaos experiment - properties: - ipsets: - description: The ipset on the pod - items: - description: RawIPSet represents an ipset on specific pod - properties: - cidrs: - description: The contents of ipset - items: - type: string - type: array - name: - description: The name of ipset - type: string - source: - type: string - required: - - cidrs - - name - - source - type: object - type: array - iptables: - description: The iptables rules on the pod - items: - description: RawIptables represents the iptables rules on specific - pod - properties: - direction: - description: The block direction of this iptables rule - type: string - ipsets: - description: The name of related ipset - items: - type: string - type: array - name: - description: The name of iptables chain - type: string - source: - type: string - required: - - direction - - ipsets - - name - - source - type: object - type: array - tcs: - description: The tc rules on the pod - items: - description: RawTrafficControl represents the traffic control chaos - on specific pod - properties: - bandwidth: - description: Bandwidth represents the detail about bandwidth control - action - properties: - buffer: - description: Buffer is the maximum amount of bytes that tokens - can be available for instantaneously. - format: int32 - minimum: 1 - type: integer - limit: - description: Limit is the number of bytes that can be queued - waiting for tokens to become available. - format: int32 - minimum: 1 - type: integer - minburst: - description: Minburst specifies the size of the peakrate bucket. - For perfect accuracy, should be set to the MTU of the interface. If - a peakrate is needed, but some burstiness is acceptable, - this size can be raised. A 3000 byte minburst allows around - 3mbit/s of peakrate, given 1000 byte packets. - format: int32 - minimum: 0 - type: integer - peakrate: - description: Peakrate is the maximum depletion rate of the - bucket. The peakrate does not need to be set, it is only - necessary if perfect millisecond timescale shaping is required. - format: int64 - minimum: 0 - type: integer - rate: - description: Rate is the speed knob. Allows bps, kbps, mbps, - gbps, tbps unit. bps means bytes per second. - type: string - required: - - buffer - - limit - - rate - type: object - corrupt: - description: Corrupt represents the detail about corrupt action - properties: - correlation: - type: string - corrupt: - type: string - required: - - correlation - - corrupt - type: object - delay: - description: Delay represents the detail about delay action - properties: - correlation: - type: string - jitter: - type: string - latency: - type: string - reorder: - description: ReorderSpec defines details of packet reorder. + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PodNetworkChaos is the Schema for the PodNetworkChaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a pod chaos experiment + properties: + ipsets: + description: The ipset on the pod + items: + description: RawIPSet represents an ipset on specific pod + properties: + cidrAndPorts: + description: The contents of ipset. Only available when IPSetType + is NetPortIPSet. + items: + description: CidrAndPort represents CIDR and port pair properties: - correlation: + cidr: type: string - gap: + port: + maximum: 65535 + minimum: 1 type: integer - reorder: - type: string required: - - correlation - - gap - - reorder + - cidr + - port type: object - required: - - latency - type: object - duplicate: - description: DuplicateSpec represents the detail about loss action - properties: - correlation: - type: string - duplicate: - type: string - required: - - correlation - - duplicate - type: object - ipset: - description: The name of target ipset - type: string - loss: - description: Loss represents the detail about loss action - properties: - correlation: - type: string - loss: - type: string - required: - - correlation - - loss - type: object - source: - description: The name and namespace of the source network chaos - type: string - type: - description: The type of traffic control - type: string - required: - - source - - type - type: object - type: array - type: object - status: - description: Most recently observed status of the chaos experiment about - pods - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: + type: array + cidrs: + description: The contents of ipset. Only available when IPSetType + is NetIPSet. + items: type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: + type: array + ipsetType: + description: IPSetType represents the type of IP set + type: string + name: + description: The name of ipset + type: string + setNames: + description: The contents of ipset. Only available when IPSetType + is SetIPSet. + items: type: string - podIP: + type: array + source: + type: string + required: + - ipsetType + - name + - source + type: object + type: array + iptables: + description: The iptables rules on the pod + items: + description: RawIptables represents the iptables rules on specific + pod + properties: + device: + description: Device represents the network device to be affected. + type: string + direction: + description: The block direction of this iptables rule + type: string + ipsets: + description: The name of related ipset + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + nullable: true + type: array + name: + description: The name of iptables chain + type: string + source: + type: string + required: + - direction + - name + - source + type: object + type: array + tcs: + description: The tc rules on the pod + items: + description: RawTrafficControl represents the traffic control chaos + on specific pod + properties: + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes that + tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be queued + waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate + bucket. For perfect accuracy, should be set to the MTU + of the interface. If a peakrate is needed, but some burstiness + is acceptable, this size can be raised. A 3000 byte minburst + allows around 3mbit/s of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of the + bucket. The peakrate does not need to be set, it is only + necessary if perfect millisecond timescale shaping is + required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + duplicate: + description: DuplicateSpec represents the detail about loss + action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + ipset: + description: The name of target ipset + type: string + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + rate: + description: Rate represents the detail about rate control action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - rate + type: object + source: + description: The name and namespace of the source network chaos + type: string + type: + description: The type of traffic control + type: string + required: + - source + - type + type: object + type: array + type: object + status: + description: Most recently observed status of the chaos experiment about + pods + properties: + failedMessage: + type: string + observedGeneration: + format: int64 + type: integer + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: + status: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_remoteclusters.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_remoteclusters.yaml new file mode 100644 index 0000000000..d32bb37b9d --- /dev/null +++ b/helm/chaos-mesh/crds/chaos-mesh.org_remoteclusters.yaml @@ -0,0 +1,101 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: remoteclusters.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: RemoteCluster + listKind: RemoteClusterList + plural: remoteclusters + singular: remotecluster + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: RemoteCluster defines a remote cluster + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: RemoteClusterSpec defines the specification of a remote cluster + properties: + configOverride: + type: object + x-kubernetes-preserve-unknown-fields: true + kubeConfig: + description: RemoteClusterKubeConfig refers to a secret by which we'll + use to connect remote cluster + properties: + secretRef: + description: RemoteClusterSecretRef refers to a secret in any + namespaces + properties: + key: + type: string + name: + type: string + namespace: + type: string + required: + - key + - name + - namespace + type: object + required: + - secretRef + type: object + namespace: + type: string + version: + type: string + required: + - kubeConfig + - namespace + - version + type: object + status: + properties: + conditions: + description: Conditions represents the current condition of the remote + cluster + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + currentVersion: + type: string + observedGeneration: + format: int64 + type: integer + required: + - currentVersion + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_schedules.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_schedules.yaml new file mode 100644 index 0000000000..3c26ef09f3 --- /dev/null +++ b/helm/chaos-mesh/crds/chaos-mesh.org_schedules.yaml @@ -0,0 +1,13778 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: schedules.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: Schedule + listKind: ScheduleList + plural: schedules + singular: schedule + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Schedule is the cronly schedule object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ScheduleSpec is the specification of a schedule object + properties: + awsChaos: + description: AWSChaosSpec is the content of the specification for + an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. Supported + action: ec2-stop / ec2-restart / detach-volume Default action: + ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. Needed + in detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws server. + Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. Needed + in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification for + an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. + Supported action: vm-stop / vm-restart / disk-detach Default + action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. Needed in + disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the data + disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification for + a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. + Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every io request. + type: string + type: object + duration: + description: Duration represents the duration of the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + default: Forbid + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos action. Supported + action: error, random Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, support + the placeholder ? and wildcard *, or the Specified domain name. + Note: 1. The wildcard * must be at the end of the string. For + example, chaos-*.org is invalid. 2. if the patterns is empty, + will take effect on all the domain names. For example: The value + is ["google.com", "github.*", "chaos-mes?.org"], will take effect + on "google.com", "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification for + a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. Supported + action: node-stop / node-reset / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status code + in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, such + as "300ms", "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + method: + description: Method is a rule to select target by http method + in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of target. + properties: + type: + description: Type represents the patch type, only support + `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers of + target. For example: `[["Set-Cookie", ""], ["Set-Cookie", + ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries of target(Request + only). For example: `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri path in http + request. + type: string + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents in target. + properties: + body: + description: Body is a rule to replace http message body in + target. + format: byte + type: string + code: + description: Code is a rule to replace http status code in + response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers of + target. The key-value pairs represent header name and header + value pairs. + type: object + method: + description: Method is a rule to replace http method in request. + type: string + path: + description: Path is rule to to replace uri path in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries in + http request. For example, with value `{ "foo": "unknown" + }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target by http + headers in request. The key-value pairs represent header name + and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target by http + headers in response. The key-value pairs represent header name + and header value pairs. + type: object + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file in + secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name of cert file + in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of key file + in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required secret + resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace of required + secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action delay. + A delay string is a possibly signed sequence of decimal numbers, + each with optional fraction and a unit suffix, such as "300ms". + Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that returned by I/O + action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting I/O + chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness are injected + to IO operations + properties: + filling: + description: Filling determines what is filled in the mistake + data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments of + wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting I/O + chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection errors + and provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected + volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. Supported + action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only set it when + action is stress + type: integer + database: + description: the match database default value is "", means match + all database + type: string + duration: + description: Duration represents the duration of the chaos action + type: string + exception: + description: the exception which needs to throw for action `exception` + or the exception message needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', unit ms + or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will generate + one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", means match + all SQL type. The value can be 'select', 'insert', 'update', + 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call chain, such + as: ext4_mount -> mount_subtree -> ... -> should_failslab + With an optional set of predicates and an optional set of + parameters, which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep Callchain + empty, which means it will fail at any call chain with slab + alloc (eg: kmalloc).' + items: + description: Frame defines the function signature and predicate + in function's body + properties: + funcname: + description: Funcname can be find from kernel source + or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, for + example, if you want to inject slab error in `d_alloc_parallel(struct + dentry *parent, const struct qstr *name)` with a special + name `bananas`, you need to set it to `struct dentry + *parent, const struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments of + this Frame, example with Parameters's, you can set + it to `STRNCMP(name->name, "bananas", 8)` to make + inject only with it, or omit it to inject for all + d_alloc_parallel call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be set + to ''0'' / ''1'' / ''2'' If `0`, indicates slab to fail + (should_failslab) If `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) You can + read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel headers + you need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so + on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos action. + Supported action: partition, netem, delay, loss, duplicate, + corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth control + action + properties: + buffer: + description: Buffer is the maximum amount of bytes that tokens + can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be queued + waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate bucket. + For perfect accuracy, should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness is acceptable, + this size can be raised. A 3000 byte minburst allows around + 3mbit/s of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of the + bucket. The peakrate does not need to be set, it is only + necessary if perfect millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies + on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets outside + k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this applies on + netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device to be + affected in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired state of + PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one of Address + and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock on which + to act. More clock description in linux kernel can be found + in man page of clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the file. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + delay: + description: Delay represents the delay of the target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for action + `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', unit + ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", means + match all database + type: string + exception: + description: The exception which needs to throw for action + `exception` or the exception message needs to throw in action + `mysql` + type: string + latency: + description: The latency duration for action 'latency' or + the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, will + use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set it + when action is stress + type: integer + mem-type: + description: the memory type need to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can + be accepted, others will be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf with + this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads to + run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP address + type: string + rate: + description: The speed of network traffic, allows bps, kbps, + mbps, gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can + be accepted, others will be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values can + be 'from', 'to'. 'from' means packets coming from the 'IPAddress' + or 'Hostname' and going to your server, 'to' means packets + originating from your server and going to the 'IPAddress' + or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of the original + value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string keys and + a set values that used to select physical machines. The + key defines the namespace which physical machine belong, + and each value is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. 0 + is effectively a sleep (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, default + is the total available memory. One can specify the size + as % of total available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify + the percent of physical machines the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify + the max percent of pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a user creates + on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: pod-kill / pod-failure / container-kill Default action: + pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It represents + the duration in seconds before the pod should be deleted. Value + must be non-negative integer. The default value is zero that + indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + exclusiveMinimum: true + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors just + like `Stressors` except that it's an experimental feature and + more powerful. You can define stressors in `stress-ng` (see + also `man stress-ng`) dialect, however not all of the supported + stressors are well tested. It maybe retired in later releases. + You should always use `Stressors` to define the stressors and + use this only when you want more stressors unsupported by `Stressors`. + When both `StressngStressors` and `Stressors` are defined, `StressngStressors` + wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported to + stress system components out. You can use one or more of them + to make up various kinds of stresses. At least one of the stressors + should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading per CPU + worker. 0 is effectively a sleep (no load) and 100 is + full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to apply the + stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj of the + stress process. See `man 5 proc` to know more about + this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per vm worker, + default is the total available memory. One can specify + the size as % of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to apply the + stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id All available + options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected program. + It's a possibly signed sequence of decimal numbers, such as + "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + workflow: + properties: + entry: + type: string + templates: + items: + properties: + abortWithStatusCheck: + description: AbortWithStatusCheck describe whether to abort + the workflow when the failure threshold of StatusCheck + is exceeded. Only used when Type is TypeStatusCheck. + type: boolean + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos + action. Supported action: ec2-stop / ec2-restart / + detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. + Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 + instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the + aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. + Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos + action. Supported action: vm-stop / vm-restart / disk-detach + Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. + Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of + the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure + subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos + action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every + io request. + type: string + type: object + duration: + description: Duration represents the duration of the + chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + children: + description: Children describes the children steps of serial + or parallel node. Only used when Type is TypeSerial or + TypeParallel. + items: + type: string + type: array + conditionalBranches: + description: ConditionalBranches describes the conditional + branches of custom tasks. Only used when Type is TypeTask. + items: + properties: + expression: + description: Expression is the expression for this + conditional branch, expected type of result is boolean. + If expression is empty, this branch will always + be selected/the template will be spawned. + type: string + target: + description: Target is the name of other template, + if expression is evaluated as true, this template + will be spawned. + type: string + required: + - target + type: object + type: array + deadline: + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos + action. Supported action: error, random Default action: + error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, + support the placeholder ? and wildcard *, or the Specified + domain name. Note: 1. The wildcard * must be at the + end of the string. For example, chaos-*.org is invalid. + 2. if the patterns is empty, will take effect on all + the domain names. For example: The value is ["google.com", + "github.*", "chaos-mes?.org"], will take effect on + "google.com", "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos + action. Supported action: node-stop / node-reset / + disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed + in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http + status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target + request/response. A duration string is a possibly + unsigned sequence of decimal numbers, each with optional + fraction and a unit suffix, such as "300ms", "2h45m". + Valid time units are "ns", "us" (or "µs"), "ms", "s", + "m", "h". + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + method: + description: Method is a rule to select target by http + method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. + properties: + body: + description: Body is a rule to patch message body + of target. + properties: + type: + description: Type represents the patch type, + only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", + "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri + path in http request. + type: string + port: + description: Port represents the target port to be proxy + of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http message + body in target. + format: byte + type: string + code: + description: Code is a rule to replace http status + code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header + name and header value pairs. + type: object + method: + description: Method is a rule to replace http method + in request. + type: string + path: + description: Path is rule to to replace uri path + in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": + "unknown" }`, the `/?foo=bar` will be altered + to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target + by http headers in request. The key-value pairs represent + header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target + by http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and + injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of + ca file in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name of + cert file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of + key file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required + secret resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace + of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: latency / fault / attrOverride + / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action + delay. A delay string is a possibly signed sequence + of decimal numbers, each with optional fraction and + a unit suffix, such as "300ms". Valid time units are + "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the + chaos action. It is required when the action is `PodFailureAction`. + 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". + type: string + errno: + description: 'Errno defines the error code that returned + by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting + I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled in + the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment + in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting + I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection + errors and provides a number from 0-100. default: + 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path of + injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos + action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only + set it when action is stress + type: integer + database: + description: the match database default value is "", + means match all database + type: string + duration: + description: Duration represents the duration of the + chaos action + type: string + exception: + description: the exception which needs to throw for + action `exception` or the exception message needs + to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set + it when action is stress, the value can be 'stack' + or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only + support 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and + will generate one if not set + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", + means match all SQL type. The value can be 'select', + 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of + KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of + kernel injection + properties: + callchain: + description: 'Callchain indicate a special call + chain, such as: ext4_mount -> mount_subtree -> + ... -> should_failslab With an optional set of + predicates and an optional set of parameters, + which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just + keep Callchain empty, which means it will fail + at any call chain with slab alloc (eg: kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from kernel + source or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab + error in `d_alloc_parallel(struct dentry + *parent, const struct qstr *name)` with + a special name `bananas`, you need to set + it to `struct dentry *parent, const struct + qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments + of this Frame, example with Parameters's, + you can set it to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, or omit + it to inject for all d_alloc_parallel call + chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can + be set to ''0'' / ''1'' / ''2'' If `0`, indicates + slab to fail (should_failslab) If `1`, indicates + alloc_page to fail (should_fail_alloc_page) If + `2`, indicates bio to fail (should_fail_bio) You + can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with + probability. If you want 1%, please set this field + with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + name: + type: string + networkChaos: + description: NetworkChaosSpec defines the desired state + of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos + action. Supported action: partition, netem, delay, + loss, duplicate, corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes + that tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can + be queued waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the + peakrate bucket. For perfect accuracy, should + be set to the MTU of the interface. If a peakrate + is needed, but some burstiness is acceptable, + this size can be raised. A 3000 byte minburst + allows around 3mbit/s of peakrate, given 1000 + byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate + of the bucket. The peakrate does not need to be + set, it is only necessary if perfect millisecond + timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, + kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, + tbps unit. bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt + action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay + action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet + reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to + be affected. + type: string + direction: + default: to + description: Direction represents the direction, this + applies on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about + loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the + chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets + outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control + action + properties: + rate: + description: Rate is the speed knob. Allows bit, + kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, + tbps unit. bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this + applies on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device + to be affected in target scope. + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired + state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only + one of Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock + on which to act. More clock description in linux + kernel can be found in man page of clock_getres, + clock_gettime, clock_settime. Muti clock ids should + be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + payload-process-num: + description: specifies the number of process work + on writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + payload-process-num: + description: specifies the number of process work + on writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the + chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to append + the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to + be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of + the file. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file + to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the + file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by + http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP + connection, we will only attack HTTP connection + with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by + http status code in response + type: string + delay: + description: Delay represents the delay of the target + request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP + connection, we will only attack HTTP connection + with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support + GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw + for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', + unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is + "", means match all database + type: string + exception: + description: The exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' + or the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set to + "8") now + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is + "", means match all SQL type. The value can be + 'select', 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", + means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's + data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only + set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, only + set it when action is stress, the value can be + 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp + flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used for + partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or + µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf + test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client + threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the + IP address + type: string + rate: + description: The speed of network traffic, allows + bps, kbps, mbps, gbps, tbps unit. bps means bytes + per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is + 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp + flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used for + partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means packets + coming from the 'IPAddress' or 'Hostname' and + going to your server, 'to' means packets originating + from your server and going to the 'IPAddress' + or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these + IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering + experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string + keys and a set values that used to select physical + machines. The key defines the namespace which + physical machine belong, and each value is a set + of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU + worker. 0 is effectively a sleep (no load) and + 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, + default is the total available memory. One can + specify the size as % of total available memory + or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of physical machines + to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of physical + machines the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a + user creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: pod-kill / pod-failure / + container-kill Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action. It is required when the action is `PodFailureAction`. + 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. + It represents the duration in seconds before the pod + should be deleted. Value must be non-negative integer. + The default value is zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + description: Schedule describe the Schedule(describing scheduled + chaos) to be injected with chaos nodes. Only used when + Type is TypeSchedule. + properties: + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos + action. Supported action: ec2-stop / ec2-restart + / detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the + device. Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the + ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of + the aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS + volume. Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure + chaos action. Supported action: vm-stop / vm-restart + / disk-detach Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the + disk. Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number + of the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name + of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure + subscription. + type: string + vmName: + description: VMName defines the name of Virtual + Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block + chaos action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of + every io request. + type: string + type: object + duration: + description: Duration represents the duration of + the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state + of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos + action. Supported action: error, random Default + action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take + effect, support the placeholder ? and wildcard + *, or the Specified domain name. Note: 1. The + wildcard * must be at the end of the string. For + example, chaos-*.org is invalid. 2. if the patterns + is empty, will take effect on all the domain names. + For example: The value is ["google.com", "github.*", + "chaos-mes?.org"], will take effect on "google.com", + "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos + action. Supported action: node-stop / node-reset + / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. + Needed in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by + http status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target + request/response. A duration string is a possibly + unsigned sequence of decimal numbers, each with + optional fraction and a unit suffix, such as "300ms", + "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + method: + description: Method is a rule to select target by + http method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. + properties: + body: + description: Body is a rule to patch message + body of target. + properties: + type: + description: Type represents the patch type, + only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http + headers of target. For example: `[["Set-Cookie", + ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri + queries of target(Request only). For example: + `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by + uri path in http request. + type: string + port: + description: Port represents the target port to + be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http + message body in target. + format: byte + type: string + code: + description: Code is a rule to replace http + status code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http + headers of target. The key-value pairs represent + header name and header value pairs. + type: object + method: + description: Method is a rule to replace http + method in request. + type: string + path: + description: Path is rule to to replace uri + path in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri + queries in http request. For example, with + value `{ "foo": "unknown" }`, the `/?foo=bar` + will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select + target by http headers in request. The key-value + pairs represent header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select + target by http headers in response. The key-value + pairs represent header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected + and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override + PodHttpChaos if there are multiple HTTPChaos experiments + are applied + properties: + caName: + description: CAName represents the data name + of ca file in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name + of cert file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name + of key file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name + of required secret resource + type: string + secretNamespace: + description: SecretNamespace represents the + namespace of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of + IOChaos + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: latency / fault / attrOverride + / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos + action delay. A delay string is a possibly signed + sequence of decimal numbers, each with optional + fraction and a unit suffix, such as "300ms". Valid + time units are "ns", "us" (or "µs"), "ms", "s", + "m", "h". + type: string + duration: + description: Duration represents the duration of + the chaos action. It is required when the action + is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that + returned by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for + injecting I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled + in the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment + in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] + segments of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for + injecting I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of + injection errors and provides a number from 0-100. + default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path + of injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state + of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos + action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only + set it when action is stress + type: integer + database: + description: the match database default value is + "", means match all database + type: string + duration: + description: Duration represents the duration of + the chaos action + type: string + exception: + description: the exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only + set it when action is stress, the value can be + 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set to + "8") now + type: string + name: + description: byteman rule name, should be unique, + and will generate one if not set + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action + 'ruleData' + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is + "", means match all SQL type. The value can be + 'select', 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", + means match all table + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state + of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request + of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call + chain, such as: ext4_mount -> mount_subtree + -> ... -> should_failslab With an optional + set of predicates and an optional set of parameters, + which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just + keep Callchain empty, which means it will + fail at any call chain with slab alloc (eg: + kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from + kernel source or `/proc/kallsyms`, such + as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab + error in `d_alloc_parallel(struct dentry + *parent, const struct qstr *name)` with + a special name `bananas`, you need to + set it to `struct dentry *parent, const + struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the + arguments of this Frame, example with + Parameters's, you can set it to `STRNCMP(name->name, + "bananas", 8)` to make inject only with + it, or omit it to inject for all d_alloc_parallel + call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, + can be set to ''0'' / ''1'' / ''2'' If `0`, + indicates slab to fail (should_failslab) If + `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) + You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails + with probability. If you want 1%, please set + this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of + fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state + of NetworkChaos + properties: + action: + description: 'Action defines the specific network + chaos action. Supported action: partition, netem, + delay, loss, duplicate, corrupt Default action: + delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about + bandwidth control action + properties: + buffer: + description: Buffer is the maximum amount of + bytes that tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that + can be queued waiting for tokens to become + available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of + the peakrate bucket. For perfect accuracy, + should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness + is acceptable, this size can be raised. A + 3000 byte minburst allows around 3mbit/s of + peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion + rate of the bucket. The peakrate does not + need to be set, it is only necessary if perfect + millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about + corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay + action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of + packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device + to be affected. + type: string + direction: + default: to + description: Direction represents the direction, + this applies on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail + about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of + the chaos action + type: string + externalTargets: + description: ExternalTargets represents network + targets outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss + action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate + control action + properties: + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this + applies on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network + device to be affected in target scope. + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired + state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. + Only one of Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular + clock on which to act. More clock description + in linux kernel can be found in man page of + clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 is + valid value + type: integer + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 is + valid value + type: integer + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of + the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to + append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to + create or delete. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to + create or delete. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + privilege: + description: Privilege is the file privilege + to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to + be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string + of the file. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + line: + description: Line is the line number of the + file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string + of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of + HTTP connection, we will only attack HTTP + connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + delay: + description: Delay represents the delay of the + target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of + HTTP connection, we will only attack HTTP + connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support + GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw + for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action + 'latency', unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value + is "", means match all database + type: string + exception: + description: The exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action + 'latency' or the latency duration in action + `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set + to "8") now + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value + is "", means match all SQL type. The value + can be 'select', 'insert', 'update', 'delete', + 'replace'. + type: string + table: + description: the match table default value is + "", means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule + file's data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, + only set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, + only set it when action is stress, the value + can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the + tcp flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used + for partition. + type: string + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: + ns, us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the + iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client + threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on + the IP address + type: string + rate: + description: The speed of network traffic, allows + bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the + tcp flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used + for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means packets + coming from the 'IPAddress' or 'Hostname' + and going to your server, 'to' means packets + originating from your server and going to + the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these + IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process + ID + type: string + recoverCmd: + description: the command to be run when recovering + experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical + machines that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string + keys and a set values that used to select + physical machines. The key defines the namespace + which physical machine belong, and each value + is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per + CPU worker. 0 is effectively a sleep (no load) + and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the + stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per + vm worker, default is the total available + memory. One can specify the size as % of total + available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when + attack + type: string + recoverCmd: + description: The command to be executed when + recover + type: string + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of physical + machines to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent + of physical machines the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do + chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that + a user creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: pod-kill / pod-failure + / container-kill Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action. It is required when the action + is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. + It represents the duration in seconds before the + pod should be deleted. Value must be non-negative + integer. The default value is zero that indicates + delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired state + of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of + stressors just like `Stressors` except that it's + an experimental feature and more powerful. You + can define stressors in `stress-ng` (see also + `man stress-ng`) dialect, however not all of the + supported stressors are well tested. It maybe + retired in later releases. You should always use + `Stressors` to define the stressors and use this + only when you want more stressors unsupported + by `Stressors`. When both `StressngStressors` + and `Stressors` are defined, `StressngStressors` + wins. + type: string + stressors: + description: Stressors defines plenty of stressors + supported to stress system components out. You + can use one or more of them to make up various + kinds of stresses. At least one of the stressors + should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading + per CPU worker. 0 is effectively a sleep + (no load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 workers + can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual + memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` + to know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % + of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 workers + can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state + of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock + id All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of + injected program. It's a possibly signed sequence + of decimal numbers, such as "300ms", "-1.5h" or + "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + required: + - schedule + - type + type: object + statusCheck: + description: StatusCheck describe the behavior of StatusCheck. + Only used when Type is TypeStatusCheck. + properties: + duration: + description: Duration defines the duration of the whole + status check if the number of failed execution does + not exceed the failure threshold. Duration is available + to both `Synchronous` and `Continuous` mode. 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum consecutive + failure for the status check to be considered failed. + minimum: 1 + type: integer + http: + properties: + body: + type: string + criteria: + description: Criteria defines how to determine the + result of the status check. + properties: + statusCode: + description: StatusCode defines the expected + http status code for the request. A statusCode + string could be a single code (e.g. 200), + or an inclusive range (e.g. 200-400, both + `200` and `400` are included). + type: string + required: + - statusCode + type: object + headers: + additionalProperties: + items: + type: string + type: array + description: "A Header represents the key-value + pairs in an HTTP header. \n The keys should be + in canonical form, as returned by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in seconds) + to perform an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of the + status check. Support type: Synchronous / Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number + of record to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum consecutive + successes for the status check to be considered successful. + SuccessThreshold only works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of seconds + after which an execution of status check times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check + type. Support type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + stressChaos: + description: StressChaosSpec defines the desired state of + StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors + just like `Stressors` except that it's an experimental + feature and more powerful. You can define stressors + in `stress-ng` (see also `man stress-ng`) dialect, + however not all of the supported stressors are well + tested. It maybe retired in later releases. You should + always use `Stressors` to define the stressors and + use this only when you want more stressors unsupported + by `Stressors`. When both `StressngStressors` and + `Stressors` are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported + to stress system components out. You can use one or + more of them to make up various kinds of stresses. + At least one of the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading + per CPU worker. 0 is effectively a sleep (no + load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to + apply the stressor. Maximum 8192 workers can + run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory + out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` to + know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % of total + available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to + apply the stressor. Maximum 8192 workers can + run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + type: object + task: + description: Task describes the behavior of the custom task. + Only used when Type is TypeTask. + properties: + container: + description: Container is the main container image to + run in the pod + properties: + args: + description: 'Arguments to the entrypoint. The container + image''s CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using + the container''s environment. If a variable cannot + be resolved, the reference in the input string + will be unchanged. Double $$ are reduced to a + single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will + never be expanded, regardless of whether the variable + exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The container image''s ENTRYPOINT is + used if this is not provided. Variable references + $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, + the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot + be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set + in the container. Cannot be updated. + items: + description: EnvVar represents an environment + variable present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined + environment variables in the container and + any service environment variables. If a + variable cannot be resolved, the reference + in the input string will be unchanged. Double + $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal + "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable + exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: + supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the + container: only resources limits and + requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret + in the pod's namespace + properties: + key: + description: The key of the secret + to select from. Must be a valid + secret key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined within + a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container + is starting. When a key exists in multiple sources, + the value associated with the last source will + take precedence. Values defined by an Env with + a duplicate key will take precedence. Cannot be + updated. + items: + description: EnvFromSource represents the source + of a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be a + C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config + management to default or override container images + in workload controllers like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, + Never, IfNotPresent. Defaults to Always if :latest + tag is specified, or IfNotPresent otherwise. Cannot + be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system + should take in response to container lifecycle + events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately + after a container is created. If the handler + fails, the container is terminated and restarted + according to its restart policy. Other management + of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT + supported as a LifecycleHandler and kept + for the backward compatibility. There + are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler + is specified. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately + before a container is terminated due to an + API request or management event such as liveness/startup + probe failure, preemption, resource contention, + etc. The handler is not called if the container + crashes or exits. The Pod''s termination grace + period countdown begins before the PreStop + hook is executed. Regardless of the outcome + of the handler, the container will eventually + terminate within the Pod''s termination grace + period (unless delayed by finalizers). Other + management of the container blocks until the + hook completes or until the termination grace + period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT + supported as a LifecycleHandler and kept + for the backward compatibility. There + are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler + is specified. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as + a DNS_LABEL. Each container in a pod must have + a unique name (DNS_LABEL). Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. + Not specifying a port here DOES NOT prevent that + port from being exposed. Any port which is listening + on the default "0.0.0.0" address inside a container + will be accessible from the network. Modifying + this array with strategic merge patch may corrupt + the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network + port in a single container. + properties: + containerPort: + description: Number of port to expose on the + pod's IP address. This must be a valid port + number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on the + host. If specified, this must be a valid + port number, 0 < x < 65536. If HostNetwork + is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an + IANA_SVC_NAME and unique within the pod. + Each named port in a pod must have a unique + name. Name for the port that can be referred + to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, + TCP, or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service + readiness. Container will be removed from service + endpoints if the probe fails. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents + resource resize policy for the container. + properties: + resourceName: + description: 'Name of the resource to which + this resource resize policy applies. Supported + values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when + specified resource is resized. If not specified, + it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this + container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, + defined in spec.resourceClaims, that are used + by this container. \n This is an alpha field + and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. + It can only be set for containers." + items: + description: ResourceClaim references one + entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available inside + a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. If Requests + is omitted for a container, it defaults to + Limits if that is explicitly specified, otherwise + to an implementation-defined value. Requests + cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + restartPolicy: + description: 'RestartPolicy defines the restart + behavior of individual containers in a pod. This + field may only be set for init containers, and + the only allowed value is "Always". For non-init + containers or when this field is not specified, + the restart behavior is defined by the Pod''s + restart policy and the container type. Setting + the RestartPolicy as "Always" for the init container + will have the following effect: this init container + will be continually restarted on exit until all + regular containers have terminated. Once all regular + containers have completed, all init containers + with restartPolicy "Always" will be shut down. + This lifecycle differs from normal init containers + and is often referred to as a "sidecar" container. + Although this init container still starts in the + init container sequence, it does not wait for + the container to complete before proceeding to + the next init container. Instead, the next init + container starts immediately after this init container + is started, or after any startupProbe has successfully + completed.' + type: string + securityContext: + description: 'SecurityContext defines the security + options the container should be run with. If set, + the fields of SecurityContext override the equivalent + fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges + than its parent process. This bool directly + controls if the no_new_privs flag will be + set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run + as Privileged 2) has CAP_SYS_ADMIN Note that + this field cannot be set when spec.os.name + is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when + running containers. Defaults to the default + set of capabilities granted by the container + runtime. Note that this field cannot be set + when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. + Processes in privileged containers are essentially + equivalent to root on the host. Defaults to + false. Note that this field cannot be set + when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc + mount to use for the containers. The default + is DefaultProcMount which uses the container + runtime defaults for readonly paths and masked + paths. This requires the ProcMountType feature + flag to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only + root filesystem. Default is false. Note that + this field cannot be set when spec.os.name + is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of + the container process. Uses runtime default + if unset. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must + run as a non-root user. If true, the Kubelet + will validate the image at runtime to ensure + that it does not run as UID 0 (root) and fail + to start the container if it does. If unset + or false, no such validation will be performed. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of + the container process. Defaults to user specified + in image metadata if unspecified. May also + be set in PodSecurityContext. If set in both + SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied + to the container. If unspecified, the container + runtime will allocate a random SELinux context + for each container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label + that applies to the container. + type: string + role: + description: Role is a SELinux role label + that applies to the container. + type: string + type: + description: Type is a SELinux type label + that applies to the container. + type: string + user: + description: User is a SELinux user label + that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this + container. If seccomp options are provided + at both the pod & container level, the container + options override the pod options. Note that + this field cannot be set when spec.os.name + is windows. + properties: + localhostProfile: + description: localhostProfile indicates + a profile defined in a file on the node + should be used. The profile must be preconfigured + on the node to work. Must be a descending + path, relative to the kubelet's configured + seccomp profile location. Must be set + if type is "Localhost". Must NOT be set + for any other type. + type: string + type: + description: "type indicates which kind + of seccomp profile will be applied. Valid + options are: \n Localhost - a profile + defined in a file on the node should be + used. RuntimeDefault - the container runtime + default profile should be used. Unconfined + - no profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options + from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where + the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName + field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the + name of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a + container should be run as a 'Host Process' + container. All of a Pod's containers must + have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess + containers and non-HostProcess containers). + In addition, if HostProcess is true then + HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to + run the entrypoint of the container process. + Defaults to the user specified in image + metadata if unspecified. May also be set + in PodSecurityContext. If set in both + SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the Pod + has successfully initialized. If specified, no + other probes are executed until this completes + successfully. If this probe fails, the Pod will + be restarted, just as if the livenessProbe failed. + This can be used to provide different probe parameters + at the beginning of a Pod''s lifecycle, when it + might take a long time to load data or warm a + cache, than during steady-state operation. This + cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. If + this is not set, reads from stdin in the container + will always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should + close the stdin channel after it has been opened + by a single attach. When stdin is true the stdin + stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is + opened on container start, is empty until the + first client attaches to stdin, and then remains + open and accepts data until the client disconnects, + at which time stdin is closed and remains closed + until the container is restarted. If this flag + is false, a container processes that reads from + stdin will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to + which the container''s termination message will + be written is mounted into the container''s filesystem. + Message written is intended to be brief final + status, such as an assertion failure message. + Will be truncated by the node if greater than + 4096 bytes. The total message length across all + containers will be limited to 12kb. Defaults to + /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message + should be populated. File will use the contents + of terminationMessagePath to populate the container + status message on both success and failure. FallbackToLogsOnError + will use the last chunk of container log output + if the termination message file is empty and the + container exited with an error. The log output + is limited to 2048 bytes or 80 lines, whichever + is smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be + true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block + devices to be used by the container. + items: + description: volumeDevice describes a mapping + of a raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside + of the container that the device will be + mapped to. + type: string + name: + description: name must match the name of a + persistentVolumeClaim in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting + of a Volume within a container. + properties: + mountPath: + description: Path within the container at + which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how + mounts are propagated from the host to container + and the other way around. When not set, + MountPropagationNone is used. This field + is beta in 1.10. + type: string + name: + description: This must match the Name of a + Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write + otherwise (false or unspecified). Defaults + to false. + type: boolean + subPath: + description: Path within the volume from which + the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume + from which the container's volume should + be mounted. Behaves similarly to SubPath + but environment variable references $(VAR_NAME) + are expanded using the container's environment. + Defaults to "" (volume's root). SubPathExpr + and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not + specified, the container runtime's default will + be used, which might be configured in the container + image. Cannot be updated. + type: string + required: + - name + type: object + volumes: + description: Volumes is a list of volumes that can be + mounted by containers in a template. + items: + description: Volume represents a named volume in a + pod that may be accessed by any container in the + pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents + an AWS Disk resource that is attached to a kubelet''s + host machine and then exposed to the pod. More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in + the volume that you want to mount. If omitted, + the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify + the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can + leave the property empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force + the readOnly setting in VolumeMounts. More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the + persistent disk resource in AWS (Amazon + EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data + Disk mount on the host and bind mount to the + pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching + mode: None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data + disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk + in the blob storage + type: string + fsType: + description: fsType is Filesystem type to + mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: + multiple blob disks per storage account Dedicated: + single blob disk per storage account Managed: + azure managed data disk (only in managed + availability set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File + Service mount on the host and bind mount to + the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret + that contains Azure Storage Account Name + and Key + type: string + shareName: + description: shareName is the azure share + Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount + on the host that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors + is a collection of Ceph monitors More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the + mounted root, rather than the full Ceph + tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile + is the path to key ring for User, default + is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef + is reference to the authentication secret + for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the + rados user name, default is admin More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume + attached and mounted on kubelets host machine. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points + to a secret object containing parameters + used to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the + volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap + that should populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode + bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. + Directories within the path are not affected + by this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced + ConfigMap will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the ConfigMap, the volume setup will + error unless it is marked optional. Paths + must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether the + ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) + represents ephemeral storage that is handled + by certain external CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI + driver that handles this volume. Consult + with your admin for the correct name as + registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", + "xfs", "ntfs". If not provided, the empty + value is passed to the associated CSI driver + which will determine the default filesystem + to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference + to the secret object containing sensitive + information to pass to the CSI driver to + complete the CSI NodePublishVolume and NodeUnpublishVolume + calls. This field is optional, and may + be empty if no secret is required. If the + secret object contains more than one secret, + all secret references are passed. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only + configuration for the volume. Defaults to + false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. + Consult your driver's documentation for + supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API + about the pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on + created files by default. Must be a Optional: + mode bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. + Directories within the path are not affected + by this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + items: + description: Items is a list of downward API + volume file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used + to set permissions on this file, must + be an octal value between 0000 and + 0777 or a decimal value between 0 + and 511. YAML accepts both octal and + decimal values, JSON requires decimal + values for mode bits. If not specified, + the volume defaultMode will be used. + This might be in conflict with other + options that affect the file mode, + like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file to + be created. Must not be absolute or + contain the ''..'' path. Must be utf-8 + encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env + vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary + directory that shares a pod''s lifetime. More + info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type + of storage medium should back this directory. + The default is "" which means to use the + node''s default medium. Must be an empty + string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount + of local storage required for this EmptyDir + volume. The size limit is also applicable + for memory medium. The maximum usage on + memory medium EmptyDir would be the minimum + value between the SizeLimit specified here + and the sum of memory limits of all containers + in a pod. The default is nil which means + that the limit is undefined. More info: + https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume that + is handled by a cluster storage driver. The + volume's lifecycle is tied to the pod that defines + it - it will be created before the pod starts, + and deleted when the pod is removed. \n Use + this if: a) the volume is only needed while + the pod runs, b) features of normal volumes + like restoring from snapshot or capacity tracking + are needed, c) the storage driver is specified + through a storage class, and d) the storage + driver supports dynamic volume provisioning + through a PersistentVolumeClaim (see EphemeralVolumeSource + for more information on the connection between + this volume type and PersistentVolumeClaim). + \n Use PersistentVolumeClaim or one of the vendor-specific + APIs for volumes that persist for longer than + the lifecycle of an individual pod. \n Use CSI + for light-weight local ephemeral volumes if + the CSI driver is meant to be used that way + - see the documentation of the driver for more + information. \n A pod can use both types of + ephemeral volumes and persistent volumes at + the same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone + PVC to provision the volume. The pod in + which this EphemeralVolumeSource is embedded + will be the owner of the PVC, i.e. the PVC + will be deleted together with the pod. The + name of the PVC will be `-` where `` is the name + from the `PodSpec.Volumes` array entry. + Pod validation will reject the pod if the + concatenated name is not valid for a PVC + (for example, too long). \n An existing + PVC with that name that is not owned by + the pod will *not* be used for the pod to + avoid using an unrelated volume by mistake. + Starting the pod is then blocked until the + unrelated PVC is removed. If such a pre-created + PVC is meant to be used by the pod, the + PVC has to updated with an owner reference + to the pod once the pod exists. Normally + this should not be necessary, but it may + be useful when manually reconstructing a + broken cluster. \n This field is read-only + and no changes will be made by Kubernetes + to the PVC after it has been created. \n + Required, must not be nil." + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when + creating it. No other fields are allowed + and will be rejected during validation. + type: object + spec: + description: The specification for the + PersistentVolumeClaim. The entire content + is copied unchanged into the PVC that + gets created from this template. The + same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: 'accessModes contains + the desired access modes the volume + should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can + be used to specify either: * An + existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external + controller can support the specified + data source, it will create a new + volume based on the contents of + the specified data source. When + the AnyVolumeDataSource feature + gate is enabled, dataSource contents + will be copied to dataSourceRef, + and dataSourceRef contents will + be copied to dataSource when dataSourceRef.namespace + is not specified. If the namespace + is specified, then dataSourceRef + will not be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, + the specified Kind must be in + the core API group. For any + other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies + the object from which to populate + the volume with data, if a non-empty + volume is desired. This may be any + object from a non-empty API group + (non core object) or a PersistentVolumeClaim + object. When this field is specified, + volume binding will only succeed + if the type of the specified object + matches some installed volume populator + or dynamic provisioner. This field + will replace the functionality of + the dataSource field and as such + if both fields are non-empty, they + must have the same value. For backwards + compatibility, when namespace isn''t + specified in dataSourceRef, both + fields (dataSource and dataSourceRef) + will be set to the same value automatically + if one of them is empty and the + other is non-empty. When namespace + is specified in dataSourceRef, dataSource + isn''t set to the same value and + must be empty. There are three important + differences between dataSource and + dataSourceRef: * While dataSource + only allows two specific types of + objects, dataSourceRef allows any + non-core object, as well as PersistentVolumeClaim + objects. * While dataSource ignores + disallowed values (dropping them), + dataSourceRef preserves all values, + and generates an error if a disallowed + value is specified. * While dataSource + only allows local objects, dataSourceRef + allows objects in any namespaces. + (Beta) Using this field requires + the AnyVolumeDataSource feature + gate to be enabled. (Alpha) Using + the namespace field of dataSourceRef + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, + the specified Kind must be in + the core API group. For any + other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + namespace: + description: Namespace is the + namespace of resource being + referenced Note that when a + namespace is specified, a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent + namespace to allow that namespace's + owner to accept the reference. + See the ReferenceGrant documentation + for details. (Alpha) This field + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents + the minimum resources the volume + should have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed + to specify resource requirements + that are lower than previous value + but must still be higher than capacity + recorded in the status field of + the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the + names of resources, defined + in spec.resourceClaims, that + are used by this container. + \n This is an alpha field and + requires enabling the DynamicResourceAllocation + feature gate. \n This field + is immutable. It can only be + set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match + the name of one entry + in pod.spec.resourceClaims + of the Pod where this + field is used. It makes + that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes + the maximum amount of compute + resources allowed. More info: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes + the minimum amount of compute + resources required. If Requests + is omitted for a container, + it defaults to Limits if that + is explicitly specified, otherwise + to an implementation-defined + value. Requests cannot exceed + Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query + over volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a key, + and an operator that relates + the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid + operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In + or NotIn, the values array + must be non-empty. If + the operator is Exists + or DoesNotExist, the values + array must be empty. This + array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a + map of {key,value} pairs. A + single {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator + is "In", and the values array + contains only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName is + the name of the StorageClass required + by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what + type of volume is required by the + claim. Value of Filesystem is implied + when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding + reference to the PersistentVolume + backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource + that is attached to a kubelet's host machine + and then exposed to the pod. + properties: + fsType: + description: 'fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. TODO: how do we prevent + errors in the filesystem from compromising + the machine' + type: string + lun: + description: 'lun is Optional: FC target lun + number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target + worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume world + wide identifiers (wwids) Either wwids or + combination of targetWWNs and lun must be + set, but not both simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume + resource that is provisioned/attached using + an exec based plugin. + properties: + driver: + description: driver is the name of the driver + to use for this volume. + type: string + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". The default filesystem depends + on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field + holds extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef + is reference to the secret object containing + sensitive information to pass to the plugin + scripts. This may be empty if no secret + object is specified. If the secret object + contains more than one secret, all secrets + are passed to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume + attached to a kubelet's host machine. This depends + on the Flocker control service being running + properties: + datasetName: + description: datasetName is Name of the dataset + stored as metadata -> name on the dataset + for Flocker should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the + dataset. This is unique identifier of a + Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE + Disk resource that is attached to a kubelet''s + host machine and then exposed to the pod. More + info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of + the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in + the volume that you want to mount. If omitted, + the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify + the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can + leave the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the + PD resource in GCE. Used to identify the + disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the + ReadOnly setting in VolumeMounts. Defaults + to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository + at a particular revision. DEPRECATED: GitRepo + is deprecated. To provision a container with + a git repo, mount an EmptyDir into an InitContainer + that clones the repo using git, then mount the + EmptyDir into the Pod''s container.' + properties: + directory: + description: directory is the target directory + name. Must not contain or start with '..'. If + '.' is supplied, the volume directory will + be the git repository. Otherwise, if specified, + the volume will contain the git repository + in the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for + the specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name + that details Glusterfs topology. More info: + https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume + path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the + Glusterfs volume to be mounted with read-only + permissions. Defaults to false. More info: + https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing + file or directory on the host machine that is + directly exposed to the container. This is generally + used for system agents or other privileged things + that are allowed to see the host machine. Most + containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can + use host directory mounts and who can/can not + mount host directories as read/write.' + properties: + path: + description: 'path of the directory on the + host. If the path is a symlink, it will + follow the link to the real path. More info: + https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults + to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource + that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether + support iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether + support iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI + Initiator Name. If initiatorName is specified + with iscsiInterface simultaneously, new + iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified + Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface + Name that uses an iSCSI transport. Defaults + to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun + number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal + List. The portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the + ReadOnly setting in VolumeMounts. Defaults + to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret + for iSCSI target and initiator authentication + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target + Portal. The Portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL + and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the + host that shares a pod''s lifetime More info: + https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the + NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the + NFS export to be mounted with read-only + permissions. Defaults to false. More info: + https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP + address of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource + represents a reference to a PersistentVolumeClaim + in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this + volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a + PhotonController persistent disk attached and + mounted on kubelets host machine + properties: + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies + Photon Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx + volume attached and mounted on kubelets host + machine + properties: + fsType: + description: fSType represents the filesystem + type to mount Must be a filesystem type + supported by the host operating system. + Ex. "ext4", "xfs". Implicitly inferred to + be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies + a Portworx volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources + secrets, configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits + used to set permissions on created files + by default. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. Directories within the path are + not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume + projections + items: + description: Projection that may be projected + along with other supported volume types + properties: + configMap: + description: configMap information about + the configMap data to project + properties: + items: + description: items if unspecified, + each key-value pair in the Data + field of the referenced ConfigMap + will be projected into the volume + as a file whose name is the key + and content is the value. If specified, + the listed keys will be projected + into the specified paths, and + unlisted keys will not be present. + If a key is specified which is + not present in the ConfigMap, + the volume setup will error unless + it is marked optional. Paths must + be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key + to a path within a volume. + properties: + key: + description: key is the key + to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an + octal value between 0000 + and 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If + not specified, the volume + defaultMode will be used. + This might be in conflict + with other options that + affect the file mode, like + fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map + the key to. May not be an + absolute path. May not contain + the path element '..'. May + not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information + about the downwardAPI data to project + properties: + items: + description: Items is a list of + DownwardAPIVolume file + items: + description: DownwardAPIVolumeFile + represents information to create + the file containing the pod + field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only + annotations, labels, name + and namespace are supported.' + properties: + apiVersion: + description: Version of + the schema the FieldPath + is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the + field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode + bits used to set permissions + on this file, must be an + octal value between 0000 + and 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If + not specified, the volume + defaultMode will be used. + This might be in conflict + with other options that + affect the file mode, like + fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path + is the relative path name + of the file to be created. + Must not be absolute or + contain the ''..'' path. + Must be utf-8 encoded. The + first item of the relative + path must not start with + ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource + of the container: only resources + limits and requests (limits.cpu, + limits.memory, requests.cpu + and requests.memory) are + currently supported.' + properties: + containerName: + description: 'Container + name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies + the output format of + the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: + resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about + the secret data to project + properties: + items: + description: items if unspecified, + each key-value pair in the Data + field of the referenced Secret + will be projected into the volume + as a file whose name is the key + and content is the value. If specified, + the listed keys will be projected + into the specified paths, and + unlisted keys will not be present. + If a key is specified which is + not present in the Secret, the + volume setup will error unless + it is marked optional. Paths must + be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key + to a path within a volume. + properties: + key: + description: key is the key + to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an + octal value between 0000 + and 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If + not specified, the volume + defaultMode will be used. + This might be in conflict + with other options that + affect the file mode, like + fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map + the key to. May not be an + absolute path. May not contain + the path element '..'. May + not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: optional field specify + whether the Secret or its key + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is + information about the serviceAccountToken + data to project + properties: + audience: + description: audience is the intended + audience of the token. A recipient + of a token must identify itself + with an identifier specified in + the audience of the token, and + otherwise should reject the token. + The audience defaults to the identifier + of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is + the requested duration of validity + of the service account token. + As the token approaches expiration, + the kubelet volume plugin will + proactively rotate the service + account token. The kubelet will + start trying to rotate the token + if the token is older than 80 + percent of its time to live or + if the token is older than 24 + hours.Defaults to 1 hour and must + be at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative + to the mount point of the file + to project the token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount + on the host that shares a pod's lifetime + properties: + group: + description: group to map volume access to + Default is no group + type: string + readOnly: + description: readOnly here will force the + Quobyte volume to be mounted with read-only + permissions. Defaults to false. + type: boolean + registry: + description: registry represents a single + or multiple Quobyte Registry services specified + as a string as host:port pair (multiple + entries are separated with commas) which + acts as the central registry for volumes + type: string + tenant: + description: tenant owning the given Quobyte + volume in the Backend Used with dynamically + provisioned Quobyte volumes, value is set + by the plugin + type: string + user: + description: user to map volume access to + Defaults to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + image: + description: 'image is the rados image name. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring + for RBDUser. Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of + Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. + Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the + ReadOnly setting in VolumeMounts. Defaults + to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides + keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. + Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of + the ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name + of the ScaleIO Protection Domain for the + configured storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret + for ScaleIO user and other sensitive information. + If this is not provided, Login operation + will fail. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable + SSL communication with Gateway, default + false + type: boolean + storageMode: + description: storageMode indicates whether + the storage for a volume should be ThickProvisioned + or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage + Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage + system as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume + already created in the ScaleIO system that + is associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that + should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode + bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. + Directories within the path are not affected + by this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + items: + description: items If unspecified, each key-value + pair in the Data field of the referenced + Secret will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the Secret, the volume setup will error + unless it is marked optional. Paths must + be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether + the Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the + secret in the pod''s namespace to use. More + info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret + to use for obtaining the StorageOS API credentials. If + not specified, default values will be attempted. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable + name of the StorageOS volume. Volume names + are only unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the + scope of the volume within StorageOS. If + no namespace is specified then the Pod's + namespace will be used. This allows the + Kubernetes name scoping to be mirrored within + StorageOS for tighter integration. Set VolumeName + to any name to override the default behaviour. + Set to "default" if you are not using namespaces + within StorageOS. Namespaces that do not + pre-exist within StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere + volume attached and mounted on kubelets host + machine + properties: + fsType: + description: fsType is filesystem type to + mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage + Policy Based Management (SPBM) profile ID + associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage + Policy Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + templateType: + type: string + timeChaos: + description: TimeChaosSpec defines the desired state of + TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id + All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected + program. It's a possibly signed sequence of decimal + numbers, such as "300ms", "-1.5h" or "2h45m". Valid + time units are "ns", "us" (or "µs"), "ms", "s", "m", + "h". + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + required: + - name + - templateType + type: object + type: array + required: + - entry + - templates + type: object + required: + - schedule + - type + type: object + status: + description: ScheduleStatus is the status of a schedule object + properties: + active: + items: + description: "ObjectReference contains enough information to let + you inspect or modify the referred object. --- New uses of this + type are discouraged because of difficulty describing its usage + when embedded in APIs. 1. Ignored fields. It includes many fields + which are not generally honored. For instance, ResourceVersion + and FieldPath are both very rarely valid in actual usage. 2. Invalid + usage help. It is impossible to add specific help for individual + usage. In most embedded usages, there are particular restrictions + like, \"must refer only to types A and B\" or \"UID not honored\" + or \"name must be restricted\". Those cannot be well described + when embedded. 3. Inconsistent validation. Because the usages + are different, the validation rules are different by usage, which + makes it hard for users to predict what will happen. 4. The fields + are both imprecise and overly precise. Kind is not a precise + mapping to a URL. This can produce ambiguity during interpretation + and require a REST mapping. In most cases, the dependency is + on the group,resource tuple and the version of the actual struct + is irrelevant. 5. We cannot easily change it. Because this type + is embedded in many locations, updates to this type will affect + numerous schemas. Don't make new APIs embed an underspecified + API type they do not control. \n Instead of using this type, create + a locally provided and used type that is well-focused on your + reference. For example, ServiceReferences for admission registration: + https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + time: + format: date-time + nullable: true + type: string + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_statuschecks.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_statuschecks.yaml new file mode 100644 index 0000000000..dcea06ed85 --- /dev/null +++ b/helm/chaos-mesh/crds/chaos-mesh.org_statuschecks.yaml @@ -0,0 +1,195 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: statuschecks.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: StatusCheck + listKind: StatusCheckList + plural: statuschecks + singular: statuscheck + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a status check + properties: + duration: + description: Duration defines the duration of the whole status check + if the number of failed execution does not exceed the failure threshold. + Duration is available to both `Synchronous` and `Continuous` mode. + 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum consecutive failure + for the status check to be considered failed. + minimum: 1 + type: integer + http: + properties: + body: + type: string + criteria: + description: Criteria defines how to determine the result of the + status check. + properties: + statusCode: + description: StatusCode defines the expected http status code + for the request. A statusCode string could be a single code + (e.g. 200), or an inclusive range (e.g. 200-400, both `200` + and `400` are included). + type: string + required: + - statusCode + type: object + headers: + additionalProperties: + items: + type: string + type: array + description: "A Header represents the key-value pairs in an HTTP + header. \n The keys should be in canonical form, as returned + by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in seconds) to perform + an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of the status check. + Support type: Synchronous / Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number of record to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum consecutive successes + for the status check to be considered successful. SuccessThreshold + only works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of seconds after which + an execution of status check times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check type. Support + type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + status: + description: Most recently observed status of status check + properties: + completionTime: + description: CompletionTime represents time when the status check + was completed. + format: date-time + type: string + conditions: + description: Conditions represents the latest available observations + of a StatusCheck's current state. + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - lastProbeTime + - lastTransitionTime + - reason + - status + - type + type: object + type: array + count: + description: Count represents the total number of the status check + executed. + format: int64 + type: integer + records: + description: Records contains the history of the execution of StatusCheck. + items: + properties: + outcome: + type: string + startTime: + format: date-time + type: string + required: + - outcome + - startTime + type: object + type: array + startTime: + description: StartTime represents time when the status check started + to execute. + format: date-time + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_stresschaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_stresschaos.yaml index bc95de3e81..1763c201ed 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_stresschaos.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_stresschaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: stresschaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,296 +12,333 @@ spec: listKind: StressChaosList plural: stresschaos singular: stresschaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: StressChaos is the Schema for the stresschaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a time chaos experiment - properties: - containerName: - description: ContainerName indicates the target container to inject - stress in - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + versions: + - additionalPrinterColumns: + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: StressChaos is the Schema for the stresschaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a time chaos experiment + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - stressngStressors: - description: StressngStressors defines plenty of stressors just like - `Stressors` except that it's an experimental feature and more powerful. - You can define stressors in `stress-ng` (see also `man stress-ng`) - dialect, however not all of the supported stressors are well tested. - It maybe retired in later releases. You should always use `Stressors` - to define the stressors and use this only when you want more stressors - unsupported by `Stressors`. When both `StressngStressors` and `Stressors` - are defined, `StressngStressors` wins. - type: string - stressors: - description: Stressors defines plenty of stressors supported to stress - system components out. You can use one or more of them to make up - various kinds of stresses. At least one of the stressors should be - specified. - properties: - cpu: - description: CPUStressor stresses CPU out - properties: - load: - description: Load specifies P percent loading per CPU worker. - 0 is effectively a sleep (no load) and 100 is full loading. - type: integer - options: - description: extend stress-ng options - items: - type: string - type: array - workers: - description: Workers specifies N workers to apply the stressor. - type: integer - required: - - workers - type: object - memory: - description: MemoryStressor stresses virtual memory out - properties: - options: - description: extend stress-ng options + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: items: type: string type: array - size: - description: Size specifies N bytes consumed per vm worker, - default is the total available memory. One can specify the - size as % of total available memory or in units of B, KB/KiB, - MB/MiB, GB/GiB, TB/TiB. - type: string - workers: - description: Workers specifies N workers to apply the stressor. - type: integer - required: - - workers - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the % of pods to do chaos action - type: string - required: - - mode - - selector - type: object - status: - description: Most recently observed status of the time chaos experiment - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors just like + `Stressors` except that it's an experimental feature and more powerful. + You can define stressors in `stress-ng` (see also `man stress-ng`) + dialect, however not all of the supported stressors are well tested. + It maybe retired in later releases. You should always use `Stressors` + to define the stressors and use this only when you want more stressors + unsupported by `Stressors`. When both `StressngStressors` and `Stressors` + are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported to stress + system components out. You can use one or more of them to make up + various kinds of stresses. At least one of the stressors should + be specified. + properties: + cpu: + description: CPUStressor stresses CPU out properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + load: + description: Load specifies P percent loading per CPU worker. + 0 is effectively a sleep (no load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to apply the stressor. + Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj of the stress + process. See `man 5 proc` to know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per vm worker, + default is the total available memory. One can specify the + size as % of total available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB. type: string + workers: + description: Workers specifies N workers to apply the stressor. + Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer required: - - action - - hostIP - - name - - namespace - - podIP + - workers type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - instances: - additionalProperties: - description: StressInstance is an instance generates stresses + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - mode + - selector + type: object + status: + description: Most recently observed status of the time chaos experiment + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. properties: - startTime: - description: StartTime specifies when the instance starts - format: date-time - type: string - uid: - description: UID is the instance identifier + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop type: string type: object - description: Instances always specifies stressing instances - type: object - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + instances: + additionalProperties: + description: StressInstance is an instance generates stresses + properties: + memoryStartTime: + description: MemoryStartTime specifies when the memStress starts + format: date-time + type: string + memoryUid: + description: MemoryUID is the memStress identifier + type: string + startTime: + description: StartTime specifies when the stress-ng starts + format: date-time + type: string + uid: + description: UID is the stress-ng identifier + type: string + type: object + description: Instances always specifies stressing instances + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_timechaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_timechaos.yaml index 2f9ef0472d..8cb96a39ef 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_timechaos.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_timechaos.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: timechaos.chaos-mesh.org spec: group: chaos-mesh.org @@ -14,250 +12,259 @@ spec: listKind: TimeChaosList plural: timechaos singular: timechaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: TimeChaos is the Schema for the timechaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a time chaos experiment - properties: - clockIds: - description: ClockIds defines all affected clock id All available options - are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", - "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", - "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] - items: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: TimeChaos is the Schema for the timechaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a time chaos experiment + properties: + clockIds: + description: ClockIds defines all affected clock id All available + options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action type: string - type: array - containerNames: - description: ContainerName indicates the name of affected container. - If not set, all containers will be injected - items: + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent type: string - type: array - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - timeOffset: - description: TimeOffset defines the delta time of injected program. - It's a possibly signed sequence of decimal numbers, such as "300ms", - "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", - "s", "m", "h". - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - mode - - selector - - timeOffset - type: object - status: - description: Most recently observed status of the time chaos experiment - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + timeOffset: + description: TimeOffset defines the delta time of injected program. + It's a possibly signed sequence of decimal numbers, such as "300ms", + "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", + "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + status: + description: Most recently observed status of the time chaos experiment + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_workflownodes.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_workflownodes.yaml index ae77ef307b..03d8dfb41b 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_workflownodes.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_workflownodes.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: workflownodes.chaos-mesh.org spec: group: chaos-mesh.org @@ -16,2078 +14,20573 @@ spec: shortNames: - wfn singular: workflownode - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a node of workflow - properties: - aws_chaos: - description: AwsChaosSpec is the content of the specification for an - AwsChaos - properties: - action: - description: 'Action defines the specific aws chaos action. Supported - action: ec2-stop / ec2-restart / detach-volume Default action: - ec2-stop' - enum: - - ec2-stop - - ec2-restart - - detach-volume - type: string - awsRegion: - description: AwsRegion defines the region of aws. - type: string - deviceName: - description: DeviceName indicates the name of the device. Needed - in detach-volume. - type: string - duration: - description: Duration represents the duration of the chaos action. - type: string - ec2Instance: - description: Ec2Instance indicates the ID of the ec2 instance. - type: string - endpoint: - description: Endpoint indicates the endpoint of the aws server. - Just used it in test now. - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. - type: string - volumeID: - description: EbsVolume indicates the ID of the EBS volume. Needed - in detach-volume. - type: string - required: - - action - - awsRegion - - ec2Instance - type: object - deadline: - format: date-time - type: string - dns_chaos: - description: DNSChaosSpec defines the desired state of DNSChaos - properties: - action: - description: 'Action defines the specific DNS chaos action. Supported - action: error, random Default action: error' - enum: - - error - - random - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - patterns: - description: "Choose which domain names to take effect, support - the placeholder ? and wildcard *, or the Specified domain name. - Note: 1. The wildcard * must be at the end of the string. - For example, chaos-*.org is invalid. 2. if the patterns is - empty, will take effect on all the domain names. For example: - \t\tThe value is [\"google.com\", \"github.*\", \"chaos-mes?.org\"], - \t\twill take effect on \"google.com\", \"github.com\" and \"chaos-mesh.org\"" - items: - type: string - type: array - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - action - - mode - - selector - type: object - gcp_chaos: - description: GcpChaosSpec is the content of the specification for a - GcpChaos - properties: - action: - description: 'Action defines the specific gcp chaos action. Supported - action: node-stop / node-reset / disk-loss Default action: node-stop' - enum: - - node-stop - - node-reset - - disk-loss - type: string - deviceName: - description: The device name of the disk to detach. Needed in disk-loss. - type: string - duration: - description: Duration represents the duration of the chaos action. - type: string - instance: - description: Instance defines the name of the instance - type: string - project: - description: Project defines the name of gcp project. - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a node of workflow + properties: + abortWithStatusCheck: + description: AbortWithStatusCheck describe whether to abort the workflow + when the failure threshold of StatusCheck is exceeded. Only used + when Type is TypeStatusCheck. + type: boolean + awsChaos: + description: AWSChaosSpec is the content of the specification for + an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. Supported + action: ec2-stop / ec2-restart / detach-volume Default action: + ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. Needed + in detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws server. + Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. Needed + in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification for + an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. + Supported action: vm-stop / vm-restart / disk-detach Default + action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. Needed in + disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the data + disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification for + a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. + Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. It - is used for GCP credentials. - type: string - zone: - description: Zone defines the zone of gcp project. - type: string - required: - - action - - instance - - project - - zone - type: object - http_chaos: - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: delay | abort | mixed Default action: delay' - enum: - - delay - - abort - - mixed - type: string - duration: - description: Duration represents the duration of the chaos action. - It is required when the action is `PodFailureAction`. 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". - type: string - headers: - description: Specifies how the header match will be performed to - route the request. - items: + type: array + delay: + description: Delay defines the delay distribution. properties: - exact_match: - type: string - invert_match: - type: string - name: - type: string - prefix_match: - type: string - present_match: - type: string - range_match: - type: string - regex_match: + correlation: type: string - safe_regex_match: + jitter: type: string - suffix_match: + latency: + description: Latency defines the latency of every io request. type: string - required: - - name type: object - type: array - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - percent: - description: 'Percent defines the percentage of injection errors - and provides a number from 0-100. default: 100.' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: + duration: + description: Duration represents the duration of the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - action - - mode - - selector - type: object - io_chaos: - description: IoChaosSpec defines the desired state of IoChaos - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: latency / fault / attrOverride / mistake' - enum: - - latency - - fault - - attrOverride - - mistake - type: string - attr: - description: Attr defines the overrided attribution - properties: - atime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - blocks: - format: int64 - type: integer - ctime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - gid: - format: int32 - type: integer - ino: - format: int64 - type: integer - kind: - description: FileType represents type of a file - type: string - mtime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - nlink: - format: int32 - type: integer - perm: - type: integer - rdev: - format: int32 - type: integer - size: - format: int64 - type: integer - uid: - format: int32 - type: integer - type: object - containerName: - description: ContainerName indicates the target container to inject - iochaos in - type: string - delay: - description: Delay defines the value of I/O chaos action delay. - A delay string is a possibly signed sequence of decimal numbers, - each with optional fraction and a unit suffix, such as "300ms". - Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - type: string - duration: - description: Duration represents the duration of the chaos action. - It is required when the action is `PodFailureAction`. 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". - type: string - errno: - description: 'Errno defines the error code that returned by I/O - action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' - format: int32 - type: integer - methods: - description: 'Methods defines the I/O methods for injecting I/O - chaos action. default: all I/O methods.' - items: - type: string - type: array - mistake: - description: Mistake defines what types of incorrectness are injected - to IO operations - properties: - filling: - description: Filling determines what is filled in the miskate - data. - enum: - - zero - - random - type: string - maxLength: - description: Max length of each wrong data segment in bytes - format: int64 - minimum: 1 - type: integer - maxOccurrences: - description: There will be [1, MaxOccurrences] segments of wrong - data. - format: int64 - minimum: 1 - type: integer - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - path: - description: Path defines the path of files for injecting I/O chaos - action. - type: string - percent: - description: 'Percent defines the percentage of injection errors - and provides a number from 0-100. default: 100.' - type: integer - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - volumePath: - description: VolumePath represents the mount path of injected volume - type: string - required: - - action - - mode - - selector - - volumePath - type: object - jvm_chaos: - description: JVMChaosSpec defines the desired state of JVMChaos - properties: - action: - description: 'Action defines the specific jvm chaos action. Supported - action: delay;return;script;cfl;oom;ccf;tce;cpf;tde;tpf' - enum: - - delay - - return - - script - - cfl - - oom - - ccf - - tce - - cpf - - tde - - tpf - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - flags: - additionalProperties: + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action type: string - description: Flags represents the flags of action - type: object - matchers: - additionalProperties: + volumeName: type: string - description: Matchers represents the matching rules for the target - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' + required: + - action + - mode + - selector + - volumeName + type: object + children: + items: type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. + type: array + conditionalBranches: + items: properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + expression: + description: Expression is the expression for this conditional + branch, expected type of result is boolean. If expression + is empty, this branch will always be selected/the template + will be spawned. + type: string + target: + description: Target is the name of other template, if expression + is evaluated as true, this template will be spawned. type: string required: - - cron + - target type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: + type: array + deadline: + format: date-time + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos action. Supported + action: error, random Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, support + the placeholder ? and wildcard *, or the Specified domain name. + Note: 1. The wildcard * must be at the end of the string. For + example, chaos-*.org is invalid. 2. if the patterns is empty, + will take effect on all the domain names. For example: The value + is ["google.com", "github.*", "chaos-mes?.org"], will take effect + on "google.com", "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - target: - description: 'Target defines the specific jvm chaos target. Supported - target: servlet;psql;jvm;jedis;http;dubbo;rocketmq;tars;mysql;druid;redisson;rabbitmq;mongodb' - enum: - - servlet - - psql - - jvm - - jedis - - http - - dubbo - - rocketmq - - tars - - mysql - - druid - - redisson - - rabbitmq - - mongodb - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the % of pods to do chaos action - type: string - required: - - action - - mode - - selector - - target - type: object - kernel_chaos: - description: KernelChaosSpec defines the desired state of KernelChaos - properties: - duration: - description: Duration represents the duration of the chaos action - type: string - failKernRequest: - description: FailKernRequest defines the request of kernel injection - properties: - callchain: - description: 'Callchain indicate a special call chain, such - as: ext4_mount -> mount_subtree -> ... -> - should_failslab With an optional set of predicates and an - optional set of parameters, which used with predicates. You - can read call chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples - to learn more. If no special call chain, just keep Callchain - empty, which means it will fail at any call chain with slab - alloc (eg: kmalloc).' - items: - description: Frame defines the function signature and predicate - in function's body - properties: - funcname: - description: Funcname can be find from kernel source or - `/proc/kallsyms`, such as `ext4_mount` - type: string - parameters: - description: Parameters is used with predicate, for example, - if you want to inject slab error in `d_alloc_parallel(struct - dentry *parent, const struct qstr *name)` with a special - name `bananas`, you need to set it to `struct dentry - *parent, const struct qstr *name` otherwise omit it. - type: string - predicate: - description: Predicate will access the arguments of this - Frame, example with Parameters's, you can set it to - `STRNCMP(name->name, "bananas", 8)` to make inject only - with it, or omit it to inject for all d_alloc_parallel - call chain. - type: string - type: object - type: array - failtype: - description: 'FailType indicates what to fail, can be set to - ''0'' / ''1'' / ''2'' If `0`, indicates slab to fail (should_failslab) - If `1`, indicates alloc_page to fail (should_fail_alloc_page) - If `2`, indicates bio to fail (should_fail_bio) You can read: 1. - https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html 2. - http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt - to learn more' - format: int32 - maximum: 2 - minimum: 0 - type: integer - headers: - description: 'Headers indicates the appropriate kernel headers - you need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so on' - items: - type: string - type: array - probability: - description: Probability indicates the fails with probability. - If you want 1%, please set this field with 1. - format: int32 - maximum: 100 - minimum: 0 - type: integer - times: - description: Times indicates the max times of fails. - format: int32 - minimum: 0 - type: integer - required: - - failtype - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - failKernRequest - - mode - - selector - type: object - network_chaos: - description: NetworkChaosSpec defines the desired state of NetworkChaos - properties: - action: - description: 'Action defines the specific network chaos action. - Supported action: partition, netem, delay, loss, duplicate, corrupt - Default action: delay' - enum: - - netem - - delay - - loss - - duplicate - - corrupt - - partition - - bandwidth - type: string - bandwidth: - description: Bandwidth represents the detail about bandwidth control - action - properties: - buffer: - description: Buffer is the maximum amount of bytes that tokens - can be available for instantaneously. - format: int32 - minimum: 1 - type: integer - limit: - description: Limit is the number of bytes that can be queued - waiting for tokens to become available. - format: int32 - minimum: 1 - type: integer - minburst: - description: Minburst specifies the size of the peakrate bucket. - For perfect accuracy, should be set to the MTU of the interface. If - a peakrate is needed, but some burstiness is acceptable, this - size can be raised. A 3000 byte minburst allows around 3mbit/s - of peakrate, given 1000 byte packets. - format: int32 - minimum: 0 - type: integer - peakrate: - description: Peakrate is the maximum depletion rate of the bucket. - The peakrate does not need to be set, it is only necessary - if perfect millisecond timescale shaping is required. - format: int64 - minimum: 0 - type: integer - rate: - description: Rate is the speed knob. Allows bps, kbps, mbps, - gbps, tbps unit. bps means bytes per second. - type: string - required: - - buffer - - limit - - rate - type: object - corrupt: - description: Corrupt represents the detail about corrupt action - properties: - correlation: - type: string - corrupt: - type: string - required: - - correlation - - corrupt - type: object - delay: - description: Delay represents the detail about delay action - properties: - correlation: - type: string - jitter: - type: string - latency: + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification for + a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. Supported + action: node-stop / node-reset / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed in disk-loss. + items: type: string - reorder: - description: ReorderSpec defines details of packet reorder. - properties: - correlation: + type: array + duration: + description: Duration represents the duration of the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status code + in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, such + as "300ms", "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + method: + description: Method is a rule to select target by http method + in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of target. + properties: + type: + description: Type represents the patch type, only support + `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers of + target. For example: `[["Set-Cookie", ""], ["Set-Cookie", + ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries of target(Request + only). For example: `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri path in http + request. + type: string + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents in target. + properties: + body: + description: Body is a rule to replace http message body in + target. + format: byte + type: string + code: + description: Code is a rule to replace http status code in + response. + format: int32 + type: integer + headers: + additionalProperties: type: string - gap: - type: integer - reorder: + description: Headers is a rule to replace http headers of + target. The key-value pairs represent header name and header + value pairs. + type: object + method: + description: Method is a rule to replace http method in request. + type: string + path: + description: Path is rule to to replace uri path in http request. + type: string + queries: + additionalProperties: type: string - required: - - correlation - - gap - - reorder - type: object - required: - - latency - type: object - direction: - description: Direction represents the direction, this applies on - netem and network partition action - enum: - - to - - from - - both - - "" - type: string - duplicate: - description: DuplicateSpec represents the detail about loss action - properties: - correlation: - type: string - duplicate: - type: string - required: - - correlation - - duplicate - type: object - duration: - description: Duration represents the duration of the chaos action - type: string - externalTargets: - description: ExternalTargets represents network targets outside - k8s - items: - type: string - type: array - loss: - description: Loss represents the detail about loss action - properties: - correlation: - type: string - loss: + description: 'Queries is a rule to replace uri queries in + http request. For example, with value `{ "foo": "unknown" + }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: type: string - required: - - correlation - - loss - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + description: RequestHeaders is a rule to select target by http + headers in request. The key-value pairs represent header name + and header value pairs. + type: object + response_headers: + additionalProperties: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: + description: ResponseHeaders is a rule to select target by http + headers in response. The key-value pairs represent header name + and header value pairs. + type: object + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. type: object - type: array - fieldSelectors: - additionalProperties: + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file in + secret, `ca.crt` for example type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: + certName: + description: CertName represents the data name of cert file + in secret, `tls.crt` for example type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: + keyName: + description: KeyName represents the data name of key file + in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required secret + resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace of required + secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action delay. + A delay string is a possibly signed sequence of decimal numbers, + each with optional fraction and a unit suffix, such as "300ms". + Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that returned by I/O + action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting I/O + chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness are injected + to IO operations + properties: + filling: + description: Filling determines what is filled in the mistake + data. + enum: + - zero + - random type: string - type: array - pods: - additionalProperties: + maxLength: + description: Max length of each wrong data segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments of + wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting I/O + chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection errors + and provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - target: - description: Target represents network target, this applies on netem - and network partition action - properties: - mode: - description: TargetMode defines the target selector mode - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - - "" + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected + volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. Supported + action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - selector: - description: TargetSelector defines the target selector - properties: - annotationSelectors: - additionalProperties: + type: array + cpuCount: + description: the CPU core number needs to use, only set it when + action is stress + type: integer + database: + description: the match database default value is "", means match + all database + type: string + duration: + description: Duration represents the duration of the chaos action + type: string + exception: + description: the exception which needs to throw for action `exception` + or the exception message needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', unit ms + or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will generate + one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", means match + all SQL type. The value can be 'select', 'insert', 'update', + 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call chain, such + as: ext4_mount -> mount_subtree -> ... -> should_failslab + With an optional set of predicates and an optional set of + parameters, which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep Callchain + empty, which means it will fail at any call chain with slab + alloc (eg: kmalloc).' + items: + description: Frame defines the function signature and predicate + in function's body + properties: + funcname: + description: Funcname can be find from kernel source + or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, for + example, if you want to inject slab error in `d_alloc_parallel(struct + dentry *parent, const struct qstr *name)` with a special + name `bananas`, you need to set it to `struct dentry + *parent, const struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments of + this Frame, example with Parameters's, you can set + it to `STRNCMP(name->name, "bananas", 8)` to make + inject only with it, or omit it to inject for all + d_alloc_parallel call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be set + to ''0'' / ''1'' / ''2'' If `0`, indicates slab to fail + (should_failslab) If `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) You can + read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel headers + you need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so + on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos action. + Supported action: partition, netem, delay, loss, duplicate, + corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth control + action + properties: + buffer: + description: Buffer is the maximum amount of bytes that tokens + can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be queued + waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate bucket. + For perfect accuracy, should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness is acceptable, + this size can be raised. A 3000 byte minburst allows around + 3mbit/s of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of the + bucket. The peakrate does not need to be set, it is only + necessary if perfect millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies + on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets outside + k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this applies on + netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device to be + affected in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired state of + PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one of Address + and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock on which + to act. More clock description in linux kernel can be found + in man page of clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the file. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + delay: + description: Delay represents the delay of the target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for action + `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', unit + ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", means + match all database + type: string + exception: + description: The exception which needs to throw for action + `exception` or the exception message needs to throw in action + `mysql` + type: string + latency: + description: The latency duration for action 'latency' or + the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, will + use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set it + when action is stress + type: integer + mem-type: + description: the memory type need to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can + be accepted, others will be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf with + this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads to + run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP address + type: string + rate: + description: The speed of network traffic, allows bps, kbps, + mbps, gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can + be accepted, others will be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values can + be 'from', 'to'. 'from' means packets coming from the 'IPAddress' + or 'Hostname' and going to your server, 'to' means packets + originating from your server and going to the 'IPAddress' + or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of the original + value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string keys and + a set values that used to select physical machines. The + key defines the namespace which physical machine belong, + and each value is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. 0 + is effectively a sleep (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, default + is the total available memory. One can specify the size + as % of total available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify + the percent of physical machines the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify + the max percent of pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a user creates + on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: pod-kill / pod-failure / container-kill Default action: + pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It represents + the duration in seconds before the pod should be deleted. Value + must be non-negative integer. The default value is zero that + indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + description: ScheduleSpec is the specification of a schedule object + properties: + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. + Supported action: ec2-stop / ec2-restart / detach-volume + Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. + Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws server. + Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. + Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. + Supported action: vm-stop / vm-restart / disk-detach Default + action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. Needed + in disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the + data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. + Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every io request. + type: string + type: object + duration: + description: Duration represents the duration of the chaos + action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + default: Forbid + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos action. + Supported action: error, random Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, support + the placeholder ? and wildcard *, or the Specified domain + name. Note: 1. The wildcard * must be at the end of the + string. For example, chaos-*.org is invalid. 2. if the patterns + is empty, will take effect on all the domain names. For + example: The value is ["google.com", "github.*", "chaos-mes?.org"], + will take effect on "google.com", "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. + Supported action: node-stop / node-reset / disk-loss Default + action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed in + disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status + code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, + such as "300ms", "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + method: + description: Method is a rule to select target by http method + in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of target. + properties: + type: + description: Type represents the patch type, only + support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], + ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", "bar"], + ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri path in + http request. + type: string + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents in + target. + properties: + body: + description: Body is a rule to replace http message body + in target. + format: byte + type: string + code: + description: Code is a rule to replace http status code + in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header name + and header value pairs. + type: object + method: + description: Method is a rule to replace http method in + request. + type: string + path: + description: Path is rule to to replace uri path in http + request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": "unknown" + }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target by + http headers in request. The key-value pairs represent header + name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target by + http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file + in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name of cert + file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of key file + in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required + secret resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace + of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. + Supported action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action delay. + A delay string is a possibly signed sequence of decimal + numbers, each with optional fraction and a unit suffix, + such as "300ms". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos + action. It is required when the action is `PodFailureAction`. + 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". + type: string + errno: + description: 'Errno defines the error code that returned by + I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting + I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness are + injected to IO operations + properties: + filling: + description: Filling determines what is filled in the + mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment in + bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting + I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection + errors and provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected + volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. + Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only set it + when action is stress + type: integer + database: + description: the match database default value is "", means + match all database + type: string + duration: + description: Duration represents the duration of the chaos + action + type: string + exception: + description: the exception which needs to throw for action + `exception` or the exception message needs to throw in action + `mysql` + type: string + latency: + description: the latency duration for action 'latency', unit + ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it + when action is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will + generate one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel + injection + properties: + callchain: + description: 'Callchain indicate a special call chain, + such as: ext4_mount -> mount_subtree -> ... -> should_failslab + With an optional set of predicates and an optional set + of parameters, which used with predicates. You can read + call chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep Callchain + empty, which means it will fail at any call chain with + slab alloc (eg: kmalloc).' + items: + description: Frame defines the function signature and + predicate in function's body + properties: + funcname: + description: Funcname can be find from kernel source + or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab error + in `d_alloc_parallel(struct dentry *parent, const + struct qstr *name)` with a special name `bananas`, + you need to set it to `struct dentry *parent, + const struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments + of this Frame, example with Parameters's, you + can set it to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, or omit it to + inject for all d_alloc_parallel call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be + set to ''0'' / ''1'' / ''2'' If `0`, indicates slab + to fail (should_failslab) If `1`, indicates alloc_page + to fail (should_fail_alloc_page) If `2`, indicates bio + to fail (should_fail_bio) You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel + headers you need. Eg: "linux/mmzone.h", "linux/blkdev.h" + and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos action. + Supported action: partition, netem, delay, loss, duplicate, + corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes that + tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be + queued waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate + bucket. For perfect accuracy, should be set to the MTU + of the interface. If a peakrate is needed, but some + burstiness is acceptable, this size can be raised. A + 3000 byte minburst allows around 3mbit/s of peakrate, + given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of + the bucket. The peakrate does not need to be set, it + is only necessary if perfect millisecond timescale shaping + is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, + mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies + on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss + action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos + action + type: string + externalTargets: + description: ExternalTargets represents network targets outside + k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control + action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, + mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + target: + description: Target represents network target, this applies + on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / + random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values + array must be non-empty. If the operator is + Exists or DoesNotExist, the values array must + be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines + the namespace which pods belong, and the each values + is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to + `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device to + be affected in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired state + of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one of + Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock on + which to act. More clock description in linux kernel + can be found in man page of clock_getres, clock_gettime, + clock_settime. Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. if + path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. if + path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. if + path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos + action + type: string + file-append: + properties: + count: + description: Count is the number of times to append the + data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create or + delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create or + delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the + file. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to be + replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside + proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + delay: + description: Delay represents the delay of the target + request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside + proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for action + `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', + unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", means + match all database + type: string + exception: + description: The exception which needs to throw for action + `exception` or the exception message needs to throw + in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' + or the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only + support 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, + will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set + it when action is stress + type: integer + mem-type: + description: the memory type need to locate, only set + it when action is stress, the value can be 'stack' or + 'heap' + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag + can be accepted, others will be dropped. only set when + the IPProtocol is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us (or + µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 is + 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads + to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP address + type: string + rate: + description: The speed of network traffic, allows bps, + kbps, mbps, gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag + can be accepted, others will be dropped. only set when + the IPProtocol is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values + can be 'from', 'to'. 'from' means packets coming from + the 'IPAddress' or 'Hostname' and going to your server, + 'to' means packets originating from your server and + going to the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of the + original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string keys + and a set values that used to select physical machines. + The key defines the namespace which physical machine + belong, and each value is a set of physical machine + names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. + 0 is effectively a sleep (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, + default is the total available memory. One can specify + the size as % of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify + the percent of physical machines the server can do chaos + action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a user creates + on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos action. + Supported action: pod-kill / pod-failure / container-kill + Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action. It is required when the action is `PodFailureAction`. + 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It represents + the duration in seconds before the pod should be deleted. + Value must be non-negative integer. The default value is + zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + exclusiveMinimum: true + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors + just like `Stressors` except that it's an experimental feature + and more powerful. You can define stressors in `stress-ng` + (see also `man stress-ng`) dialect, however not all of the + supported stressors are well tested. It maybe retired in + later releases. You should always use `Stressors` to define + the stressors and use this only when you want more stressors + unsupported by `Stressors`. When both `StressngStressors` + and `Stressors` are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported + to stress system components out. You can use one or more + of them to make up various kinds of stresses. At least one + of the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading per + CPU worker. 0 is effectively a sleep (no load) and + 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to apply + the stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj of + the stress process. See `man 5 proc` to know more + about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per vm + worker, default is the total available memory. One + can specify the size as % of total available memory + or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to apply + the stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id All available + options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected + program. It's a possibly signed sequence of decimal numbers, + such as "300ms", "-1.5h" or "2h45m". Valid time units are + "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + workflow: + properties: + entry: + type: string + templates: + items: + properties: + abortWithStatusCheck: + description: AbortWithStatusCheck describe whether to + abort the workflow when the failure threshold of StatusCheck + is exceeded. Only used when Type is TypeStatusCheck. + type: boolean + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos + action. Supported action: ec2-stop / ec2-restart + / detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the + device. Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the + ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of + the aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS + volume. Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure + chaos action. Supported action: vm-stop / vm-restart + / disk-detach Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the + disk. Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number + of the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name + of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure + subscription. + type: string + vmName: + description: VMName defines the name of Virtual + Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block + chaos action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of + every io request. + type: string + type: object + duration: + description: Duration represents the duration of + the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + children: + description: Children describes the children steps of + serial or parallel node. Only used when Type is TypeSerial + or TypeParallel. + items: + type: string + type: array + conditionalBranches: + description: ConditionalBranches describes the conditional + branches of custom tasks. Only used when Type is TypeTask. + items: + properties: + expression: + description: Expression is the expression for + this conditional branch, expected type of result + is boolean. If expression is empty, this branch + will always be selected/the template will be + spawned. + type: string + target: + description: Target is the name of other template, + if expression is evaluated as true, this template + will be spawned. + type: string + required: + - target + type: object + type: array + deadline: + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state + of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos + action. Supported action: error, random Default + action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take + effect, support the placeholder ? and wildcard + *, or the Specified domain name. Note: 1. The + wildcard * must be at the end of the string. For + example, chaos-*.org is invalid. 2. if the patterns + is empty, will take effect on all the domain names. + For example: The value is ["google.com", "github.*", + "chaos-mes?.org"], will take effect on "google.com", + "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos + action. Supported action: node-stop / node-reset + / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. + Needed in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by + http status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target + request/response. A duration string is a possibly + unsigned sequence of decimal numbers, each with + optional fraction and a unit suffix, such as "300ms", + "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + method: + description: Method is a rule to select target by + http method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. + properties: + body: + description: Body is a rule to patch message + body of target. + properties: + type: + description: Type represents the patch type, + only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http + headers of target. For example: `[["Set-Cookie", + ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri + queries of target(Request only). For example: + `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by + uri path in http request. + type: string + port: + description: Port represents the target port to + be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http + message body in target. + format: byte + type: string + code: + description: Code is a rule to replace http + status code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http + headers of target. The key-value pairs represent + header name and header value pairs. + type: object + method: + description: Method is a rule to replace http + method in request. + type: string + path: + description: Path is rule to to replace uri + path in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri + queries in http request. For example, with + value `{ "foo": "unknown" }`, the `/?foo=bar` + will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select + target by http headers in request. The key-value + pairs represent header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select + target by http headers in response. The key-value + pairs represent header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected + and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override + PodHttpChaos if there are multiple HTTPChaos experiments + are applied + properties: + caName: + description: CAName represents the data name + of ca file in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name + of cert file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name + of key file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name + of required secret resource + type: string + secretNamespace: + description: SecretNamespace represents the + namespace of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of + IOChaos + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: latency / fault / attrOverride + / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos + action delay. A delay string is a possibly signed + sequence of decimal numbers, each with optional + fraction and a unit suffix, such as "300ms". Valid + time units are "ns", "us" (or "µs"), "ms", "s", + "m", "h". + type: string + duration: + description: Duration represents the duration of + the chaos action. It is required when the action + is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that + returned by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for + injecting I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled + in the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment + in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] + segments of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for + injecting I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of + injection errors and provides a number from 0-100. + default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path + of injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state + of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos + action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only + set it when action is stress + type: integer + database: + description: the match database default value is + "", means match all database + type: string + duration: + description: Duration represents the duration of + the chaos action + type: string + exception: + description: the exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only + set it when action is stress, the value can be + 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set to + "8") now + type: string + name: + description: byteman rule name, should be unique, + and will generate one if not set + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action + 'ruleData' + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is + "", means match all SQL type. The value can be + 'select', 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", + means match all table + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state + of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request + of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call + chain, such as: ext4_mount -> mount_subtree + -> ... -> should_failslab With an optional + set of predicates and an optional set of parameters, + which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just + keep Callchain empty, which means it will + fail at any call chain with slab alloc (eg: + kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from + kernel source or `/proc/kallsyms`, such + as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab + error in `d_alloc_parallel(struct dentry + *parent, const struct qstr *name)` with + a special name `bananas`, you need to + set it to `struct dentry *parent, const + struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the + arguments of this Frame, example with + Parameters's, you can set it to `STRNCMP(name->name, + "bananas", 8)` to make inject only with + it, or omit it to inject for all d_alloc_parallel + call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, + can be set to ''0'' / ''1'' / ''2'' If `0`, + indicates slab to fail (should_failslab) If + `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) + You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails + with probability. If you want 1%, please set + this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of + fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + name: + type: string + networkChaos: + description: NetworkChaosSpec defines the desired state + of NetworkChaos + properties: + action: + description: 'Action defines the specific network + chaos action. Supported action: partition, netem, + delay, loss, duplicate, corrupt Default action: + delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about + bandwidth control action + properties: + buffer: + description: Buffer is the maximum amount of + bytes that tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that + can be queued waiting for tokens to become + available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of + the peakrate bucket. For perfect accuracy, + should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness + is acceptable, this size can be raised. A + 3000 byte minburst allows around 3mbit/s of + peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion + rate of the bucket. The peakrate does not + need to be set, it is only necessary if perfect + millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about + corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay + action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of + packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device + to be affected. + type: string + direction: + default: to + description: Direction represents the direction, + this applies on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail + about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of + the chaos action + type: string + externalTargets: + description: ExternalTargets represents network + targets outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss + action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate + control action + properties: + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this + applies on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network + device to be affected in target scope. + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired + state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. + Only one of Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular + clock on which to act. More clock description + in linux kernel can be found in man page of + clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 is + valid value + type: integer + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 is + valid value + type: integer + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of + the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to + append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to + create or delete. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to + create or delete. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + privilege: + description: Privilege is the file privilege + to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to + be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string + of the file. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + line: + description: Line is the line number of the + file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string + of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of + HTTP connection, we will only attack HTTP + connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + delay: + description: Delay represents the delay of the + target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of + HTTP connection, we will only attack HTTP + connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support + GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw + for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action + 'latency', unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value + is "", means match all database + type: string + exception: + description: The exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action + 'latency' or the latency duration in action + `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set + to "8") now + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value + is "", means match all SQL type. The value + can be 'select', 'insert', 'update', 'delete', + 'replace'. + type: string + table: + description: the match table default value is + "", means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule + file's data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, + only set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, + only set it when action is stress, the value + can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the + tcp flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used + for partition. + type: string + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: + ns, us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the + iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client + threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on + the IP address + type: string + rate: + description: The speed of network traffic, allows + bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the + tcp flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used + for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means packets + coming from the 'IPAddress' or 'Hostname' + and going to your server, 'to' means packets + originating from your server and going to + the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these + IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process + ID + type: string + recoverCmd: + description: the command to be run when recovering + experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical + machines that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string + keys and a set values that used to select + physical machines. The key defines the namespace + which physical machine belong, and each value + is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per + CPU worker. 0 is effectively a sleep (no load) + and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the + stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per + vm worker, default is the total available + memory. One can specify the size as % of total + available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when + attack + type: string + recoverCmd: + description: The command to be executed when + recover + type: string + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of physical + machines to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent + of physical machines the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do + chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that + a user creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: pod-kill / pod-failure + / container-kill Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action. It is required when the action + is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. + It represents the duration in seconds before the + pod should be deleted. Value must be non-negative + integer. The default value is zero that indicates + delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + description: Schedule describe the Schedule(describing + scheduled chaos) to be injected with chaos nodes. + Only used when Type is TypeSchedule. + properties: + awsChaos: + description: AWSChaosSpec is the content of the + specification for an AWSChaos + properties: + action: + description: 'Action defines the specific aws + chaos action. Supported action: ec2-stop / + ec2-restart / detach-volume Default action: + ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of + aws. + type: string + deviceName: + description: DeviceName indicates the name of + the device. Needed in detach-volume. + type: string + duration: + description: Duration represents the duration + of the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of + the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint + of the aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of + kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the + EBS volume. Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the + specification for an AzureChaos + properties: + action: + description: 'Action defines the specific azure + chaos action. Supported action: vm-stop / + vm-restart / disk-detach Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of + the disk. Needed in disk-detach. + type: string + duration: + description: Duration represents the duration + of the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit + Number of the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name + of ResourceGroup + type: string + secretName: + description: SecretName defines the name of + kubernetes secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of + Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual + Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the + specification for a BlockChaos + properties: + action: + description: 'Action defines the specific block + chaos action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency + of every io request. + type: string + type: object + duration: + description: Duration represents the duration + of the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state + of DNSChaos + properties: + action: + description: 'Action defines the specific DNS + chaos action. Supported action: error, random + Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take + effect, support the placeholder ? and wildcard + *, or the Specified domain name. Note: 1. + The wildcard * must be at the end of the string. + For example, chaos-*.org is invalid. 2. if + the patterns is empty, will take effect on + all the domain names. For example: The value + is ["google.com", "github.*", "chaos-mes?.org"], + will take effect on "google.com", "github.com" + and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the + specification for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp + chaos action. Supported action: node-stop + / node-reset / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. + Needed in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action. + type: string + instance: + description: Instance defines the name of the + instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of + kubernetes secret. It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http + session. + type: boolean + code: + description: Code is a rule to select target + by http status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the + target request/response. A duration string + is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a + unit suffix, such as "300ms", "2h45m". Valid + time units are "ns", "us" (or "µs"), "ms", + "s", "m", "h". + type: string + duration: + description: Duration represents the duration + of the chaos action. + type: string + method: + description: Method is a rule to select target + by http method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. + properties: + body: + description: Body is a rule to patch message + body of target. + properties: + type: + description: Type represents the patch + type, only support `JSON` as [merge + patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append + http headers of target. For example: `[["Set-Cookie", + ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append + uri queries of target(Request only). For + example: `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target + by uri path in http request. + type: string + port: + description: Port represents the target port + to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some + contents in target. + properties: + body: + description: Body is a rule to replace http + message body in target. + format: byte + type: string + code: + description: Code is a rule to replace http + status code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace + http headers of target. The key-value + pairs represent header name and header + value pairs. + type: object + method: + description: Method is a rule to replace + http method in request. + type: string + path: + description: Path is rule to to replace + uri path in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace + uri queries in http request. For example, + with value `{ "foo": "unknown" }`, the + `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select + target by http headers in request. The key-value + pairs represent header name and header value + pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select + target by http headers in response. The key-value + pairs represent header name and header value + pairs. + type: object + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + target: + description: Target is the object to be selected + and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override + PodHttpChaos if there are multiple HTTPChaos + experiments are applied + properties: + caName: + description: CAName represents the data + name of ca file in secret, `ca.crt` for + example + type: string + certName: + description: CertName represents the data + name of cert file in secret, `tls.crt` + for example + type: string + keyName: + description: KeyName represents the data + name of key file in secret, `tls.key` + for example + type: string + secretName: + description: SecretName represents the name + of required secret resource + type: string + secretNamespace: + description: SecretNamespace represents + the namespace of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state + of IOChaos + properties: + action: + description: 'Action defines the specific pod + chaos action. Supported action: latency / + fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of + file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O + chaos action delay. A delay string is a possibly + signed sequence of decimal numbers, each with + optional fraction and a unit suffix, such + as "300ms". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration + of the chaos action. It is required when the + action is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that + returned by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods + for injecting I/O chaos action. default: all + I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is + filled in the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data + segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] + segments of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files + for injecting I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage + of injection errors and provides a number + from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount + path of injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state + of JVMChaos + properties: + action: + description: 'Action defines the specific jvm + chaos action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, + only set it when action is stress + type: integer + database: + description: the match database default value + is "", means match all database + type: string + duration: + description: Duration represents the duration + of the chaos action + type: string + exception: + description: the exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action + 'latency', unit ms or the latency duration + in action `mysql` + type: integer + memType: + description: the memory type needs to locate, + only set it when action is stress, the value + can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set + to "8") now + type: string + name: + description: byteman rule name, should be unique, + and will generate one if not set + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action + 'ruleData' + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + sqlType: + description: the match sql type default value + is "", means match all SQL type. The value + can be 'select', 'insert', 'update', 'delete', + 'replace'. + type: string + table: + description: the match table default value is + "", means match all table + type: string + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired + state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request + of kernel injection + properties: + callchain: + description: 'Callchain indicate a special + call chain, such as: ext4_mount -> mount_subtree + -> ... -> should_failslab With an optional + set of predicates and an optional set + of parameters, which used with predicates. + You can read call chan and predicate examples + from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, + just keep Callchain empty, which means + it will fail at any call chain with slab + alloc (eg: kmalloc).' + items: + description: Frame defines the function + signature and predicate in function's + body + properties: + funcname: + description: Funcname can be find + from kernel source or `/proc/kallsyms`, + such as `ext4_mount` + type: string + parameters: + description: Parameters is used with + predicate, for example, if you want + to inject slab error in `d_alloc_parallel(struct + dentry *parent, const struct qstr + *name)` with a special name `bananas`, + you need to set it to `struct dentry + *parent, const struct qstr *name` + otherwise omit it. + type: string + predicate: + description: Predicate will access + the arguments of this Frame, example + with Parameters's, you can set it + to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, + or omit it to inject for all d_alloc_parallel + call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to + fail, can be set to ''0'' / ''1'' / ''2'' + If `0`, indicates slab to fail (should_failslab) + If `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) + You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails + with probability. If you want 1%, please + set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times + of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired + state of NetworkChaos + properties: + action: + description: 'Action defines the specific network + chaos action. Supported action: partition, + netem, delay, loss, duplicate, corrupt Default + action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail + about bandwidth control action + properties: + buffer: + description: Buffer is the maximum amount + of bytes that tokens can be available + for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes + that can be queued waiting for tokens + to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size + of the peakrate bucket. For perfect accuracy, + should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness + is acceptable, this size can be raised. + A 3000 byte minburst allows around 3mbit/s + of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion + rate of the bucket. The peakrate does + not need to be set, it is only necessary + if perfect millisecond timescale shaping + is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, + mbps, gbps, tbps unit. bps means bytes + per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about + corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about + delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details + of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device + to be affected. + type: string + direction: + default: to + description: Direction represents the direction, + this applies on netem and network partition + action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail + about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration + of the chaos action + type: string + externalTargets: + description: ExternalTargets represents network + targets outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about + loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about + rate control action + properties: + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, + mbps, gbps, tbps unit. bps means bytes + per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + target: + description: Target represents network target, + this applies on netem and network partition + action + properties: + mode: + description: 'Mode defines the mode to run + chaos action. Supported mode: one / all + / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select + pods that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and + values that can be used to select + objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector + expressions that can be used to select + objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and + values that can be used to select + objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and + values that can be used to select + objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of + namespace to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and + values that can be used to select + nodes. Selector which must match a + node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node + name and objects must belong to these + nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a + set of condition of a pod at the current + time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string + keys and a set values that used to + select pods. The key defines the namespace + which pods belong, and the each values + is a set of pod names. + type: object + type: object + value: + description: Value is required when the + mode is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent + of pods the server can do chaos action. + IF `RandomMaxPercentMode`, provide a + number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network + device to be affected in target scope. + type: string + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the + desired state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. + Only one of Address and Selector could be + specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular + clock on which to act. More clock description + in linux kernel can be found in man page + of clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time + offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill + data in. if path not provided, payload + will read/write from/into a temp file, + temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of + data will write into the file path. support + unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | + 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload + will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 + is valid value + type: integer + size: + description: 'specifies how many units of + data will write into the file path. support + unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | + 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload + will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 + is valid value + type: integer + size: + description: 'specifies how many units of + data will write into the file path. support + unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | + 512kB' + type: string + type: object + duration: + description: Duration represents the duration + of the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times + to append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name + to create or delete. + type: string + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name + to create or delete. + type: string + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege + to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be + renamed. + type: string + source-file: + description: SourceFile is the name need + to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination + string of the file. + type: string + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + line: + description: Line is the line number of + the file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string + of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target + service listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port + of HTTP connection, we will only attack + HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + delay: + description: Delay represents the delay + of the target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target + service listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port + of HTTP connection, we will only attack + HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only + support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to + throw for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action + 'latency', unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default + value is "", means match all database + type: string + exception: + description: The exception which needs to + throw for action `exception` or the exception + message needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action + 'latency' or the latency duration in action + `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set + to "8") now + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default + value is "", means match all SQL type. + The value can be 'select', 'insert', 'update', + 'delete', 'replace'. + type: string + table: + description: the match table default value + is "", means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + value: + description: the return value for action + 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule + file's data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to + use, only set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, + only set it when action is stress, the + value can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka + config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 + is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic + to these destination ports, use a ',' + to separate or to indicate the range, + such as 80, 8001:8010. it can only be + used in conjunction with -p tcp or -p + udp + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using + this IP protocol, supported: tcp, udp, + icmp, all' + type: string + percent: + description: percentage of packets to corrupt + (10 is 10%) + type: string + source-port: + description: only impact egress traffic + from these source ports, use a ',' to + separate or to indicate the range, such + as 80, 8001:8010. it can only be used + in conjunction with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match + the tcp flag can be accepted, others will + be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 + is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic + to these destination ports, use a ',' + to separate or to indicate the range, + such as 80, 8001:8010. it can only be + used in conjunction with -p tcp or -p + udp + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using + this IP protocol, supported: tcp, udp, + icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: + ns, us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic + from these source ports, use a ',' to + separate or to indicate the range, such + as 80, 8001:8010. it can only be used + in conjunction with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified + IP + type: string + dns-ip: + description: map specified host to this + IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: + ns, us (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 + is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic + to these destination ports, use a ',' + to separate or to indicate the range, + such as 80, 8001:8010. it can only be + used in conjunction with -p tcp or -p + udp + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using + this IP protocol, supported: tcp, udp, + icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic + from these source ports, use a ',' to + separate or to indicate the range, such + as 80, 8001:8010. it can only be used + in conjunction with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run + the iperf test + type: string + ip-address: + description: Generate traffic to this IP + address + type: string + parallel: + description: The number of iperf parallel + client threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port + on the IP address + type: string + rate: + description: The speed of network traffic, + allows bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 + is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic + to these destination ports, use a ',' + to separate or to indicate the range, + such as 80, 8001:8010. it can only be + used in conjunction with -p tcp or -p + udp + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using + this IP protocol, supported: tcp, udp, + icmp, all' + type: string + percent: + description: percentage of packets to loss + (10 is 10%) + type: string + source-port: + description: only impact egress traffic + from these source ports, use a ',' to + separate or to indicate the range, such + as 80, 8001:8010. it can only be used + in conjunction with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match + the tcp flag can be accepted, others will + be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means + packets coming from the 'IPAddress' or + 'Hostname' and going to your server, 'to' + means packets originating from your server + and going to the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic + to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process + ID + type: string + recoverCmd: + description: the command to be run when + recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be + sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines + whether to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` + command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines + whether to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` + command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical + machines that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of + string keys and a set values that used + to select physical machines. The key defines + the namespace which physical machine belong, + and each value is a set of physical machine + names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading + per CPU worker. 0 is effectively a sleep + (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply + the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % + of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed + when attack + type: string + recoverCmd: + description: The command to be executed + when recover + type: string + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent + of physical machines the server can do chaos + action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes + that a user creates on a chaos experiment about + pods. + properties: + action: + description: 'Action defines the specific pod + chaos action. Supported action: pod-kill / + pod-failure / container-kill Default action: + pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action. It is required when the + action is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill + action. It represents the duration in seconds + before the pod should be deleted. Value must + be non-negative integer. The default value + is zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired + state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty + of stressors just like `Stressors` except + that it's an experimental feature and more + powerful. You can define stressors in `stress-ng` + (see also `man stress-ng`) dialect, however + not all of the supported stressors are well + tested. It maybe retired in later releases. + You should always use `Stressors` to define + the stressors and use this only when you want + more stressors unsupported by `Stressors`. + When both `StressngStressors` and `Stressors` + are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors + supported to stress system components out. + You can use one or more of them to make up + various kinds of stresses. At least one of + the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent + loading per CPU worker. 0 is effectively + a sleep (no load) and 100 is full + loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 + workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual + memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 + proc` to know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes + consumed per vm worker, default is + the total available memory. One can + specify the size as % of total available + memory or in units of B, KB/KiB, MB/MiB, + GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 + workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state + of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock + id All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time + of injected program. It's a possibly signed + sequence of decimal numbers, such as "300ms", + "-1.5h" or "2h45m". Valid time units are "ns", + "us" (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + required: + - schedule + - type + type: object + statusCheck: + description: StatusCheck describe the behavior of StatusCheck. + Only used when Type is TypeStatusCheck. + properties: + duration: + description: Duration defines the duration of the + whole status check if the number of failed execution + does not exceed the failure threshold. Duration + is available to both `Synchronous` and `Continuous` + mode. 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum + consecutive failure for the status check to be + considered failed. + minimum: 1 + type: integer + http: + properties: + body: + type: string + criteria: + description: Criteria defines how to determine + the result of the status check. + properties: + statusCode: + description: StatusCode defines the expected + http status code for the request. A statusCode + string could be a single code (e.g. 200), + or an inclusive range (e.g. 200-400, both + `200` and `400` are included). + type: string + required: + - statusCode + type: object + headers: + additionalProperties: + items: + type: string + type: array + description: "A Header represents the key-value + pairs in an HTTP header. \n The keys should + be in canonical form, as returned by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in + seconds) to perform an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of + the status check. Support type: Synchronous / + Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number + of record to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum + consecutive successes for the status check to + be considered successful. SuccessThreshold only + works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of + seconds after which an execution of status check + times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check + type. Support type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + stressChaos: + description: StressChaosSpec defines the desired state + of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of + stressors just like `Stressors` except that it's + an experimental feature and more powerful. You + can define stressors in `stress-ng` (see also + `man stress-ng`) dialect, however not all of the + supported stressors are well tested. It maybe + retired in later releases. You should always use + `Stressors` to define the stressors and use this + only when you want more stressors unsupported + by `Stressors`. When both `StressngStressors` + and `Stressors` are defined, `StressngStressors` + wins. + type: string + stressors: + description: Stressors defines plenty of stressors + supported to stress system components out. You + can use one or more of them to make up various + kinds of stresses. At least one of the stressors + should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading + per CPU worker. 0 is effectively a sleep + (no load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 workers + can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual + memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` + to know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % + of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 workers + can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + task: + description: Task describes the behavior of the custom + task. Only used when Type is TypeTask. + properties: + container: + description: Container is the main container image + to run in the pod + properties: + args: + description: 'Arguments to the entrypoint. The + container image''s CMD is used if this is + not provided. Variable references $(VAR_NAME) + are expanded using the container''s environment. + If a variable cannot be resolved, the reference + in the input string will be unchanged. Double + $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal + "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable + exists or not. Cannot be updated. More info: + https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed + within a shell. The container image''s ENTRYPOINT + is used if this is not provided. Variable + references $(VAR_NAME) are expanded using + the container''s environment. If a variable + cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, + regardless of whether the variable exists + or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to + set in the container. Cannot be updated. + items: + description: EnvVar represents an environment + variable present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined + environment variables in the container + and any service environment variables. + If a variable cannot be resolved, the + reference in the input string will be + unchanged. Double $$ are reduced to + a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, + regardless of whether the variable exists + or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment + variable's value. Cannot be used if + value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the + ConfigMap or its key must be + defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the + pod: supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in + terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field + to select in the specified API + version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: + required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret + in the pod's namespace + properties: + key: + description: The key of the secret + to select from. Must be a valid + secret key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the + Secret or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined + within a source must be a C_IDENTIFIER. All + invalid keys will be reported as an event + when the container is starting. When a key + exists in multiple sources, the value associated + with the last source will take precedence. + Values defined by an Env with a duplicate + key will take precedence. Cannot be updated. + items: + description: EnvFromSource represents the + source of a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to + prepend to each key in the ConfigMap. + Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: + https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level + config management to default or override container + images in workload controllers like Deployments + and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, + Never, IfNotPresent. Defaults to Always if + :latest tag is specified, or IfNotPresent + otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system + should take in response to container lifecycle + events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately + after a container is created. If the handler + fails, the container is terminated and + restarted according to its restart policy. + Other management of the container blocks + until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action + to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the + command is root ('/') in the + container's filesystem. The command + is simply exec'd, it is not run + inside a shell, so traditional + shell instructions ('|', etc) + won't work. To use a shell, you + need to explicitly call out to + that shell. Exit status of 0 is + treated as live/healthy and non-zero + is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood + as the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is + NOT supported as a LifecycleHandler + and kept for the backward compatibility. + There are no validation of this field + and lifecycle hooks will fail in runtime + when tcp handler is specified. + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the + pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately + before a container is terminated due to + an API request or management event such + as liveness/startup probe failure, preemption, + resource contention, etc. The handler + is not called if the container crashes + or exits. The Pod''s termination grace + period countdown begins before the PreStop + hook is executed. Regardless of the outcome + of the handler, the container will eventually + terminate within the Pod''s termination + grace period (unless delayed by finalizers). + Other management of the container blocks + until the hook completes or until the + termination grace period is reached. More + info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action + to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the + command is root ('/') in the + container's filesystem. The command + is simply exec'd, it is not run + inside a shell, so traditional + shell instructions ('|', etc) + won't work. To use a shell, you + need to explicitly call out to + that shell. Exit status of 0 is + treated as live/healthy and non-zero + is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood + as the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is + NOT supported as a LifecycleHandler + and kept for the backward compatibility. + There are no validation of this field + and lifecycle hooks will fail in runtime + when tcp handler is specified. + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the + pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed + after having succeeded. Defaults to 3. + Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC + service. Number must be in the range + 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of + the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness + probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum + value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully + upon probe failure. The grace period is + the duration in seconds after the processes + running in the pod are sent a termination + signal and the time when the processes + are forcibly halted with a kill signal. + Set this value longer than the expected + cleanup time for your process. If this + value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value + zero indicates stop immediately via the + kill signal (no opportunity to shut down). + This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified + as a DNS_LABEL. Each container in a pod must + have a unique name (DNS_LABEL). Cannot be + updated. + type: string + ports: + description: List of ports to expose from the + container. Not specifying a port here DOES + NOT prevent that port from being exposed. + Any port which is listening on the default + "0.0.0.0" address inside a container will + be accessible from the network. Modifying + this array with strategic merge patch may + corrupt the data. For more information See + https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network + port in a single container. + properties: + containerPort: + description: Number of port to expose + on the pod's IP address. This must be + a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the + external port to. + type: string + hostPort: + description: Number of port to expose + on the host. If specified, this must + be a valid port number, 0 < x < 65536. + If HostNetwork is specified, this must + match ContainerPort. Most containers + do not need this. + format: int32 + type: integer + name: + description: If specified, this must be + an IANA_SVC_NAME and unique within the + pod. Each named port in a pod must have + a unique name. Name for the port that + can be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be + UDP, TCP, or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service + readiness. Container will be removed from + service endpoints if the probe fails. Cannot + be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed + after having succeeded. Defaults to 3. + Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC + service. Number must be in the range + 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of + the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness + probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum + value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully + upon probe failure. The grace period is + the duration in seconds after the processes + running in the pod are sent a termination + signal and the time when the processes + are forcibly halted with a kill signal. + Set this value longer than the expected + cleanup time for your process. If this + value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value + zero indicates stop immediately via the + kill signal (no opportunity to shut down). + This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the + container. + items: + description: ContainerResizePolicy represents + resource resize policy for the container. + properties: + resourceName: + description: 'Name of the resource to + which this resource resize policy applies. + Supported values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when + specified resource is resized. If not + specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by + this container. Cannot be updated. More info: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of + resources, defined in spec.resourceClaims, + that are used by this container. \n This + is an alpha field and requires enabling + the DynamicResourceAllocation feature + gate. \n This field is immutable. It can + only be set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum + amount of compute resources allowed. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. + If Requests is omitted for a container, + it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined + value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + restartPolicy: + description: 'RestartPolicy defines the restart + behavior of individual containers in a pod. + This field may only be set for init containers, + and the only allowed value is "Always". For + non-init containers or when this field is + not specified, the restart behavior is defined + by the Pod''s restart policy and the container + type. Setting the RestartPolicy as "Always" + for the init container will have the following + effect: this init container will be continually + restarted on exit until all regular containers + have terminated. Once all regular containers + have completed, all init containers with restartPolicy + "Always" will be shut down. This lifecycle + differs from normal init containers and is + often referred to as a "sidecar" container. + Although this init container still starts + in the init container sequence, it does not + wait for the container to complete before + proceeding to the next init container. Instead, + the next init container starts immediately + after this init container is started, or after + any startupProbe has successfully completed.' + type: string + securityContext: + description: 'SecurityContext defines the security + options the container should be run with. + If set, the fields of SecurityContext override + the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges + than its parent process. This bool directly + controls if the no_new_privs flag will + be set on the container process. AllowPrivilegeEscalation + is true always when the container is: + 1) run as Privileged 2) has CAP_SYS_ADMIN + Note that this field cannot be set when + spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop + when running containers. Defaults to the + default set of capabilities granted by + the container runtime. Note that this + field cannot be set when spec.os.name + is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent + POSIX capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent + POSIX capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged + mode. Processes in privileged containers + are essentially equivalent to root on + the host. Defaults to false. Note that + this field cannot be set when spec.os.name + is windows. + type: boolean + procMount: + description: procMount denotes the type + of proc mount to use for the containers. + The default is DefaultProcMount which + uses the container runtime defaults for + readonly paths and masked paths. This + requires the ProcMountType feature flag + to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has + a read-only root filesystem. Default is + false. Note that this field cannot be + set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint + of the container process. Uses runtime + default if unset. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. Note that this field + cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container + must run as a non-root user. If true, + the Kubelet will validate the image at + runtime to ensure that it does not run + as UID 0 (root) and fail to start the + container if it does. If unset or false, + no such validation will be performed. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint + of the container process. Defaults to + user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. Note that this field + cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied + to the container. If unspecified, the + container runtime will allocate a random + SELinux context for each container. May + also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. Note that this field + cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level + label that applies to the container. + type: string + role: + description: Role is a SELinux role + label that applies to the container. + type: string + type: + description: Type is a SELinux type + label that applies to the container. + type: string + user: + description: User is a SELinux user + label that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use + by this container. If seccomp options + are provided at both the pod & container + level, the container options override + the pod options. Note that this field + cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: localhostProfile indicates + a profile defined in a file on the + node should be used. The profile must + be preconfigured on the node to work. + Must be a descending path, relative + to the kubelet's configured seccomp + profile location. Must be set if type + is "Localhost". Must NOT be set for + any other type. + type: string + type: + description: "type indicates which kind + of seccomp profile will be applied. + Valid options are: \n Localhost - + a profile defined in a file on the + node should be used. RuntimeDefault + - the container runtime default profile + should be used. Unconfined - no profile + should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings + applied to all containers. If unspecified, + the options from the PodSecurityContext + will be used. If set in both SecurityContext + and PodSecurityContext, the value specified + in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name + is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where + the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName + field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName + is the name of the GMSA credential + spec to use. + type: string + hostProcess: + description: HostProcess determines + if a container should be run as a + 'Host Process' container. All of a + Pod's containers must have the same + effective HostProcess value (it is + not allowed to have a mix of HostProcess + containers and non-HostProcess containers). + In addition, if HostProcess is true + then HostNetwork must also be set + to true. + type: boolean + runAsUserName: + description: The UserName in Windows + to run the entrypoint of the container + process. Defaults to the user specified + in image metadata if unspecified. + May also be set in PodSecurityContext. + If set in both SecurityContext and + PodSecurityContext, the value specified + in SecurityContext takes precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the + Pod has successfully initialized. If specified, + no other probes are executed until this completes + successfully. If this probe fails, the Pod + will be restarted, just as if the livenessProbe + failed. This can be used to provide different + probe parameters at the beginning of a Pod''s + lifecycle, when it might take a long time + to load data or warm a cache, than during + steady-state operation. This cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed + after having succeeded. Defaults to 3. + Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC + service. Number must be in the range + 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of + the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness + probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum + value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully + upon probe failure. The grace period is + the duration in seconds after the processes + running in the pod are sent a termination + signal and the time when the processes + are forcibly halted with a kill signal. + Set this value longer than the expected + cleanup time for your process. If this + value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value + zero indicates stop immediately via the + kill signal (no opportunity to shut down). + This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. + If this is not set, reads from stdin in the + container will always result in EOF. Default + is false. + type: boolean + stdinOnce: + description: Whether the container runtime should + close the stdin channel after it has been + opened by a single attach. When stdin is true + the stdin stream will remain open across multiple + attach sessions. If stdinOnce is set to true, + stdin is opened on container start, is empty + until the first client attaches to stdin, + and then remains open and accepts data until + the client disconnects, at which time stdin + is closed and remains closed until the container + is restarted. If this flag is false, a container + processes that reads from stdin will never + receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file + to which the container''s termination message + will be written is mounted into the container''s + filesystem. Message written is intended to + be brief final status, such as an assertion + failure message. Will be truncated by the + node if greater than 4096 bytes. The total + message length across all containers will + be limited to 12kb. Defaults to /dev/termination-log. + Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message + should be populated. File will use the contents + of terminationMessagePath to populate the + container status message on both success and + failure. FallbackToLogsOnError will use the + last chunk of container log output if the + termination message file is empty and the + container exited with an error. The log output + is limited to 2048 bytes or 80 lines, whichever + is smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to + be true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block + devices to be used by the container. + items: + description: volumeDevice describes a mapping + of a raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside + of the container that the device will + be mapped to. + type: string + name: + description: name must match the name + of a persistentVolumeClaim in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting + of a Volume within a container. + properties: + mountPath: + description: Path within the container + at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines + how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is + used. This field is beta in 1.10. + type: string + name: + description: This must match the Name + of a Volume. + type: string + readOnly: + description: Mounted read-only if true, + read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + subPath: + description: Path within the volume from + which the container's volume should + be mounted. Defaults to "" (volume's + root). + type: string + subPathExpr: + description: Expanded path within the + volume from which the container's volume + should be mounted. Behaves similarly + to SubPath but environment variable + references $(VAR_NAME) are expanded + using the container's environment. Defaults + to "" (volume's root). SubPathExpr and + SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. + If not specified, the container runtime's + default will be used, which might be configured + in the container image. Cannot be updated. + type: string + required: + - name + type: object + volumes: + description: Volumes is a list of volumes that can + be mounted by containers in a template. + items: + description: Volume represents a named volume + in a pod that may be accessed by any container + in the pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents + an AWS Disk resource that is attached to + a kubelet''s host machine and then exposed + to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem + type of the volume that you want to + mount. Tip: Ensure that the filesystem + type is supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + partition: + description: 'partition is the partition + in the volume that you want to mount. + If omitted, the default is to mount + by volume name. Examples: For volume + /dev/sda1, you specify the partition + as "1". Similarly, the volume partition + for /dev/sda is "0" (or you can leave + the property empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will + force the readOnly setting in VolumeMounts. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of + the persistent disk resource in AWS + (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure + Data Disk mount on the host and bind mount + to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host + Caching mode: None, Read Only, Read + Write.' + type: string + diskName: + description: diskName is the Name of the + data disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data + disk in the blob storage + type: string + fsType: + description: fsType is Filesystem type + to mount. Must be a filesystem type + supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are + Shared: multiple blob disks per storage + account Dedicated: single blob disk + per storage account Managed: azure + managed data disk (only in managed availability + set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure + File Service mount on the host and bind + mount to the pod. + properties: + readOnly: + description: readOnly defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of + secret that contains Azure Storage Account + Name and Key + type: string + shareName: + description: shareName is the azure share + Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount + on the host that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors + is a collection of Ceph monitors More + info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as + the mounted root, rather than the full + Ceph tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here + will force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: + SecretFile is the path to key ring for + User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef + is reference to the authentication secret + for User, default is empty. More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is + the rados user name, default is admin + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume + attached and mounted on kubelets host machine. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if + unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points + to a secret object containing parameters + used to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify + the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap + that should populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: + mode bits used to set permissions on + created files by default. Must be an + octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML + accepts both octal and decimal values, + JSON requires decimal values for mode + bits. Defaults to 0644. Directories + within the path are not affected by + this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + items: + description: items if unspecified, each + key-value pair in the Data field of + the referenced ConfigMap will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will be + projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not present + in the ConfigMap, the volume setup will + error unless it is marked optional. + Paths must be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key to a + path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 or + a decimal value between 0 and + 511. YAML accepts both octal and + decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume defaultMode + will be used. This might be in + conflict with other options that + affect the file mode, like fsGroup, + and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the key + to. May not be an absolute path. + May not contain the path element + '..'. May not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) + represents ephemeral storage that is handled + by certain external CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the + CSI driver that handles this volume. + Consult with your admin for the correct + name as registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", + "xfs", "ntfs". If not provided, the + empty value is passed to the associated + CSI driver which will determine the + default filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a + reference to the secret object containing + sensitive information to pass to the + CSI driver to complete the CSI NodePublishVolume + and NodeUnpublishVolume calls. This + field is optional, and may be empty + if no secret is required. If the secret + object contains more than one secret, + all secret references are passed. + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only + configuration for the volume. Defaults + to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI + driver. Consult your driver's documentation + for supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward + API about the pod that should populate this + volume + properties: + defaultMode: + description: 'Optional: mode bits to use + on created files by default. Must be + a Optional: mode bits used to set permissions + on created files by default. Must be + an octal value between 0000 and 0777 + or a decimal value between 0 and 511. + YAML accepts both octal and decimal + values, JSON requires decimal values + for mode bits. Defaults to 0644. Directories + within the path are not affected by + this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + items: + description: Items is a list of downward + API volume file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only annotations, + labels, name and namespace are + supported.' + properties: + apiVersion: + description: Version of the + schema the FieldPath is written + in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field + to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits + used to set permissions on this + file, must be an octal value between + 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts + both octal and decimal values, + JSON requires decimal values for + mode bits. If not specified, the + volume defaultMode will be used. + This might be in conflict with + other options that affect the + file mode, like fsGroup, and the + result can be other mode bits + set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file + to be created. Must not be absolute + or contain the ''..'' path. Must + be utf-8 encoded. The first item + of the relative path must not + start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource + of the container: only resources + limits and requests (limits.cpu, + limits.memory, requests.cpu and + requests.memory) are currently + supported.' + properties: + containerName: + description: 'Container name: + required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary + directory that shares a pod''s lifetime. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type + of storage medium should back this directory. + The default is "" which means to use + the node''s default medium. Must be + an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount + of local storage required for this EmptyDir + volume. The size limit is also applicable + for memory medium. The maximum usage + on memory medium EmptyDir would be the + minimum value between the SizeLimit + specified here and the sum of memory + limits of all containers in a pod. The + default is nil which means that the + limit is undefined. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume + that is handled by a cluster storage driver. + The volume's lifecycle is tied to the pod + that defines it - it will be created before + the pod starts, and deleted when the pod + is removed. \n Use this if: a) the volume + is only needed while the pod runs, b) features + of normal volumes like restoring from snapshot + or capacity tracking are needed, c) the + storage driver is specified through a storage + class, and d) the storage driver supports + dynamic volume provisioning through a PersistentVolumeClaim + (see EphemeralVolumeSource for more information + on the connection between this volume type + and PersistentVolumeClaim). \n Use PersistentVolumeClaim + or one of the vendor-specific APIs for volumes + that persist for longer than the lifecycle + of an individual pod. \n Use CSI for light-weight + local ephemeral volumes if the CSI driver + is meant to be used that way - see the documentation + of the driver for more information. \n A + pod can use both types of ephemeral volumes + and persistent volumes at the same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a + stand-alone PVC to provision the volume. + The pod in which this EphemeralVolumeSource + is embedded will be the owner of the + PVC, i.e. the PVC will be deleted together + with the pod. The name of the PVC will + be `-` where + `` is the name from the + `PodSpec.Volumes` array entry. Pod validation + will reject the pod if the concatenated + name is not valid for a PVC (for example, + too long). \n An existing PVC with that + name that is not owned by the pod will + *not* be used for the pod to avoid using + an unrelated volume by mistake. Starting + the pod is then blocked until the unrelated + PVC is removed. If such a pre-created + PVC is meant to be used by the pod, + the PVC has to updated with an owner + reference to the pod once the pod exists. + Normally this should not be necessary, + but it may be useful when manually reconstructing + a broken cluster. \n This field is read-only + and no changes will be made by Kubernetes + to the PVC after it has been created. + \n Required, must not be nil." + properties: + metadata: + description: May contain labels and + annotations that will be copied + into the PVC when creating it. No + other fields are allowed and will + be rejected during validation. + type: object + spec: + description: The specification for + the PersistentVolumeClaim. The entire + content is copied unchanged into + the PVC that gets created from this + template. The same fields as in + a PersistentVolumeClaim are also + valid here. + properties: + accessModes: + description: 'accessModes contains + the desired access modes the + volume should have. More info: + https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field + can be used to specify either: + * An existing VolumeSnapshot + object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external + controller can support the specified + data source, it will create + a new volume based on the contents + of the specified data source. + When the AnyVolumeDataSource + feature gate is enabled, dataSource + contents will be copied to dataSourceRef, + and dataSourceRef contents will + be copied to dataSource when + dataSourceRef.namespace is not + specified. If the namespace + is specified, then dataSourceRef + will not be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the + group for the resource being + referenced. If APIGroup + is not specified, the specified + Kind must be in the core + API group. For any other + third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies + the object from which to populate + the volume with data, if a non-empty + volume is desired. This may + be any object from a non-empty + API group (non core object) + or a PersistentVolumeClaim object. + When this field is specified, + volume binding will only succeed + if the type of the specified + object matches some installed + volume populator or dynamic + provisioner. This field will + replace the functionality of + the dataSource field and as + such if both fields are non-empty, + they must have the same value. + For backwards compatibility, + when namespace isn''t specified + in dataSourceRef, both fields + (dataSource and dataSourceRef) + will be set to the same value + automatically if one of them + is empty and the other is non-empty. + When namespace is specified + in dataSourceRef, dataSource + isn''t set to the same value + and must be empty. There are + three important differences + between dataSource and dataSourceRef: + * While dataSource only allows + two specific types of objects, + dataSourceRef allows any non-core + object, as well as PersistentVolumeClaim + objects. * While dataSource + ignores disallowed values (dropping + them), dataSourceRef preserves + all values, and generates an + error if a disallowed value + is specified. * While dataSource + only allows local objects, dataSourceRef + allows objects in any namespaces. + (Beta) Using this field requires + the AnyVolumeDataSource feature + gate to be enabled. (Alpha) + Using the namespace field of + dataSourceRef requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the + group for the resource being + referenced. If APIGroup + is not specified, the specified + Kind must be in the core + API group. For any other + third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + namespace: + description: Namespace is + the namespace of resource + being referenced Note that + when a namespace is specified, + a gateway.networking.k8s.io/ReferenceGrant + object is required in the + referent namespace to allow + that namespace's owner to + accept the reference. See + the ReferenceGrant documentation + for details. (Alpha) This + field requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents + the minimum resources the volume + should have. If RecoverVolumeExpansionFailure + feature is enabled users are + allowed to specify resource + requirements that are lower + than previous value but must + still be higher than capacity + recorded in the status field + of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists + the names of resources, + defined in spec.resourceClaims, + that are used by this container. + \n This is an alpha field + and requires enabling the + DynamicResourceAllocation + feature gate. \n This field + is immutable. It can only + be set for containers." + items: + description: ResourceClaim + references one entry in + PodSpec.ResourceClaims. + properties: + name: + description: Name must + match the name of + one entry in pod.spec.resourceClaims + of the Pod where this + field is used. It + makes that resource + available inside a + container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes + the maximum amount of compute + resources allowed. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes + the minimum amount of compute + resources required. If Requests + is omitted for a container, + it defaults to Limits if + that is explicitly specified, + otherwise to an implementation-defined + value. Requests cannot exceed + Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label + query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, + a key, and an operator + that relates the key and + values. + properties: + key: + description: key is + the label key that + the selector applies + to. + type: string + operator: + description: operator + represents a key's + relationship to a + set of values. Valid + operators are In, + NotIn, Exists and + DoesNotExist. + type: string + values: + description: values + is an array of string + values. If the operator + is In or NotIn, the + values array must + be non-empty. If the + operator is Exists + or DoesNotExist, the + values array must + be empty. This array + is replaced during + a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is + a map of {key,value} pairs. + A single {key,value} in + the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", + the operator is "In", and + the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName + is the name of the StorageClass + required by the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines + what type of volume is required + by the claim. Value of Filesystem + is implied when not included + in claim spec. + type: string + volumeName: + description: volumeName is the + binding reference to the PersistentVolume + backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel + resource that is attached to a kubelet's + host machine and then exposed to the pod. + properties: + fsType: + description: 'fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target + lun number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here + will force the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: + FC target worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume + world wide identifiers (wwids) Either + wwids or combination of targetWWNs and + lun must be set, but not both simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic + volume resource that is provisioned/attached + using an exec based plugin. + properties: + driver: + description: driver is the name of the + driver to use for this volume. + type: string + fsType: + description: fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". The + default filesystem depends on FlexVolume + script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this + field holds extra command options if + any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults + to false (read/write). ReadOnly here + will force the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef + is reference to the secret object containing + sensitive information to pass to the + plugin scripts. This may be empty if + no secret object is specified. If the + secret object contains more than one + secret, all secrets are passed to the + plugin scripts.' + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker + volume attached to a kubelet's host machine. + This depends on the Flocker control service + being running + properties: + datasetName: + description: datasetName is Name of the + dataset stored as metadata -> name on + the dataset for Flocker should be considered + as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of + the dataset. This is unique identifier + of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents + a GCE Disk resource that is attached to + a kubelet''s host machine and then exposed + to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type + of the volume that you want to mount. + Tip: Ensure that the filesystem type + is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + partition: + description: 'partition is the partition + in the volume that you want to mount. + If omitted, the default is to mount + by volume name. Examples: For volume + /dev/sda1, you specify the partition + as "1". Similarly, the volume partition + for /dev/sda is "0" (or you can leave + the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of + the PD resource in GCE. Used to identify + the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force + the ReadOnly setting in VolumeMounts. + Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository + at a particular revision. DEPRECATED: GitRepo + is deprecated. To provision a container + with a git repo, mount an EmptyDir into + an InitContainer that clones the repo using + git, then mount the EmptyDir into the Pod''s + container.' + properties: + directory: + description: directory is the target directory + name. Must not contain or start with + '..'. If '.' is supplied, the volume + directory will be the git repository. Otherwise, + if specified, the volume will contain + the git repository in the subdirectory + with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash + for the specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint + name that details Glusterfs topology. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume + path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force + the Glusterfs volume to be mounted with + read-only permissions. Defaults to false. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing + file or directory on the host machine that + is directly exposed to the container. This + is generally used for system agents or other + privileged things that are allowed to see + the host machine. Most containers will NOT + need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who + can use host directory mounts and who can/can + not mount host directories as read/write.' + properties: + path: + description: 'path of the directory on + the host. If the path is a symlink, + it will follow the link to the real + path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume + Defaults to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk + resource that is attached to a kubelet''s + host machine and then exposed to the pod. + More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines + whether support iSCSI Discovery CHAP + authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether + support iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem + type of the volume that you want to + mount. Tip: Ensure that the filesystem + type is supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom + iSCSI Initiator Name. If initiatorName + is specified with iscsiInterface simultaneously, + new iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified + Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface + Name that uses an iSCSI transport. Defaults + to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target + Lun number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target + Portal List. The portal is either an + IP or ip_addr:port if the port is other + than default (typically TCP ports 860 + and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force + the ReadOnly setting in VolumeMounts. + Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret + for iSCSI target and initiator authentication + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target + Portal. The Portal is either an IP or + ip_addr:port if the port is other than + default (typically TCP ports 860 and + 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be + a DNS_LABEL and unique within the pod. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount + on the host that shares a pod''s lifetime + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by + the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force + the NFS export to be mounted with read-only + permissions. Defaults to false. More + info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or + IP address of the NFS server. More info: + https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource + represents a reference to a PersistentVolumeClaim + in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of + a PersistentVolumeClaim in the same + namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents + a PhotonController persistent disk attached + and mounted on kubelets host machine + properties: + fsType: + description: fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies + Photon Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx + volume attached and mounted on kubelets + host machine + properties: + fsType: + description: fSType represents the filesystem + type to mount Must be a filesystem type + supported by the host operating system. + Ex. "ext4", "xfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies + a Portworx volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one + resources secrets, configmaps, and downward + API + properties: + defaultMode: + description: defaultMode are the mode + bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both + octal and decimal values, JSON requires + decimal values for mode bits. Directories + within the path are not affected by + this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume + projections + items: + description: Projection that may be + projected along with other supported + volume types + properties: + configMap: + description: configMap information + about the configMap data to project + properties: + items: + description: items if unspecified, + each key-value pair in the + Data field of the referenced + ConfigMap will be projected + into the volume as a file + whose name is the key and + content is the value. If specified, + the listed keys will be projected + into the specified paths, + and unlisted keys will not + be present. If a key is specified + which is not present in the + ConfigMap, the volume setup + will error unless it is marked + optional. Paths must be relative + and may not contain the '..' + path or start with '..'. + items: + description: Maps a string + key to a path within a volume. + properties: + key: + description: key is the + key to project. + type: string + mode: + description: 'mode is + Optional: mode bits + used to set permissions + on this file. Must be + an octal value between + 0000 and 0777 or a decimal + value between 0 and + 511. YAML accepts both + octal and decimal values, + JSON requires decimal + values for mode bits. + If not specified, the + volume defaultMode will + be used. This might + be in conflict with + other options that affect + the file mode, like + fsGroup, and the result + can be other mode bits + set.' + format: int32 + type: integer + path: + description: path is the + relative path of the + file to map the key + to. May not be an absolute + path. May not contain + the path element '..'. + May not start with the + string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: optional specify + whether the ConfigMap or its + keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information + about the downwardAPI data to + project + properties: + items: + description: Items is a list + of DownwardAPIVolume file + items: + description: DownwardAPIVolumeFile + represents information to + create the file containing + the pod field + properties: + fieldRef: + description: 'Required: + Selects a field of the + pod: only annotations, + labels, name and namespace + are supported.' + properties: + apiVersion: + description: Version + of the schema the + FieldPath is written + in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path + of the field to + select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: + mode bits used to set + permissions on this + file, must be an octal + value between 0000 and + 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and + decimal values, JSON + requires decimal values + for mode bits. If not + specified, the volume + defaultMode will be + used. This might be + in conflict with other + options that affect + the file mode, like + fsGroup, and the result + can be other mode bits + set.' + format: int32 + type: integer + path: + description: 'Required: + Path is the relative + path name of the file + to be created. Must + not be absolute or contain + the ''..'' path. Must + be utf-8 encoded. The + first item of the relative + path must not start + with ''..''' + type: string + resourceFieldRef: + description: 'Selects + a resource of the container: + only resources limits + and requests (limits.cpu, + limits.memory, requests.cpu + and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container + name: required for + volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies + the output format + of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: + resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information + about the secret data to project + properties: + items: + description: items if unspecified, + each key-value pair in the + Data field of the referenced + Secret will be projected into + the volume as a file whose + name is the key and content + is the value. If specified, + the listed keys will be projected + into the specified paths, + and unlisted keys will not + be present. If a key is specified + which is not present in the + Secret, the volume setup will + error unless it is marked + optional. Paths must be relative + and may not contain the '..' + path or start with '..'. + items: + description: Maps a string + key to a path within a volume. + properties: + key: + description: key is the + key to project. + type: string + mode: + description: 'mode is + Optional: mode bits + used to set permissions + on this file. Must be + an octal value between + 0000 and 0777 or a decimal + value between 0 and + 511. YAML accepts both + octal and decimal values, + JSON requires decimal + values for mode bits. + If not specified, the + volume defaultMode will + be used. This might + be in conflict with + other options that affect + the file mode, like + fsGroup, and the result + can be other mode bits + set.' + format: int32 + type: integer + path: + description: path is the + relative path of the + file to map the key + to. May not be an absolute + path. May not contain + the path element '..'. + May not start with the + string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: optional field + specify whether the Secret + or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken + is information about the serviceAccountToken + data to project + properties: + audience: + description: audience is the + intended audience of the token. + A recipient of a token must + identify itself with an identifier + specified in the audience + of the token, and otherwise + should reject the token. The + audience defaults to the identifier + of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds + is the requested duration + of validity of the service + account token. As the token + approaches expiration, the + kubelet volume plugin will + proactively rotate the service + account token. The kubelet + will start trying to rotate + the token if the token is + older than 80 percent of its + time to live or if the token + is older than 24 hours.Defaults + to 1 hour and must be at least + 10 minutes. + format: int64 + type: integer + path: + description: path is the path + relative to the mount point + of the file to project the + token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte + mount on the host that shares a pod's lifetime + properties: + group: + description: group to map volume access + to Default is no group + type: string + readOnly: + description: readOnly here will force + the Quobyte volume to be mounted with + read-only permissions. Defaults to false. + type: boolean + registry: + description: registry represents a single + or multiple Quobyte Registry services + specified as a string as host:port pair + (multiple entries are separated with + commas) which acts as the central registry + for volumes + type: string + tenant: + description: tenant owning the given Quobyte + volume in the Backend Used with dynamically + provisioned Quobyte volumes, value is + set by the plugin + type: string + user: + description: user to map volume access + to Defaults to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by + name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block + Device mount on the host that shares a pod''s + lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem + type of the volume that you want to + mount. Tip: Ensure that the filesystem + type is supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + image: + description: 'image is the rados image + name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key + ring for RBDUser. Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection + of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. + Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force + the ReadOnly setting in VolumeMounts. + Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the + authentication secret for RBDUser. If + provided overrides keyring. Default + is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. + Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO + persistent volume attached and mounted on + Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Default + is "xfs". + type: string + gateway: + description: gateway is the host address + of the ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name + of the ScaleIO Protection Domain for + the configured storage. + type: string + readOnly: + description: readOnly Defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the + secret for ScaleIO user and other sensitive + information. If this is not provided, + Login operation will fail. + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable + SSL communication with Gateway, default + false + type: boolean + storageMode: + description: storageMode indicates whether + the storage for a volume should be ThickProvisioned + or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO + Storage Pool associated with the protection + domain. + type: string + system: + description: system is the name of the + storage system as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of + a volume already created in the ScaleIO + system that is associated with this + volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that + should populate this volume. More info: + https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: + mode bits used to set permissions on + created files by default. Must be an + octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML + accepts both octal and decimal values, + JSON requires decimal values for mode + bits. Defaults to 0644. Directories + within the path are not affected by + this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + items: + description: items If unspecified, each + key-value pair in the Data field of + the referenced Secret will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will be + projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not present + in the Secret, the volume setup will + error unless it is marked optional. + Paths must be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key to a + path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 or + a decimal value between 0 and + 511. YAML accepts both octal and + decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume defaultMode + will be used. This might be in + conflict with other options that + affect the file mode, like fsGroup, + and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the key + to. May not be an absolute path. + May not contain the path element + '..'. May not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether + the Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of + the secret in the pod''s namespace to + use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS + volume attached and mounted on Kubernetes + nodes. + properties: + fsType: + description: fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret + to use for obtaining the StorageOS API + credentials. If not specified, default + values will be attempted. + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable + name of the StorageOS volume. Volume + names are only unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies + the scope of the volume within StorageOS. If + no namespace is specified then the Pod's + namespace will be used. This allows + the Kubernetes name scoping to be mirrored + within StorageOS for tighter integration. + Set VolumeName to any name to override + the default behaviour. Set to "default" + if you are not using namespaces within + StorageOS. Namespaces that do not pre-exist + within StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere + volume attached and mounted on kubelets + host machine + properties: + fsType: + description: fsType is filesystem type + to mount. Must be a filesystem type + supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage + Policy Based Management (SPBM) profile + ID associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the + storage Policy Based Management (SPBM) + profile name. + type: string + volumePath: + description: volumePath is the path that + identifies vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + templateType: + type: string + timeChaos: + description: TimeChaosSpec defines the desired state + of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock + id All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of + injected program. It's a possibly signed sequence + of decimal numbers, such as "300ms", "-1.5h" or + "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + required: + - name + - templateType + type: object + type: array + required: + - entry + - templates + type: object + required: + - schedule + - type + type: object + startTime: + format: date-time + type: string + statusCheck: + description: StatusCheck describe the behavior of StatusCheck. Only + used when Type is TypeStatusCheck. + properties: + duration: + description: Duration defines the duration of the whole status + check if the number of failed execution does not exceed the + failure threshold. Duration is available to both `Synchronous` + and `Continuous` mode. 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum consecutive + failure for the status check to be considered failed. + minimum: 1 + type: integer + http: + properties: + body: + type: string + criteria: + description: Criteria defines how to determine the result + of the status check. + properties: + statusCode: + description: StatusCode defines the expected http status + code for the request. A statusCode string could be a + single code (e.g. 200), or an inclusive range (e.g. + 200-400, both `200` and `400` are included). + type: string + required: + - statusCode + type: object + headers: + additionalProperties: + items: + type: string + type: array + description: "A Header represents the key-value pairs in an + HTTP header. \n The keys should be in canonical form, as + returned by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in seconds) to + perform an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of the status check. + Support type: Synchronous / Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number of record + to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum consecutive + successes for the status check to be considered successful. + SuccessThreshold only works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of seconds after + which an execution of status check times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check type. Support + type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + stressChaos: + description: StressChaosSpec defines the desired state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors just + like `Stressors` except that it's an experimental feature and + more powerful. You can define stressors in `stress-ng` (see + also `man stress-ng`) dialect, however not all of the supported + stressors are well tested. It maybe retired in later releases. + You should always use `Stressors` to define the stressors and + use this only when you want more stressors unsupported by `Stressors`. + When both `StressngStressors` and `Stressors` are defined, `StressngStressors` + wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported to + stress system components out. You can use one or more of them + to make up various kinds of stresses. At least one of the stressors + should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading per CPU + worker. 0 is effectively a sleep (no load) and 100 is + full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to apply the + stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj of the + stress process. See `man 5 proc` to know more about + this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per vm worker, + default is the total available memory. One can specify + the size as % of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to apply the + stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + type: object + task: + properties: + container: + description: Container is the main container image to run in the + pod + properties: + args: + description: 'Arguments to the entrypoint. The container image''s + CMD is used if this is not provided. Variable references + $(VAR_NAME) are expanded using the container''s environment. + If a variable cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced to a single + $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of + whether the variable exists or not. Cannot be updated. More + info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within a shell. + The container image''s ENTRYPOINT is used if this is not + provided. Variable references $(VAR_NAME) are expanded using + the container''s environment. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double + $$ are reduced to a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references will + never be expanded, regardless of whether the variable exists + or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables + in the container and any service environment variables. + If a variable cannot be resolved, the reference in + the input string will be unchanged. Double $$ are + reduced to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment variables + in the container. The keys defined within a source must + be a C_IDENTIFIER. All invalid keys will be reported as + an event when the container is starting. When a key exists + in multiple sources, the value associated with the last + source will take precedence. Values defined by an Env with + a duplicate key will take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to each + key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management + to default or override container images in workload controllers + like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent + otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system should take + in response to container lifecycle events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately after a + container is created. If the handler fails, the container + is terminated and restarted according to its restart + policy. Other management of the container blocks until + the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory + for the command is root ('/') in the container's + filesystem. The command is simply exec'd, it + is not run inside a shell, so traditional shell + instructions ('|', etc) won't work. To use a + shell, you need to explicitly call out to that + shell. Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to + perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the + host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of this field + and lifecycle hooks will fail in runtime when tcp + handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately before a container + is terminated due to an API request or management event + such as liveness/startup probe failure, preemption, + resource contention, etc. The handler is not called + if the container crashes or exits. The Pod''s termination + grace period countdown begins before the PreStop hook + is executed. Regardless of the outcome of the handler, + the container will eventually terminate within the Pod''s + termination grace period (unless delayed by finalizers). + Other management of the container blocks until the hook + completes or until the termination grace period is reached. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory + for the command is root ('/') in the container's + filesystem. The command is simply exec'd, it + is not run inside a shell, so traditional shell + instructions ('|', etc) won't work. To use a + shell, you need to explicitly call out to that + shell. Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to + perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the + host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of this field + and lifecycle hooks will fail in runtime when tcp + handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. Container + will be restarted if the probe fails. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', + etc) won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC + port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a + TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and + the time when the processes are forcibly halted with + a kill signal. Set this value longer than the expected + cleanup time for your process. If this value is nil, + the pod's terminationGracePeriodSeconds will be used. + Otherwise, this value overrides the value provided by + the pod spec. Value must be non-negative integer. The + value zero indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta field + and requires enabling ProbeTerminationGracePeriod feature + gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe + times out. Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. Not + specifying a port here DOES NOT prevent that port from being + exposed. Any port which is listening on the default "0.0.0.0" + address inside a container will be accessible from the network. + Modifying this array with strategic merge patch may corrupt + the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port in + a single container. + properties: + containerPort: + description: Number of port to expose on the pod's IP + address. This must be a valid port number, 0 < x < + 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external port + to. + type: string + hostPort: + description: Number of port to expose on the host. If + specified, this must be a valid port number, 0 < x + < 65536. If HostNetwork is specified, this must match + ContainerPort. Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an IANA_SVC_NAME + and unique within the pod. Each named port in a pod + must have a unique name. Name for the port that can + be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, TCP, or + SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service readiness. + Container will be removed from service endpoints if the + probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', + etc) won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC + port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a + TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and + the time when the processes are forcibly halted with + a kill signal. Set this value longer than the expected + cleanup time for your process. If this value is nil, + the pod's terminationGracePeriodSeconds will be used. + Otherwise, this value overrides the value provided by + the pod spec. Value must be non-negative integer. The + value zero indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta field + and requires enabling ProbeTerminationGracePeriod feature + gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe + times out. Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource resize + policy for the container. + properties: + resourceName: + description: 'Name of the resource to which this resource + resize policy applies. Supported values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when specified + resource is resized. If not specified, it defaults + to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this container. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. \n This field + is immutable. It can only be set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry + in pod.spec.resourceClaims of the Pod where this + field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of + compute resources required. If Requests is omitted for + a container, it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined value. + Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + restartPolicy: + description: 'RestartPolicy defines the restart behavior of + individual containers in a pod. This field may only be set + for init containers, and the only allowed value is "Always". + For non-init containers or when this field is not specified, + the restart behavior is defined by the Pod''s restart policy + and the container type. Setting the RestartPolicy as "Always" + for the init container will have the following effect: this + init container will be continually restarted on exit until + all regular containers have terminated. Once all regular + containers have completed, all init containers with restartPolicy + "Always" will be shut down. This lifecycle differs from + normal init containers and is often referred to as a "sidecar" + container. Although this init container still starts in + the init container sequence, it does not wait for the container + to complete before proceeding to the next init container. + Instead, the next init container starts immediately after + this init container is started, or after any startupProbe + has successfully completed.' + type: string + securityContext: + description: 'SecurityContext defines the security options + the container should be run with. If set, the fields of + SecurityContext override the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether + a process can gain more privileges than its parent process. + This bool directly controls if the no_new_privs flag + will be set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run as Privileged + 2) has CAP_SYS_ADMIN Note that this field cannot be + set when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running + containers. Defaults to the default set of capabilities + granted by the container runtime. Note that this field + cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes + in privileged containers are essentially equivalent + to root on the host. Defaults to false. Note that this + field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc mount + to use for the containers. The default is DefaultProcMount + which uses the container runtime defaults for readonly + paths and masked paths. This requires the ProcMountType + feature flag to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root + filesystem. Default is false. Note that this field cannot + be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set + when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as + a non-root user. If true, the Kubelet will validate + the image at runtime to ensure that it does not run + as UID 0 (root) and fail to start the container if it + does. If unset or false, no such validation will be + performed. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container + process. Defaults to user specified in image metadata + if unspecified. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to the + container. If unspecified, the container runtime will + allocate a random SELinux context for each container. May + also be set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set + when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this container. + If seccomp options are provided at both the pod & container + level, the container options override the pod options. + Note that this field cannot be set when spec.os.name + is windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. The + profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's + configured seccomp profile location. Must be set + if type is "Localhost". Must NOT be set for any + other type. + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: \n Localhost + - a profile defined in a file on the node should + be used. RuntimeDefault - the container runtime + default profile should be used. Unconfined - no + profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied to + all containers. If unspecified, the options from the + PodSecurityContext will be used. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set + when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA + admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec + named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of + the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. All + of a Pod's containers must have the same effective + HostProcess value (it is not allowed to have a mix + of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork + must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set + in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the Pod has successfully + initialized. If specified, no other probes are executed + until this completes successfully. If this probe fails, + the Pod will be restarted, just as if the livenessProbe + failed. This can be used to provide different probe parameters + at the beginning of a Pod''s lifecycle, when it might take + a long time to load data or warm a cache, than during steady-state + operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', + etc) won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC + port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a + TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and + the time when the processes are forcibly halted with + a kill signal. Set this value longer than the expected + cleanup time for your process. If this value is nil, + the pod's terminationGracePeriodSeconds will be used. + Otherwise, this value overrides the value provided by + the pod spec. Value must be non-negative integer. The + value zero indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta field + and requires enabling ProbeTerminationGracePeriod feature + gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe + times out. Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate a buffer + for stdin in the container runtime. If this is not set, + reads from stdin in the container will always result in + EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close the + stdin channel after it has been opened by a single attach. + When stdin is true the stdin stream will remain open across + multiple attach sessions. If stdinOnce is set to true, stdin + is opened on container start, is empty until the first client + attaches to stdin, and then remains open and accepts data + until the client disconnects, at which time stdin is closed + and remains closed until the container is restarted. If + this flag is false, a container processes that reads from + stdin will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to which the + container''s termination message will be written is mounted + into the container''s filesystem. Message written is intended + to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. + The total message length across all containers will be limited + to 12kb. Defaults to /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message should be + populated. File will use the contents of terminationMessagePath + to populate the container status message on both success + and failure. FallbackToLogsOnError will use the last chunk + of container log output if the termination message file + is empty and the container exited with an error. The log + output is limited to 2048 bytes or 80 lines, whichever is + smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate a TTY + for itself, also requires 'stdin' to be true. Default is + false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to + be used by the container. + items: + description: volumeDevice describes a mapping of a raw block + device within a container. + properties: + devicePath: + description: devicePath is the path inside of the container + that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's filesystem. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a Volume + within a container. + properties: + mountPath: + description: Path within the container at which the + volume should be mounted. Must not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts + are propagated from the host to container and the + other way around. When not set, MountPropagationNone + is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write otherwise + (false or unspecified). Defaults to false. + type: boolean + subPath: + description: Path within the volume from which the container's + volume should be mounted. Defaults to "" (volume's + root). + type: string + subPathExpr: + description: Expanded path within the volume from which + the container's volume should be mounted. Behaves + similarly to SubPath but environment variable references + $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). SubPathExpr and SubPath + are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not specified, + the container runtime's default will be used, which might + be configured in the container image. Cannot be updated. + type: string + required: + - name + type: object + volumes: + description: Volumes is a list of volumes that can be mounted + by containers in a template. + items: + description: Volume represents a named volume in a pod that + may be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents an AWS Disk + resource that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume + that you want to mount. If omitted, the default is + to mount by volume name. Examples: For volume /dev/sda1, + you specify the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can leave the + property empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force the readOnly + setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the persistent + disk resource in AWS (Amazon EBS volume). More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data Disk mount + on the host and bind mount to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching mode: + None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data disk in + the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in the + blob storage + type: string + fsType: + description: fsType is Filesystem type to mount. Must + be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: multiple + blob disks per storage account Dedicated: single + blob disk per storage account Managed: azure managed + data disk (only in managed availability set). defaults + to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File Service + mount on the host and bind mount to the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret that + contains Azure Storage Account Name and Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount on the host + that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors is a collection + of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the mounted + root, rather than the full Ceph tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile is + the path to key ring for User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef is reference + to the authentication secret for User, default is + empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the rados user + name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume attached + and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points to a secret + object containing parameters used to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the volume in + cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that should + populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value pair + in the Data field of the referenced ConfigMap will + be projected into the volume as a file whose name + is the key and content is the value. If specified, + the listed keys will be projected into the specified + paths, and unlisted keys will not be present. If a + key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. + Paths must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within a + volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used + to set permissions on this file. Must be an + octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal values + for mode bits. If not specified, the volume + defaultMode will be used. This might be in conflict + with other options that affect the file mode, + like fsGroup, and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative path of the + file to map the key to. May not be an absolute + path. May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents + ephemeral storage that is handled by certain external + CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI driver that + handles this volume. Consult with your admin for the + correct name as registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the + associated CSI driver which will determine the default + filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference to + the secret object containing sensitive information + to pass to the CSI driver to complete the CSI NodePublishVolume + and NodeUnpublishVolume calls. This field is optional, + and may be empty if no secret is required. If the + secret object contains more than one secret, all secret + references are passed. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only configuration + for the volume. Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. Consult + your driver's documentation for supported values. + type: object + required: + - driver type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key that the selector - applies to. + downwardAPI: + description: downwardAPI represents downward API about the + pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on created + files by default. Must be a Optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + items: + description: Items is a list of downward API volume + file + items: + description: DownwardAPIVolumeFile represents information + to create the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects a field of the + pod: only annotations, labels, name and namespace + are supported.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used to set + permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for mode + bits. If not specified, the volume defaultMode + will be used. This might be in conflict with + other options that affect the file mode, like + fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must not + be absolute or contain the ''..'' path. Must + be utf-8 encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary directory + that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type of storage + medium should back this directory. The default is + "" which means to use the node''s default medium. + Must be an empty string (default) or Memory. More + info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount of local + storage required for this EmptyDir volume. The size + limit is also applicable for memory medium. The maximum + usage on memory medium EmptyDir would be the minimum + value between the SizeLimit specified here and the + sum of memory limits of all containers in a pod. The + default is nil which means that the limit is undefined. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume that is handled + by a cluster storage driver. The volume's lifecycle is + tied to the pod that defines it - it will be created before + the pod starts, and deleted when the pod is removed. \n + Use this if: a) the volume is only needed while the pod + runs, b) features of normal volumes like restoring from + snapshot or capacity tracking are needed, c) the storage + driver is specified through a storage class, and d) the + storage driver supports dynamic volume provisioning through + a PersistentVolumeClaim (see EphemeralVolumeSource for + more information on the connection between this volume + type and PersistentVolumeClaim). \n Use PersistentVolumeClaim + or one of the vendor-specific APIs for volumes that persist + for longer than the lifecycle of an individual pod. \n + Use CSI for light-weight local ephemeral volumes if the + CSI driver is meant to be used that way - see the documentation + of the driver for more information. \n A pod can use both + types of ephemeral volumes and persistent volumes at the + same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone PVC + to provision the volume. The pod in which this EphemeralVolumeSource + is embedded will be the owner of the PVC, i.e. the + PVC will be deleted together with the pod. The name + of the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` + array entry. Pod validation will reject the pod if + the concatenated name is not valid for a PVC (for + example, too long). \n An existing PVC with that name + that is not owned by the pod will *not* be used for + the pod to avoid using an unrelated volume by mistake. + Starting the pod is then blocked until the unrelated + PVC is removed. If such a pre-created PVC is meant + to be used by the pod, the PVC has to updated with + an owner reference to the pod once the pod exists. + Normally this should not be necessary, but it may + be useful when manually reconstructing a broken cluster. + \n This field is read-only and no changes will be + made by Kubernetes to the PVC after it has been created. + \n Required, must not be nil." + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when creating + it. No other fields are allowed and will be rejected + during validation. + type: object + spec: + description: The specification for the PersistentVolumeClaim. + The entire content is copied unchanged into the + PVC that gets created from this template. The + same fields as in a PersistentVolumeClaim are + also valid here. + properties: + accessModes: + description: 'accessModes contains the desired + access modes the volume should have. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can be used to + specify either: * An existing VolumeSnapshot + object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller + can support the specified data source, it + will create a new volume based on the contents + of the specified data source. When the AnyVolumeDataSource + feature gate is enabled, dataSource contents + will be copied to dataSourceRef, and dataSourceRef + contents will be copied to dataSource when + dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef + will not be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the group for the + resource being referenced. If APIGroup + is not specified, the specified Kind must + be in the core API group. For any other + third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies the object + from which to populate the volume with data, + if a non-empty volume is desired. This may + be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding + will only succeed if the type of the specified + object matches some installed volume populator + or dynamic provisioner. This field will replace + the functionality of the dataSource field + and as such if both fields are non-empty, + they must have the same value. For backwards + compatibility, when namespace isn''t specified + in dataSourceRef, both fields (dataSource + and dataSourceRef) will be set to the same + value automatically if one of them is empty + and the other is non-empty. When namespace + is specified in dataSourceRef, dataSource + isn''t set to the same value and must be empty. + There are three important differences between + dataSource and dataSourceRef: * While dataSource + only allows two specific types of objects, + dataSourceRef allows any non-core object, + as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values + (dropping them), dataSourceRef preserves all + values, and generates an error if a disallowed + value is specified. * While dataSource only + allows local objects, dataSourceRef allows + objects in any namespaces. (Beta) Using this + field requires the AnyVolumeDataSource feature + gate to be enabled. (Alpha) Using the namespace + field of dataSourceRef requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the group for the + resource being referenced. If APIGroup + is not specified, the specified Kind must + be in the core API group. For any other + third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: Namespace is the namespace + of resource being referenced Note that + when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent namespace + to allow that namespace's owner to accept + the reference. See the ReferenceGrant + documentation for details. (Alpha) This + field requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents the minimum + resources the volume should have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed to specify + resource requirements that are lower than + previous value but must still be higher than + capacity recorded in the status field of the + claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the names of + resources, defined in spec.resourceClaims, + that are used by this container. \n This + is an alpha field and requires enabling + the DynamicResourceAllocation feature + gate. \n This field is immutable. It can + only be set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum + amount of compute resources allowed. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. + If Requests is omitted for a container, + it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined + value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName is the name of + the StorageClass required by the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type of + volume is required by the claim. Value of + Filesystem is implied when not included in + claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource that + is attached to a kubelet's host machine and then exposed + to the pod. + properties: + fsType: + description: 'fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. TODO: how do we prevent + errors in the filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target worldwide + names (WWNs)' + items: type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. + type: array + wwids: + description: 'wwids Optional: FC volume world wide identifiers + (wwids) Either wwids or combination of targetWWNs + and lun must be set, but not both simultaneously.' + items: type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. This - array is replaced during a strategic merge patch. - items: + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume resource + that is provisioned/attached using an exec based plugin. + properties: + driver: + description: driver is the name of the driver to use + for this volume. + type: string + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". The default filesystem + depends on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field holds + extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef is reference + to the secret object containing sensitive information + to pass to the plugin scripts. This may be empty if + no secret object is specified. If the secret object + contains more than one secret, all secrets are passed + to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. + type: object + x-kubernetes-map-type: atomic + required: + - driver type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. + flocker: + description: flocker represents a Flocker volume attached + to a kubelet's host machine. This depends on the Flocker + control service being running + properties: + datasetName: + description: datasetName is Name of the dataset stored + as metadata -> name on the dataset for Flocker should + be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. + This is unique identifier of a Flocker dataset + type: string type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE Disk resource + that is attached to a kubelet''s host machine and then + exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume + that you want to mount. If omitted, the default is + to mount by volume name. Examples: For volume /dev/sda1, + you specify the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can leave the + property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the PD resource + in GCE. Used to identify the disk in GCE. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of - a pod at the current time. supported value: Pending / - Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + gitRepo: + description: 'gitRepo represents a git repository at a particular + revision. DEPRECATED: GitRepo is deprecated. To provision + a container with a git repo, mount an EmptyDir into an + InitContainer that clones the repo using git, then mount + the EmptyDir into the Pod''s container.' + properties: + directory: + description: directory is the target directory name. + Must not contain or start with '..'. If '.' is supplied, + the volume directory will be the git repository. Otherwise, + if specified, the volume will contain the git repository + in the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the specified + revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs mount on + the host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name that details + Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume path. More + info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the Glusterfs + volume to be mounted with read-only permissions. Defaults + to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing file or + directory on the host machine that is directly exposed + to the container. This is generally used for system agents + or other privileged things that are allowed to see the + host machine. Most containers will NOT need this. More + info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can use host + directory mounts and who can/can not mount host directories + as read/write.' + properties: + path: + description: 'path of the directory on the host. If + the path is a symlink, it will follow the link to + the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults to "" + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource that + is attached to a kubelet''s host machine and then exposed + to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether support + iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support + iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI Initiator + Name. If initiatorName is specified with iscsiInterface + simultaneously, new iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface Name that + uses an iSCSI transport. Defaults to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal List. + The portal is either an IP or ip_addr:port if the + port is other than default (typically TCP ports 860 + and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the ReadOnly setting + in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for iSCSI + target and initiator authentication + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target Portal. The + Portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and + 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL and + unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the host that + shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the NFS export + to be mounted with read-only permissions. Defaults + to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP address of + the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource represents + a reference to a PersistentVolumeClaim in the same namespace. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly setting + in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets host + machine + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon Controller + persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx volume + attached and mounted on kubelets host machine + properties: + fsType: + description: fSType represents the filesystem type to + mount Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx + volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources secrets, + configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits used to set + permissions on created files by default. Must be an + octal value between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for mode bits. + Directories within the path are not affected by this + setting. This might be in conflict with other options + that affect the file mode, like fsGroup, and the result + can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume projections + items: + description: Projection that may be projected along + with other supported volume types + properties: + configMap: + description: configMap information about the configMap + data to project + properties: + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced + ConfigMap will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the ConfigMap, the volume setup will + error unless it is marked optional. Paths + must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether the + ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about the + downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used + to set permissions on this file, must + be an octal value between 0000 and + 0777 or a decimal value between 0 + and 511. YAML accepts both octal and + decimal values, JSON requires decimal + values for mode bits. If not specified, + the volume defaultMode will be used. + This might be in conflict with other + options that affect the file mode, + like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file to + be created. Must not be absolute or + contain the ''..'' path. Must be utf-8 + encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env + vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about the secret + data to project + properties: + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced + Secret will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the Secret, the volume setup will error + unless it is marked optional. Paths must + be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional field specify whether + the Secret or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to project + properties: + audience: + description: audience is the intended audience + of the token. A recipient of a token must + identify itself with an identifier specified + in the audience of the token, and otherwise + should reject the token. The audience defaults + to the identifier of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is the requested + duration of validity of the service account + token. As the token approaches expiration, + the kubelet volume plugin will proactively + rotate the service account token. The kubelet + will start trying to rotate the token if + the token is older than 80 percent of its + time to live or if the token is older than + 24 hours.Defaults to 1 hour and must be + at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative to + the mount point of the file to project the + token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount on the host + that shares a pod's lifetime + properties: + group: + description: group to map volume access to Default is + no group + type: string + readOnly: + description: readOnly here will force the Quobyte volume + to be mounted with read-only permissions. Defaults + to false. + type: boolean + registry: + description: registry represents a single or multiple + Quobyte Registry services specified as a string as + host:port pair (multiple entries are separated with + commas) which acts as the central registry for volumes + type: string + tenant: + description: tenant owning the given Quobyte volume + in the Backend Used with dynamically provisioned Quobyte + volumes, value is set by the plugin + type: string + user: + description: user to map volume access to Defaults to + serivceaccount user + type: string + volume: + description: volume is a string that references an already + created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device mount + on the host that shares a pod''s lifetime. More info: + https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + image: + description: 'image is the rados image name. More info: + https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring for RBDUser. + Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of Ceph monitors. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. Default is + rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. More info: + https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides keyring. + Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. Default is + admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent volume + attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of the ScaleIO + API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the ScaleIO + Protection Domain for the configured storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret for + ScaleIO user and other sensitive information. If this + is not provided, Login operation will fail. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL communication + with Gateway, default false + type: boolean + storageMode: + description: storageMode indicates whether the storage + for a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage Pool + associated with the protection domain. + type: string + system: + description: system is the name of the storage system + as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume already + created in the ScaleIO system that is associated with + this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that should populate + this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer items: + description: items If unspecified, each key-value pair + in the Data field of the referenced Secret will be + projected into the volume as a file whose name is + the key and content is the value. If specified, the + listed keys will be projected into the specified paths, + and unlisted keys will not be present. If a key is + specified which is not present in the Secret, the + volume setup will error unless it is marked optional. + Paths must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within a + volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used + to set permissions on this file. Must be an + octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal values + for mode bits. If not specified, the volume + defaultMode will be used. This might be in conflict + with other options that affect the file mode, + like fsGroup, and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative path of the + file to map the key to. May not be an absolute + path. May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether the Secret + or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the secret in + the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' type: string - type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. type: object + storageos: + description: storageOS represents a StorageOS volume attached + and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret to use for + obtaining the StorageOS API credentials. If not specified, + default values will be attempted. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable name of + the StorageOS volume. Volume names are only unique + within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the scope of + the volume within StorageOS. If no namespace is specified + then the Pod's namespace will be used. This allows + the Kubernetes name scoping to be mirrored within + StorageOS for tighter integration. Set VolumeName + to any name to override the default behaviour. Set + to "default" if you are not using namespaces within + StorageOS. Namespaces that do not pre-exist within + StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere volume attached + and mounted on kubelets host machine + properties: + fsType: + description: fsType is filesystem type to mount. Must + be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy Based + Management (SPBM) profile ID associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage Policy + Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name type: object - value: - description: TargetValue is required when the mode is set to - `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - If `FixedPodMode`, provide an integer of pods to do chaos - action. If `FixedPercentPodMod`, provide a number from 0-100 - to specify the percent of pods the server can do chaos action. - If `RandomMaxPercentPodMod`, provide a number from 0-100 - to specify the max percent of pods to do chaos action + type: array + type: object + templateName: + type: string + timeChaos: + description: TimeChaosSpec defines the desired state of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id All available + options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: type: string - required: - - mode - - selector - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - action - - mode - - selector - type: object - pod_chaos: - description: PodChaosSpec defines the attributes that a user creates - on a chaos experiment about pods. - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: pod-kill / pod-failure / container-kill Default action: - pod-kill' - enum: - - pod-kill - - pod-failure - - container-kill - type: string - containerName: - description: ContainerName indicates the name of the container. - Needed in container-kill. - type: string - duration: - description: Duration represents the duration of the chaos action. - It is required when the action is `PodFailureAction`. 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". - type: string - gracePeriod: - description: GracePeriod is used in pod-kill action. It represents - the duration in seconds before the pod should be deleted. Value - must be non-negative integer. The default value is zero that indicates - delete immediately. - format: int64 - minimum: 0 - type: integer - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + type: array + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - action - - mode - - selector - type: object - start_time: - format: date-time - type: string - stress_chaos: - description: StressChaosSpec defines the desired state of StressChaos - properties: - containerName: - description: ContainerName indicates the target container to inject - stress in - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - stressngStressors: - description: StressngStressors defines plenty of stressors just - like `Stressors` except that it's an experimental feature and - more powerful. You can define stressors in `stress-ng` (see also - `man stress-ng`) dialect, however not all of the supported stressors - are well tested. It maybe retired in later releases. You should - always use `Stressors` to define the stressors and use this only - when you want more stressors unsupported by `Stressors`. When - both `StressngStressors` and `Stressors` are defined, `StressngStressors` - wins. - type: string - stressors: - description: Stressors defines plenty of stressors supported to - stress system components out. You can use one or more of them - to make up various kinds of stresses. At least one of the stressors - should be specified. - properties: - cpu: - description: CPUStressor stresses CPU out - properties: - load: - description: Load specifies P percent loading per CPU worker. - 0 is effectively a sleep (no load) and 100 is full loading. - type: integer - options: - description: extend stress-ng options - items: - type: string - type: array - workers: - description: Workers specifies N workers to apply the stressor. - type: integer - required: - - workers - type: object - memory: - description: MemoryStressor stresses virtual memory out - properties: - options: - description: extend stress-ng options + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: items: type: string type: array - size: - description: Size specifies N bytes consumed per vm worker, - default is the total available memory. One can specify - the size as % of total available memory or in units of - B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. - type: string - workers: - description: Workers specifies N workers to apply the stressor. - type: integer - required: - - workers - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the % of pods to do chaos action - type: string - required: - - mode - - selector - type: object - tasks: - items: + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected program. + It's a possibly signed sequence of decimal numbers, such as + "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: type: string - type: array - template_name: - type: string - time_chaos: - description: TimeChaosSpec defines the desired state of TimeChaos - properties: - clockIds: - description: ClockIds defines all affected clock id All available - options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", - "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", - "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] - items: - type: string - type: array - containerNames: - description: ContainerName indicates the name of affected container. - If not set, all containers will be injected - items: - type: string - type: array - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. + workflowName: + type: string + required: + - startTime + - templateName + - type + - workflowName + type: object + status: + description: Most recently observed status of the workflow node + properties: + activeChildren: + description: ActiveChildren means the created children node + items: + description: LocalObjectReference contains enough information to + let you locate the referenced object inside the same namespace. properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object type: object - timeOffset: - description: TimeOffset defines the delta time of injected program. - It's a possibly signed sequence of decimal numbers, such as "300ms", - "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), - "ms", "s", "m", "h". - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - mode - - selector - - timeOffset - type: object - type: - type: string - workflow_name: - type: string - required: - - start_time - - template_name - - type - - workflow_name - type: object - status: - description: Most recently observed status of the workflow node - properties: - active_children: - description: ActiveChildren means the created children node - items: - description: LocalObjectReference contains enough information to let - you locate the referenced object inside the same namespace. - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - type: object - type: array - chaos_resource: - description: ChaosResource refs to the real chaos CR object. - properties: - apiGroup: - description: APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the - core API group. For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - required: - - kind - - name - type: object - conditions: - description: Represents the latest available observations of a worklfow - node's current state. - items: + x-kubernetes-map-type: atomic + type: array + chaosResource: + description: ChaosResource refs to the real chaos CR object. properties: - reason: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. type: string - status: + kind: + description: Kind is the type of resource being referenced type: string - type: + name: + description: Name is the name of resource being referenced type: string required: - - reason - - status - - type + - kind + - name type: object - type: array - expected_children_num: - description: ExpectedChildrenNum means the expected children to execute - type: integer - finished_children: - description: Children is necessary for representing the order when replicated - child template references by parent template. - items: - description: LocalObjectReference contains enough information to let - you locate the referenced object inside the same namespace. + x-kubernetes-map-type: atomic + conditionalBranchesStatus: + description: ConditionalBranchesStatus records the evaluation result + of each ConditionalBranch properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string + branches: + items: + properties: + evaluationResult: + type: string + target: + type: string + required: + - evaluationResult + - target + type: object + type: array + context: + items: + type: string + type: array type: object - type: array - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + conditions: + description: Represents the latest available observations of a workflow + node's current state. + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - reason + - status + - type + type: object + type: array + finishedChildren: + description: Children is necessary for representing the order when + replicated child template references by parent template. + items: + description: LocalObjectReference contains enough information to + let you locate the referenced object inside the same namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: + status: {} diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_workflows.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_workflows.yaml index 48bae7d646..067ddbfa67 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_workflows.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_workflows.yaml @@ -1,11 +1,9 @@ - --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: workflows.chaos-mesh.org spec: group: chaos-mesh.org @@ -16,2079 +14,10137 @@ spec: shortNames: - wf singular: workflow - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a workflow - properties: - entry: - type: string - templates: - items: - properties: - aws_chaos: - description: AwsChaosSpec is the content of the specification - for an AwsChaos - properties: - action: - description: 'Action defines the specific aws chaos action. - Supported action: ec2-stop / ec2-restart / detach-volume - Default action: ec2-stop' - enum: - - ec2-stop - - ec2-restart - - detach-volume - type: string - awsRegion: - description: AwsRegion defines the region of aws. - type: string - deviceName: - description: DeviceName indicates the name of the device. - Needed in detach-volume. - type: string - duration: - description: Duration represents the duration of the chaos - action. - type: string - ec2Instance: - description: Ec2Instance indicates the ID of the ec2 instance. - type: string - endpoint: - description: Endpoint indicates the endpoint of the aws server. - Just used it in test now. - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. - type: string - volumeID: - description: EbsVolume indicates the ID of the EBS volume. - Needed in detach-volume. - type: string - required: - - action - - awsRegion - - ec2Instance - type: object - dns_chaos: - description: DNSChaosSpec defines the desired state of DNSChaos - properties: - action: - description: 'Action defines the specific DNS chaos action. - Supported action: error, random Default action: error' - enum: - - error - - random - type: string - duration: - description: Duration represents the duration of the chaos - action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - patterns: - description: "Choose which domain names to take effect, support - the placeholder ? and wildcard *, or the Specified domain - name. Note: 1. The wildcard * must be at the end of - the string. For example, chaos-*.org is invalid. 2. - if the patterns is empty, will take effect on all the domain - names. For example: \t\tThe value is [\"google.com\", \"github.*\", - \"chaos-mes?.org\"], \t\twill take effect on \"google.com\", - \"github.com\" and \"chaos-mesh.org\"" - items: - type: string - type: array - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, - provide a number from 0-100 to specify the max percent of - pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - duration: - type: string - gcp_chaos: - description: GcpChaosSpec is the content of the specification - for a GcpChaos - properties: - action: - description: 'Action defines the specific gcp chaos action. - Supported action: node-stop / node-reset / disk-loss Default - action: node-stop' - enum: - - node-stop - - node-reset - - disk-loss - type: string - deviceName: - description: The device name of the disk to detach. Needed - in disk-loss. - type: string - duration: - description: Duration represents the duration of the chaos - action. - type: string - instance: - description: Instance defines the name of the instance - type: string - project: - description: Project defines the name of gcp project. - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a workflow + properties: + entry: + type: string + templates: + items: + properties: + abortWithStatusCheck: + description: AbortWithStatusCheck describe whether to abort + the workflow when the failure threshold of StatusCheck is + exceeded. Only used when Type is TypeStatusCheck. + type: boolean + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. + Supported action: ec2-stop / ec2-restart / detach-volume + Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. + Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws + server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. + Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. + Supported action: vm-stop / vm-restart / disk-detach Default + action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. Needed + in disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the + data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. + Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. - It is used for GCP credentials. - type: string - zone: - description: Zone defines the zone of gcp project. - type: string - required: - - action - - instance - - project - - zone - type: object - http_chaos: - properties: - action: - description: 'Action defines the specific pod chaos action. - Supported action: delay | abort | mixed Default action: - delay' - enum: - - delay - - abort - - mixed - type: string - duration: - description: Duration represents the duration of the chaos - action. It is required when the action is `PodFailureAction`. - 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". - type: string - headers: - description: Specifies how the header match will be performed - to route the request. - items: + type: array + delay: + description: Delay defines the delay distribution. properties: - exact_match: - type: string - invert_match: - type: string - name: - type: string - prefix_match: - type: string - present_match: - type: string - range_match: + correlation: type: string - regex_match: + jitter: type: string - safe_regex_match: + latency: + description: Latency defines the latency of every io + request. type: string - suffix_match: - type: string - required: - - name type: object - type: array - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - percent: - description: 'Percent defines the percentage of injection - errors and provides a number from 0-100. default: 100.' - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: + duration: + description: Duration represents the duration of the chaos + action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - action - - mode - - selector - type: object - io_chaos: - description: IoChaosSpec defines the desired state of IoChaos - properties: - action: - description: 'Action defines the specific pod chaos action. - Supported action: latency / fault / attrOverride / mistake' - enum: - - latency - - fault - - attrOverride - - mistake - type: string - attr: - description: Attr defines the overrided attribution - properties: - atime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - blocks: - format: int64 - type: integer - ctime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - gid: - format: int32 - type: integer - ino: - format: int64 - type: integer - kind: - description: FileType represents type of a file - type: string - mtime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - nlink: - format: int32 - type: integer - perm: - type: integer - rdev: - format: int32 - type: integer - size: - format: int64 - type: integer - uid: - format: int32 - type: integer - type: object - containerName: - description: ContainerName indicates the target container - to inject iochaos in - type: string - delay: - description: Delay defines the value of I/O chaos action delay. - A delay string is a possibly signed sequence of decimal - numbers, each with optional fraction and a unit suffix, - such as "300ms". Valid time units are "ns", "us" (or "µs"), - "ms", "s", "m", "h". - type: string - duration: - description: Duration represents the duration of the chaos - action. It is required when the action is `PodFailureAction`. - 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". - type: string - errno: - description: 'Errno defines the error code that returned by - I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' - format: int32 - type: integer - methods: - description: 'Methods defines the I/O methods for injecting - I/O chaos action. default: all I/O methods.' - items: - type: string - type: array - mistake: - description: Mistake defines what types of incorrectness are - injected to IO operations - properties: - filling: - description: Filling determines what is filled in the - miskate data. - enum: - - zero - - random - type: string - maxLength: - description: Max length of each wrong data segment in - bytes - format: int64 - minimum: 1 - type: integer - maxOccurrences: - description: There will be [1, MaxOccurrences] segments - of wrong data. - format: int64 - minimum: 1 - type: integer - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - path: - description: Path defines the path of files for injecting - I/O chaos action. - type: string - percent: - description: 'Percent defines the percentage of injection - errors and provides a number from 0-100. default: 100.' - type: integer - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - volumePath: - description: VolumePath represents the mount path of injected - volume - type: string - required: - - action - - mode - - selector - - volumePath - type: object - jvm_chaos: - description: JVMChaosSpec defines the desired state of JVMChaos - properties: - action: - description: 'Action defines the specific jvm chaos action. - Supported action: delay;return;script;cfl;oom;ccf;tce;cpf;tde;tpf' - enum: - - delay - - return - - script - - cfl - - oom - - ccf - - tce - - cpf - - tde - - tpf - type: string - duration: - description: Duration represents the duration of the chaos - action - type: string - flags: - additionalProperties: + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action type: string - description: Flags represents the flags of action - type: object - matchers: - additionalProperties: + volumeName: type: string - description: Matchers represents the matching rules for the - target - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' + required: + - action + - mode + - selector + - volumeName + type: object + children: + description: Children describes the children steps of serial + or parallel node. Only used when Type is TypeSerial or TypeParallel. + items: type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. + type: array + conditionalBranches: + description: ConditionalBranches describes the conditional branches + of custom tasks. Only used when Type is TypeTask. + items: properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" + expression: + description: Expression is the expression for this conditional + branch, expected type of result is boolean. If expression + is empty, this branch will always be selected/the template + will be spawned. + type: string + target: + description: Target is the name of other template, if + expression is evaluated as true, this template will + be spawned. type: string required: - - cron + - target type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: + type: array + deadline: + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos action. + Supported action: error, random Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, + support the placeholder ? and wildcard *, or the Specified + domain name. Note: 1. The wildcard * must be at the end + of the string. For example, chaos-*.org is invalid. 2. + if the patterns is empty, will take effect on all the + domain names. For example: The value is ["google.com", + "github.*", "chaos-mes?.org"], will take effect on "google.com", + "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - target: - description: 'Target defines the specific jvm chaos target. - Supported target: servlet;psql;jvm;jedis;http;dubbo;rocketmq;tars;mysql;druid;redisson;rabbitmq;mongodb' - enum: - - servlet - - psql - - jvm - - jedis - - http - - dubbo - - rocketmq - - tars - - mysql - - druid - - redisson - - rabbitmq - - mongodb - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the % of pods to do chaos - action - type: string - required: - - action - - mode - - selector - - target - type: object - kernel_chaos: - description: KernelChaosSpec defines the desired state of KernelChaos - properties: - duration: - description: Duration represents the duration of the chaos - action - type: string - failKernRequest: - description: FailKernRequest defines the request of kernel - injection - properties: - callchain: - description: 'Callchain indicate a special call chain, - such as: ext4_mount -> mount_subtree -> - ... -> should_failslab With an optional - set of predicates and an optional set of parameters, - which used with predicates. You can read call chan and - predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples - to learn more. If no special call chain, just keep Callchain - empty, which means it will fail at any call chain with - slab alloc (eg: kmalloc).' - items: - description: Frame defines the function signature and - predicate in function's body - properties: - funcname: - description: Funcname can be find from kernel source - or `/proc/kallsyms`, such as `ext4_mount` - type: string - parameters: - description: Parameters is used with predicate, - for example, if you want to inject slab error - in `d_alloc_parallel(struct dentry *parent, const - struct qstr *name)` with a special name `bananas`, - you need to set it to `struct dentry *parent, - const struct qstr *name` otherwise omit it. - type: string - predicate: - description: Predicate will access the arguments - of this Frame, example with Parameters's, you - can set it to `STRNCMP(name->name, "bananas", - 8)` to make inject only with it, or omit it to - inject for all d_alloc_parallel call chain. - type: string - type: object - type: array - failtype: - description: 'FailType indicates what to fail, can be - set to ''0'' / ''1'' / ''2'' If `0`, indicates slab - to fail (should_failslab) If `1`, indicates alloc_page - to fail (should_fail_alloc_page) If `2`, indicates bio - to fail (should_fail_bio) You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html 2. - http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt - to learn more' - format: int32 - maximum: 2 - minimum: 0 - type: integer - headers: - description: 'Headers indicates the appropriate kernel - headers you need. Eg: "linux/mmzone.h", "linux/blkdev.h" - and so on' - items: - type: string - type: array - probability: - description: Probability indicates the fails with probability. - If you want 1%, please set this field with 1. - format: int32 - maximum: 100 - minimum: 0 - type: integer - times: - description: Times indicates the max times of fails. - format: int32 - minimum: 0 - type: integer - required: - - failtype - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - failKernRequest - - mode - - selector - type: object - name: - type: string - network_chaos: - description: NetworkChaosSpec defines the desired state of NetworkChaos - properties: - action: - description: 'Action defines the specific network chaos action. - Supported action: partition, netem, delay, loss, duplicate, - corrupt Default action: delay' - enum: - - netem - - delay - - loss - - duplicate - - corrupt - - partition - - bandwidth - type: string - bandwidth: - description: Bandwidth represents the detail about bandwidth - control action - properties: - buffer: - description: Buffer is the maximum amount of bytes that - tokens can be available for instantaneously. - format: int32 - minimum: 1 - type: integer - limit: - description: Limit is the number of bytes that can be - queued waiting for tokens to become available. - format: int32 - minimum: 1 - type: integer - minburst: - description: Minburst specifies the size of the peakrate - bucket. For perfect accuracy, should be set to the MTU - of the interface. If a peakrate is needed, but some - burstiness is acceptable, this size can be raised. A - 3000 byte minburst allows around 3mbit/s of peakrate, - given 1000 byte packets. - format: int32 - minimum: 0 - type: integer - peakrate: - description: Peakrate is the maximum depletion rate of - the bucket. The peakrate does not need to be set, it - is only necessary if perfect millisecond timescale shaping - is required. - format: int64 - minimum: 0 - type: integer - rate: - description: Rate is the speed knob. Allows bps, kbps, - mbps, gbps, tbps unit. bps means bytes per second. - type: string - required: - - buffer - - limit - - rate - type: object - corrupt: - description: Corrupt represents the detail about corrupt action - properties: - correlation: - type: string - corrupt: - type: string - required: - - correlation - - corrupt - type: object - delay: - description: Delay represents the detail about delay action - properties: - correlation: - type: string - jitter: - type: string - latency: - type: string - reorder: - description: ReorderSpec defines details of packet reorder. - properties: - correlation: - type: string - gap: - type: integer - reorder: - type: string - required: - - correlation - - gap - - reorder - type: object - required: - - latency - type: object - direction: - description: Direction represents the direction, this applies - on netem and network partition action - enum: - - to - - from - - both - - "" - type: string - duplicate: - description: DuplicateSpec represents the detail about loss - action - properties: - correlation: - type: string - duplicate: - type: string - required: - - correlation - - duplicate - type: object - duration: - description: Duration represents the duration of the chaos - action - type: string - externalTargets: - description: ExternalTargets represents network targets outside - k8s - items: - type: string - type: array - loss: - description: Loss represents the detail about loss action - properties: - correlation: - type: string - loss: - type: string - required: - - correlation - - loss - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - target: - description: Target represents network target, this applies - on netem and network partition action - properties: - mode: - description: TargetMode defines the target selector mode - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - - "" - type: string - selector: - description: TargetSelector defines the target selector - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can - be used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions - that can be used to select objects. A list of selectors - based on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can - be used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can - be used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. + pods: + additionalProperties: items: type: string type: array - nodeSelectors: - additionalProperties: + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. + Supported action: node-stop / node-reset / disk-loss Default + action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed + in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status + code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, + such as "300ms", "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + method: + description: Method is a rule to select target by http method + in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of + target. + properties: + type: + description: Type represents the patch type, only + support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. type: string - description: Map of string keys and values that can - be used to select nodes. Selector which must match - a node's labels, and objects must belong to these - selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects - must belong to these nodes. + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], + ["Set-Cookie", ""]]`.' + items: items: type: string type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", "bar"], + ["foo", "unknown"]]`.' + items: items: type: string type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set - values that used to select pods. The key defines - the namespace which pods belong, and the each values - is a set of pod names. - type: object - type: object - value: - description: TargetValue is required when the mode is - set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - If `FixedPodMode`, provide an integer of pods to do - chaos action. If `FixedPercentPodMod`, provide a number - from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods - to do chaos action - type: string - required: - - mode - - selector - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - action - - mode - - selector - type: object - pod_chaos: - description: PodChaosSpec defines the attributes that a user creates - on a chaos experiment about pods. - properties: - action: - description: 'Action defines the specific pod chaos action. - Supported action: pod-kill / pod-failure / container-kill - Default action: pod-kill' - enum: - - pod-kill - - pod-failure - - container-kill - type: string - containerName: - description: ContainerName indicates the name of the container. - Needed in container-kill. - type: string - duration: - description: Duration represents the duration of the chaos - action. It is required when the action is `PodFailureAction`. - 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". - type: string - gracePeriod: - description: GracePeriod is used in pod-kill action. It represents - the duration in seconds before the pod should be deleted. - Value must be non-negative integer. The default value is - zero that indicates delete immediately. - format: int64 - minimum: 0 - type: integer - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: + type: array + type: object + path: + description: Path is a rule to select target by uri path + in http request. + type: string + port: + description: Port represents the target port to be proxy + of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http message + body in target. + format: byte type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator + code: + description: Code is a rule to replace http status code + in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header name + and header value pairs. type: object - type: array - fieldSelectors: - additionalProperties: + method: + description: Method is a rule to replace http method + in request. type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: + path: + description: Path is rule to to replace uri path in + http request. type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: + queries: + additionalProperties: type: string - type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - action - - mode - - selector - type: object - stress_chaos: - description: StressChaosSpec defines the desired state of StressChaos - properties: - containerName: - description: ContainerName indicates the target container - to inject stress in - type: string - duration: - description: Duration represents the duration of the chaos - action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": + "unknown" }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: + description: RequestHeaders is a rule to select target by + http headers in request. The key-value pairs represent + header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target + by http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - stressngStressors: - description: StressngStressors defines plenty of stressors - just like `Stressors` except that it's an experimental feature - and more powerful. You can define stressors in `stress-ng` - (see also `man stress-ng`) dialect, however not all of the - supported stressors are well tested. It maybe retired in - later releases. You should always use `Stressors` to define - the stressors and use this only when you want more stressors - unsupported by `Stressors`. When both `StressngStressors` - and `Stressors` are defined, `StressngStressors` wins. - type: string - stressors: - description: Stressors defines plenty of stressors supported - to stress system components out. You can use one or more - of them to make up various kinds of stresses. At least one - of the stressors should be specified. - properties: - cpu: - description: CPUStressor stresses CPU out - properties: - load: - description: Load specifies P percent loading per - CPU worker. 0 is effectively a sleep (no load) and - 100 is full loading. - type: integer - options: - description: extend stress-ng options - items: - type: string - type: array - workers: - description: Workers specifies N workers to apply - the stressor. - type: integer - required: - - workers - type: object - memory: - description: MemoryStressor stresses virtual memory out - properties: - options: - description: extend stress-ng options + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: items: type: string type: array - size: - description: Size specifies N bytes consumed per vm - worker, default is the total available memory. One - can specify the size as % of total available memory - or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. - type: string - workers: - description: Workers specifies N workers to apply - the stressor. - type: integer - required: - - workers - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the % of pods to do chaos - action - type: string - required: - - mode - - selector - type: object - tasks: - items: - type: string - type: array - template_type: - type: string - time_chaos: - description: TimeChaosSpec defines the desired state of TimeChaos - properties: - clockIds: - description: ClockIds defines all affected clock id All available - options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", - "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", - "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] - items: - type: string - type: array - containerNames: - description: ContainerName indicates the name of affected - container. If not set, all containers will be injected - items: - type: string - type: array - duration: - description: Duration represents the duration of the chaos - action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file + in secret, `ca.crt` for example type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. + certName: + description: CertName represents the data name of cert + file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of key + file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required + secret resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace + of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. + Supported action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: - type: string - type: array + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer required: - - key - - operator + - nsec + - sec type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action + delay. A delay string is a possibly signed sequence of + decimal numbers, each with optional fraction and a unit + suffix, such as "300ms". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos + action. It is required when the action is `PodFailureAction`. + 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". + type: string + errno: + description: 'Errno defines the error code that returned + by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting + I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled in the + mistake data. + enum: + - zero + - random type: string - type: array - pods: - additionalProperties: - items: + maxLength: + description: Max length of each wrong data segment in + bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting + I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection + errors and provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected + volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. + Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only set + it when action is stress + type: integer + database: + description: the match database default value is "", means + match all database + type: string + duration: + description: Duration represents the duration of the chaos + action + type: string + exception: + description: the exception which needs to throw for action + `exception` or the exception message needs to throw in + action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it + when action is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will + generate one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel + injection + properties: + callchain: + description: 'Callchain indicate a special call chain, + such as: ext4_mount -> mount_subtree -> ... -> should_failslab + With an optional set of predicates and an optional + set of parameters, which used with predicates. You + can read call chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep + Callchain empty, which means it will fail at any call + chain with slab alloc (eg: kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from kernel + source or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab error + in `d_alloc_parallel(struct dentry *parent, + const struct qstr *name)` with a special name + `bananas`, you need to set it to `struct dentry + *parent, const struct qstr *name` otherwise + omit it. + type: string + predicate: + description: Predicate will access the arguments + of this Frame, example with Parameters's, you + can set it to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, or omit it + to inject for all d_alloc_parallel call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be + set to ''0'' / ''1'' / ''2'' If `0`, indicates slab + to fail (should_failslab) If `1`, indicates alloc_page + to fail (should_fail_alloc_page) If `2`, indicates + bio to fail (should_fail_bio) You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel + headers you need. Eg: "linux/mmzone.h", "linux/blkdev.h" + and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + name: + type: string + networkChaos: + description: NetworkChaosSpec defines the desired state of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos + action. Supported action: partition, netem, delay, loss, + duplicate, corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes that + tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be + queued waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate + bucket. For perfect accuracy, should be set to the + MTU of the interface. If a peakrate is needed, but + some burstiness is acceptable, this size can be raised. + A 3000 byte minburst allows around 3mbit/s of peakrate, + given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate + of the bucket. The peakrate does not need to be set, + it is only necessary if perfect millisecond timescale + shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, + mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt + action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be + affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies + on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss + action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos + action + type: string + externalTargets: + description: ExternalTargets represents network targets + outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control + action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, + mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + target: + description: Target represents network target, this applies + on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device + to be affected in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired state + of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one + of Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock + on which to act. More clock description in linux kernel + can be found in man page of clock_getres, clock_gettime, + clock_settime. Muti clock ids should be split with + "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. + if path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. + if path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on + writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. + if path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on + writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos + action + type: string + file-append: + properties: + count: + description: Count is the number of times to append + the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the + file. + type: string + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to + be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http + status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside + proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by http + status code in response + type: string + delay: + description: Delay represents the delay of the target + request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside + proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for + action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', + unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", + means match all database + type: string + exception: + description: The exception which needs to throw for + action `exception` or the exception message needs + to throw in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' + or the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only + support 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", + means match all SQL type. The value can be 'select', + 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, + will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set + it when action is stress + type: integer + mem-type: + description: the memory type need to locate, only set + it when action is stress, the value can be 'stack' + or 'heap' + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is + 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag + can be accepted, others will be dropped. only set + when the IPProtocol is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or + µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf + test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads + to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP + address + type: string + rate: + description: The speed of network traffic, allows bps, + kbps, mbps, gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag + can be accepted, others will be dropped. only set + when the IPProtocol is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values + can be 'from', 'to'. 'from' means packets coming from + the 'IPAddress' or 'Hostname' and going to your server, + 'to' means packets originating from your server and + going to the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP + addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of + the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to + flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to + flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string keys + and a set values that used to select physical machines. + The key defines the namespace which physical machine + belong, and each value is a set of physical machine + names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. + 0 is effectively a sleep (no load) and 100 is full + loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, + default is the total available memory. One can specify + the size as % of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to + specify the percent of physical machines the server can + do chaos action. IF `RandomMaxPercentMode`, provide a + number from 0-100 to specify the max percent of pods to + do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a user + creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos action. + Supported action: pod-kill / pod-failure / container-kill + Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action. It is required when the action is `PodFailureAction`. + 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It + represents the duration in seconds before the pod should + be deleted. Value must be non-negative integer. The default + value is zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + description: Schedule describe the Schedule(describing scheduled + chaos) to be injected with chaos nodes. Only used when Type + is TypeSchedule. + properties: + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos + action. Supported action: ec2-stop / ec2-restart / + detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. + Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 + instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the + aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. + Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos + action. Supported action: vm-stop / vm-restart / disk-detach + Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. + Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of + the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure + subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos + action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every + io request. + type: string + type: object + duration: + description: Duration represents the duration of the + chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos + action. Supported action: error, random Default action: + error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, + support the placeholder ? and wildcard *, or the Specified + domain name. Note: 1. The wildcard * must be at the + end of the string. For example, chaos-*.org is invalid. + 2. if the patterns is empty, will take effect on all + the domain names. For example: The value is ["google.com", + "github.*", "chaos-mes?.org"], will take effect on + "google.com", "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos + action. Supported action: node-stop / node-reset / + disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed + in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http + status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target + request/response. A duration string is a possibly + unsigned sequence of decimal numbers, each with optional + fraction and a unit suffix, such as "300ms", "2h45m". + Valid time units are "ns", "us" (or "µs"), "ms", "s", + "m", "h". + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + method: + description: Method is a rule to select target by http + method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. + properties: + body: + description: Body is a rule to patch message body + of target. + properties: + type: + description: Type represents the patch type, + only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", + "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri + path in http request. + type: string + port: + description: Port represents the target port to be proxy + of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http message + body in target. + format: byte + type: string + code: + description: Code is a rule to replace http status + code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header + name and header value pairs. + type: object + method: + description: Method is a rule to replace http method + in request. + type: string + path: + description: Path is rule to to replace uri path + in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": + "unknown" }`, the `/?foo=bar` will be altered + to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target + by http headers in request. The key-value pairs represent + header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target + by http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and + injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of + ca file in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name of + cert file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of + key file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required + secret resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace + of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: latency / fault / attrOverride + / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action + delay. A delay string is a possibly signed sequence + of decimal numbers, each with optional fraction and + a unit suffix, such as "300ms". Valid time units are + "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the + chaos action. It is required when the action is `PodFailureAction`. + 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". + type: string + errno: + description: 'Errno defines the error code that returned + by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting + I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled in + the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment + in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting + I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection + errors and provides a number from 0-100. default: + 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path of + injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos + action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only + set it when action is stress + type: integer + database: + description: the match database default value is "", + means match all database + type: string + duration: + description: Duration represents the duration of the + chaos action + type: string + exception: + description: the exception which needs to throw for + action `exception` or the exception message needs + to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set + it when action is stress, the value can be 'stack' + or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only + support 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and + will generate one if not set + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", + means match all SQL type. The value can be 'select', + 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of + KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of + kernel injection + properties: + callchain: + description: 'Callchain indicate a special call + chain, such as: ext4_mount -> mount_subtree -> + ... -> should_failslab With an optional set of + predicates and an optional set of parameters, + which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just + keep Callchain empty, which means it will fail + at any call chain with slab alloc (eg: kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from kernel + source or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab + error in `d_alloc_parallel(struct dentry + *parent, const struct qstr *name)` with + a special name `bananas`, you need to set + it to `struct dentry *parent, const struct + qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments + of this Frame, example with Parameters's, + you can set it to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, or omit + it to inject for all d_alloc_parallel call + chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can + be set to ''0'' / ''1'' / ''2'' If `0`, indicates + slab to fail (should_failslab) If `1`, indicates + alloc_page to fail (should_fail_alloc_page) If + `2`, indicates bio to fail (should_fail_bio) You + can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with + probability. If you want 1%, please set this field + with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state + of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos + action. Supported action: partition, netem, delay, + loss, duplicate, corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes + that tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can + be queued waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the + peakrate bucket. For perfect accuracy, should + be set to the MTU of the interface. If a peakrate + is needed, but some burstiness is acceptable, + this size can be raised. A 3000 byte minburst + allows around 3mbit/s of peakrate, given 1000 + byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate + of the bucket. The peakrate does not need to be + set, it is only necessary if perfect millisecond + timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, + kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, + tbps unit. bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt + action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay + action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet + reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to + be affected. + type: string + direction: + default: to + description: Direction represents the direction, this + applies on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about + loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the + chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets + outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control + action + properties: + rate: + description: Rate is the speed knob. Allows bit, + kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, + tbps unit. bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this + applies on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device + to be affected in target scope. + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired + state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only + one of Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock + on which to act. More clock description in linux + kernel can be found in man page of clock_getres, + clock_gettime, clock_settime. Muti clock ids should + be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + payload-process-num: + description: specifies the number of process work + on writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + payload-process-num: + description: specifies the number of process work + on writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the + chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to append + the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to + be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of + the file. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file + to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the + file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by + http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP + connection, we will only attack HTTP connection + with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by + http status code in response + type: string + delay: + description: Delay represents the delay of the target + request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP + connection, we will only attack HTTP connection + with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support + GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw + for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', + unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is + "", means match all database + type: string + exception: + description: The exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' + or the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set to + "8") now + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is + "", means match all SQL type. The value can be + 'select', 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", + means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's + data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only + set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, only + set it when action is stress, the value can be + 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp + flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used for + partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or + µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf + test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client + threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the + IP address + type: string + rate: + description: The speed of network traffic, allows + bps, kbps, mbps, gbps, tbps unit. bps means bytes + per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is + 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp + flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used for + partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means packets + coming from the 'IPAddress' or 'Hostname' and + going to your server, 'to' means packets originating + from your server and going to the 'IPAddress' + or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these + IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering + experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string + keys and a set values that used to select physical + machines. The key defines the namespace which + physical machine belong, and each value is a set + of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU + worker. 0 is effectively a sleep (no load) and + 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, + default is the total available memory. One can + specify the size as % of total available memory + or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of physical machines + to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of physical + machines the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a + user creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: pod-kill / pod-failure / + container-kill Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action. It is required when the action is `PodFailureAction`. + 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. + It represents the duration in seconds before the pod + should be deleted. Value must be non-negative integer. + The default value is zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired state of + StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors + just like `Stressors` except that it's an experimental + feature and more powerful. You can define stressors + in `stress-ng` (see also `man stress-ng`) dialect, + however not all of the supported stressors are well + tested. It maybe retired in later releases. You should + always use `Stressors` to define the stressors and + use this only when you want more stressors unsupported + by `Stressors`. When both `StressngStressors` and + `Stressors` are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported + to stress system components out. You can use one or + more of them to make up various kinds of stresses. + At least one of the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading + per CPU worker. 0 is effectively a sleep (no + load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to + apply the stressor. Maximum 8192 workers can + run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory + out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` to + know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % of total + available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to + apply the stressor. Maximum 8192 workers can + run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state of + TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id + All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected + program. It's a possibly signed sequence of decimal + numbers, such as "300ms", "-1.5h" or "2h45m". Valid + time units are "ns", "us" (or "µs"), "ms", "s", "m", + "h". + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + required: + - schedule + - type + type: object + statusCheck: + description: StatusCheck describe the behavior of StatusCheck. + Only used when Type is TypeStatusCheck. + properties: + duration: + description: Duration defines the duration of the whole + status check if the number of failed execution does not + exceed the failure threshold. Duration is available to + both `Synchronous` and `Continuous` mode. 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum consecutive + failure for the status check to be considered failed. + minimum: 1 + type: integer + http: + properties: + body: + type: string + criteria: + description: Criteria defines how to determine the result + of the status check. + properties: + statusCode: + description: StatusCode defines the expected http + status code for the request. A statusCode string + could be a single code (e.g. 200), or an inclusive + range (e.g. 200-400, both `200` and `400` are + included). + type: string + required: + - statusCode + type: object + headers: + additionalProperties: + items: + type: string + type: array + description: "A Header represents the key-value pairs + in an HTTP header. \n The keys should be in canonical + form, as returned by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in seconds) + to perform an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of the status + check. Support type: Synchronous / Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number of record + to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum consecutive + successes for the status check to be considered successful. + SuccessThreshold only works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of seconds + after which an execution of status check times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check type. + Support type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + stressChaos: + description: StressChaosSpec defines the desired state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors + just like `Stressors` except that it's an experimental + feature and more powerful. You can define stressors in + `stress-ng` (see also `man stress-ng`) dialect, however + not all of the supported stressors are well tested. It + maybe retired in later releases. You should always use + `Stressors` to define the stressors and use this only + when you want more stressors unsupported by `Stressors`. + When both `StressngStressors` and `Stressors` are defined, + `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported + to stress system components out. You can use one or more + of them to make up various kinds of stresses. At least + one of the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading per + CPU worker. 0 is effectively a sleep (no load) + and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to apply + the stressor. Maximum 8192 workers can run by + stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory + out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` to know + more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per + vm worker, default is the total available memory. + One can specify the size as % of total available + memory or in units of B, KB/KiB, MB/MiB, GB/GiB, + TB/TiB. + type: string + workers: + description: Workers specifies N workers to apply + the stressor. Maximum 8192 workers can run by + stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - mode + - selector + type: object + task: + description: Task describes the behavior of the custom task. + Only used when Type is TypeTask. + properties: + container: + description: Container is the main container image to run + in the pod + properties: + args: + description: 'Arguments to the entrypoint. The container + image''s CMD is used if this is not provided. Variable + references $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, the + reference in the input string will be unchanged. Double + $$ are reduced to a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Cannot be updated. More info: + https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The container image''s ENTRYPOINT is used + if this is not provided. Variable references $(VAR_NAME) + are expanded using the container''s environment. If + a variable cannot be resolved, the reference in the + input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable exists + or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set in + the container. Cannot be updated. + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined environment + variables in the container and any service environment + variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults + to "".' + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: + supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, + requests.cpu, requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in + the pod's namespace + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined within + a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container is + starting. When a key exists in multiple sources, the + value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will + take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source of + a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config + management to default or override container images + in workload controllers like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, + IfNotPresent. Defaults to Always if :latest tag is + specified, or IfNotPresent otherwise. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system should + take in response to container lifecycle events. Cannot + be updated. + properties: + postStart: + description: 'PostStart is called immediately after + a container is created. If the handler fails, + the container is terminated and restarted according + to its restart policy. Other management of the + container blocks until the hook completes. More + info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of + this field and lifecycle hooks will fail in + runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately before + a container is terminated due to an API request + or management event such as liveness/startup probe + failure, preemption, resource contention, etc. + The handler is not called if the container crashes + or exits. The Pod''s termination grace period + countdown begins before the PreStop hook is executed. + Regardless of the outcome of the handler, the + container will eventually terminate within the + Pod''s termination grace period (unless delayed + by finalizers). Other management of the container + blocks until the hook completes or until the termination + grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of + this field and lifecycle hooks will fail in + runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. Cannot + be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. + Not specifying a port here DOES NOT prevent that port + from being exposed. Any port which is listening on + the default "0.0.0.0" address inside a container will + be accessible from the network. Modifying this array + with strategic merge patch may corrupt the data. For + more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port + in a single container. + properties: + containerPort: + description: Number of port to expose on the pod's + IP address. This must be a valid port number, + 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on the host. + If specified, this must be a valid port number, + 0 < x < 65536. If HostNetwork is specified, + this must match ContainerPort. Most containers + do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an IANA_SVC_NAME + and unique within the pod. Each named port in + a pod must have a unique name. Name for the + port that can be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, TCP, + or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service readiness. + Container will be removed from service endpoints if + the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource + resize policy for the container. + properties: + resourceName: + description: 'Name of the resource to which this + resource resize policy applies. Supported values: + cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when specified + resource is resized. If not specified, it defaults + to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this container. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, + defined in spec.resourceClaims, that are used + by this container. \n This is an alpha field and + requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can + only be set for containers." + items: + description: ResourceClaim references one entry + in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one + entry in pod.spec.resourceClaims of the + Pod where this field is used. It makes that + resource available inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount + of compute resources required. If Requests is + omitted for a container, it defaults to Limits + if that is explicitly specified, otherwise to + an implementation-defined value. Requests cannot + exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + restartPolicy: + description: 'RestartPolicy defines the restart behavior + of individual containers in a pod. This field may + only be set for init containers, and the only allowed + value is "Always". For non-init containers or when + this field is not specified, the restart behavior + is defined by the Pod''s restart policy and the container + type. Setting the RestartPolicy as "Always" for the + init container will have the following effect: this + init container will be continually restarted on exit + until all regular containers have terminated. Once + all regular containers have completed, all init containers + with restartPolicy "Always" will be shut down. This + lifecycle differs from normal init containers and + is often referred to as a "sidecar" container. Although + this init container still starts in the init container + sequence, it does not wait for the container to complete + before proceeding to the next init container. Instead, + the next init container starts immediately after this + init container is started, or after any startupProbe + has successfully completed.' + type: string + securityContext: + description: 'SecurityContext defines the security options + the container should be run with. If set, the fields + of SecurityContext override the equivalent fields + of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges than + its parent process. This bool directly controls + if the no_new_privs flag will be set on the container + process. AllowPrivilegeEscalation is true always + when the container is: 1) run as Privileged 2) + has CAP_SYS_ADMIN Note that this field cannot + be set when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running + containers. Defaults to the default set of capabilities + granted by the container runtime. Note that this + field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes + in privileged containers are essentially equivalent + to root on the host. Defaults to false. Note that + this field cannot be set when spec.os.name is + windows. + type: boolean + procMount: + description: procMount denotes the type of proc + mount to use for the containers. The default is + DefaultProcMount which uses the container runtime + defaults for readonly paths and masked paths. + This requires the ProcMountType feature flag to + be enabled. Note that this field cannot be set + when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only + root filesystem. Default is false. Note that this + field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the + container process. Uses runtime default if unset. + May also be set in PodSecurityContext. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run + as a non-root user. If true, the Kubelet will + validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start + the container if it does. If unset or false, no + such validation will be performed. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in + SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the + container process. Defaults to user specified + in image metadata if unspecified. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in + SecurityContext takes precedence. Note that this + field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to + the container. If unspecified, the container runtime + will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + properties: + level: + description: Level is SELinux level label that + applies to the container. + type: string + role: + description: Role is a SELinux role label that + applies to the container. + type: string + type: + description: Type is a SELinux type label that + applies to the container. + type: string + user: + description: User is a SELinux user label that + applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this + container. If seccomp options are provided at + both the pod & container level, the container + options override the pod options. Note that this + field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. + The profile must be preconfigured on the node + to work. Must be a descending path, relative + to the kubelet's configured seccomp profile + location. Must be set if type is "Localhost". + Must NOT be set for any other type. + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: + \n Localhost - a profile defined in a file + on the node should be used. RuntimeDefault + - the container runtime default profile should + be used. Unconfined - no profile should be + applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options + from the PodSecurityContext will be used. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the + GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name + of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. + All of a Pod's containers must have the same + effective HostProcess value (it is not allowed + to have a mix of HostProcess containers and + non-HostProcess containers). In addition, + if HostProcess is true then HostNetwork must + also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run + the entrypoint of the container process. Defaults + to the user specified in image metadata if + unspecified. May also be set in PodSecurityContext. + If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the Pod has + successfully initialized. If specified, no other probes + are executed until this completes successfully. If + this probe fails, the Pod will be restarted, just + as if the livenessProbe failed. This can be used to + provide different probe parameters at the beginning + of a Pod''s lifecycle, when it might take a long time + to load data or warm a cache, than during steady-state + operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will + always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close + the stdin channel after it has been opened by a single + attach. When stdin is true the stdin stream will remain + open across multiple attach sessions. If stdinOnce + is set to true, stdin is opened on container start, + is empty until the first client attaches to stdin, + and then remains open and accepts data until the client + disconnects, at which time stdin is closed and remains + closed until the container is restarted. If this flag + is false, a container processes that reads from stdin + will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to which + the container''s termination message will be written + is mounted into the container''s filesystem. Message + written is intended to be brief final status, such + as an assertion failure message. Will be truncated + by the node if greater than 4096 bytes. The total + message length across all containers will be limited + to 12kb. Defaults to /dev/termination-log. Cannot + be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message should + be populated. File will use the contents of terminationMessagePath + to populate the container status message on both success + and failure. FallbackToLogsOnError will use the last + chunk of container log output if the termination message + file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, + whichever is smaller. Defaults to File. Cannot be + updated. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices + to be used by the container. + items: + description: volumeDevice describes a mapping of a + raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside of + the container that the device will be mapped + to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting of a + Volume within a container. + properties: + mountPath: + description: Path within the container at which + the volume should be mounted. Must not contain + ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts + are propagated from the host to container and + the other way around. When not set, MountPropagationNone + is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write + otherwise (false or unspecified). Defaults to + false. + type: boolean + subPath: + description: Path within the volume from which + the container's volume should be mounted. Defaults + to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from + which the container's volume should be mounted. + Behaves similarly to SubPath but environment + variable references $(VAR_NAME) are expanded + using the container's environment. Defaults + to "" (volume's root). SubPathExpr and SubPath + are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not specified, + the container runtime's default will be used, which + might be configured in the container image. Cannot + be updated. + type: string + required: + - name + type: object + volumes: + description: Volumes is a list of volumes that can be mounted + by containers in a template. + items: + description: Volume represents a named volume in a pod + that may be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents an AWS + Disk resource that is attached to a kubelet''s host + machine and then exposed to the pod. More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in the + volume that you want to mount. If omitted, the + default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for + /dev/sda is "0" (or you can leave the property + empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force the + readOnly setting in VolumeMounts. More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the persistent + disk resource in AWS (Amazon EBS volume). More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data Disk + mount on the host and bind mount to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching + mode: None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data + disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in + the blob storage + type: string + fsType: + description: fsType is Filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: + multiple blob disks per storage account Dedicated: + single blob disk per storage account Managed: + azure managed data disk (only in managed availability + set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File Service + mount on the host and bind mount to the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret + that contains Azure Storage Account Name and + Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount on + the host that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors is + a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the mounted + root, rather than the full Ceph tree, default + is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile + is the path to key ring for User, default is + /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef + is reference to the authentication secret for + User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the rados + user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume attached + and mounted on kubelets host machine. More info: + https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Examples: "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points to + a secret object containing parameters used to + connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the volume + in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that + should populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced ConfigMap + will be projected into the volume as a file + whose name is the key and content is the value. + If specified, the listed keys will be projected + into the specified paths, and unlisted keys + will not be present. If a key is specified which + is not present in the ConfigMap, the volume + setup will error unless it is marked optional. + Paths must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 and + 0777 or a decimal value between 0 and + 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. If not specified, the volume + defaultMode will be used. This might be + in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path of + the file to map the key to. May not be + an absolute path. May not contain the + path element '..'. May not start with + the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents + ephemeral storage that is handled by certain external + CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI driver + that handles this volume. Consult with your + admin for the correct name as registered in + the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", "xfs", + "ntfs". If not provided, the empty value is + passed to the associated CSI driver which will + determine the default filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference + to the secret object containing sensitive information + to pass to the CSI driver to complete the CSI + NodePublishVolume and NodeUnpublishVolume calls. + This field is optional, and may be empty if + no secret is required. If the secret object + contains more than one secret, all secret references + are passed. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only configuration + for the volume. Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. + Consult your driver's documentation for supported + values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API about + the pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on created + files by default. Must be a Optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: Items is a list of downward API volume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, + defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used to + set permissions on this file, must be + an octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML + accepts both octal and decimal values, + JSON requires decimal values for mode + bits. If not specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must + not be absolute or contain the ''..'' + path. Must be utf-8 encoded. The first + item of the relative path must not start + with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the + container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu + and requests.memory) are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults + to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary directory + that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type of storage + medium should back this directory. The default + is "" which means to use the node''s default + medium. Must be an empty string (default) or + Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount of + local storage required for this EmptyDir volume. + The size limit is also applicable for memory + medium. The maximum usage on memory medium EmptyDir + would be the minimum value between the SizeLimit + specified here and the sum of memory limits + of all containers in a pod. The default is nil + which means that the limit is undefined. More + info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume that is + handled by a cluster storage driver. The volume's + lifecycle is tied to the pod that defines it - it + will be created before the pod starts, and deleted + when the pod is removed. \n Use this if: a) the + volume is only needed while the pod runs, b) features + of normal volumes like restoring from snapshot or + capacity tracking are needed, c) the storage driver + is specified through a storage class, and d) the + storage driver supports dynamic volume provisioning + through a PersistentVolumeClaim (see EphemeralVolumeSource + for more information on the connection between this + volume type and PersistentVolumeClaim). \n Use PersistentVolumeClaim + or one of the vendor-specific APIs for volumes that + persist for longer than the lifecycle of an individual + pod. \n Use CSI for light-weight local ephemeral + volumes if the CSI driver is meant to be used that + way - see the documentation of the driver for more + information. \n A pod can use both types of ephemeral + volumes and persistent volumes at the same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone + PVC to provision the volume. The pod in which + this EphemeralVolumeSource is embedded will + be the owner of the PVC, i.e. the PVC will be + deleted together with the pod. The name of + the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` + array entry. Pod validation will reject the + pod if the concatenated name is not valid for + a PVC (for example, too long). \n An existing + PVC with that name that is not owned by the + pod will *not* be used for the pod to avoid + using an unrelated volume by mistake. Starting + the pod is then blocked until the unrelated + PVC is removed. If such a pre-created PVC is + meant to be used by the pod, the PVC has to + updated with an owner reference to the pod once + the pod exists. Normally this should not be + necessary, but it may be useful when manually + reconstructing a broken cluster. \n This field + is read-only and no changes will be made by + Kubernetes to the PVC after it has been created. + \n Required, must not be nil." + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when creating + it. No other fields are allowed and will + be rejected during validation. + type: object + spec: + description: The specification for the PersistentVolumeClaim. + The entire content is copied unchanged into + the PVC that gets created from this template. + The same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: 'accessModes contains the + desired access modes the volume should + have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can be + used to specify either: * An existing + VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller + can support the specified data source, + it will create a new volume based on + the contents of the specified data source. + When the AnyVolumeDataSource feature + gate is enabled, dataSource contents + will be copied to dataSourceRef, and + dataSourceRef contents will be copied + to dataSource when dataSourceRef.namespace + is not specified. If the namespace is + specified, then dataSourceRef will not + be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, the + specified Kind must be in the core + API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies + the object from which to populate the + volume with data, if a non-empty volume + is desired. This may be any object from + a non-empty API group (non core object) + or a PersistentVolumeClaim object. When + this field is specified, volume binding + will only succeed if the type of the + specified object matches some installed + volume populator or dynamic provisioner. + This field will replace the functionality + of the dataSource field and as such + if both fields are non-empty, they must + have the same value. For backwards compatibility, + when namespace isn''t specified in dataSourceRef, + both fields (dataSource and dataSourceRef) + will be set to the same value automatically + if one of them is empty and the other + is non-empty. When namespace is specified + in dataSourceRef, dataSource isn''t + set to the same value and must be empty. + There are three important differences + between dataSource and dataSourceRef: + * While dataSource only allows two specific + types of objects, dataSourceRef allows + any non-core object, as well as PersistentVolumeClaim + objects. * While dataSource ignores + disallowed values (dropping them), dataSourceRef + preserves all values, and generates + an error if a disallowed value is specified. + * While dataSource only allows local + objects, dataSourceRef allows objects + in any namespaces. (Beta) Using this + field requires the AnyVolumeDataSource + feature gate to be enabled. (Alpha) + Using the namespace field of dataSourceRef + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, the + specified Kind must be in the core + API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: Namespace is the namespace + of resource being referenced Note + that when a namespace is specified, + a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent + namespace to allow that namespace's + owner to accept the reference. See + the ReferenceGrant documentation + for details. (Alpha) This field + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents the + minimum resources the volume should + have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed + to specify resource requirements that + are lower than previous value but must + still be higher than capacity recorded + in the status field of the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the names + of resources, defined in spec.resourceClaims, + that are used by this container. + \n This is an alpha field and requires + enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. + It can only be set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match + the name of one entry in pod.spec.resourceClaims + of the Pod where this field + is used. It makes that resource + available inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the + maximum amount of compute resources + allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the + minimum amount of compute resources + required. If Requests is omitted + for a container, it defaults to + Limits if that is explicitly specified, + otherwise to an implementation-defined + value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query + over volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a + list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a + set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values + array must be non-empty. If + the operator is Exists or + DoesNotExist, the values array + must be empty. This array + is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName is the + name of the StorageClass required by + the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type + of volume is required by the claim. + Value of Filesystem is implied when + not included in claim spec. + type: string + volumeName: + description: volumeName is the binding + reference to the PersistentVolume backing + this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource + that is attached to a kubelet's host machine and + then exposed to the pod. + properties: + fsType: + description: 'fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. TODO: how do we prevent errors + in the filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target + worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume world + wide identifiers (wwids) Either wwids or combination + of targetWWNs and lun must be set, but not both + simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume + resource that is provisioned/attached using an exec + based plugin. + properties: + driver: + description: driver is the name of the driver + to use for this volume. + type: string + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". The default filesystem depends on FlexVolume + script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field + holds extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef + is reference to the secret object containing + sensitive information to pass to the plugin + scripts. This may be empty if no secret object + is specified. If the secret object contains + more than one secret, all secrets are passed + to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume attached + to a kubelet's host machine. This depends on the + Flocker control service being running + properties: + datasetName: + description: datasetName is Name of the dataset + stored as metadata -> name on the dataset for + Flocker should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. + This is unique identifier of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE Disk + resource that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of the + volume that you want to mount. Tip: Ensure that + the filesystem type is supported by the host + operating system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in the + volume that you want to mount. If omitted, the + default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for + /dev/sda is "0" (or you can leave the property + empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the PD + resource in GCE. Used to identify the disk in + GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository + at a particular revision. DEPRECATED: GitRepo is + deprecated. To provision a container with a git + repo, mount an EmptyDir into an InitContainer that + clones the repo using git, then mount the EmptyDir + into the Pod''s container.' + properties: + directory: + description: directory is the target directory + name. Must not contain or start with '..'. If + '.' is supplied, the volume directory will be + the git repository. Otherwise, if specified, + the volume will contain the git repository in + the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the + specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs mount + on the host that shares a pod''s lifetime. More + info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name that + details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume path. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the Glusterfs + volume to be mounted with read-only permissions. + Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing file + or directory on the host machine that is directly + exposed to the container. This is generally used + for system agents or other privileged things that + are allowed to see the host machine. Most containers + will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can use + host directory mounts and who can/can not mount + host directories as read/write.' + properties: + path: + description: 'path of the directory on the host. + If the path is a symlink, it will follow the + link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults + to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource + that is attached to a kubelet''s host machine and + then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether + support iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support + iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI + Initiator Name. If initiatorName is specified + with iscsiInterface simultaneously, new iSCSI + interface : will + be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified + Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface Name + that uses an iSCSI transport. Defaults to 'default' + (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal + List. The portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for + iSCSI target and initiator authentication + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target Portal. + The Portal is either an IP or ip_addr:port if + the port is other than default (typically TCP + ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL + and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the host + that shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the NFS + server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the NFS + export to be mounted with read-only permissions. + Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP address + of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource represents + a reference to a PersistentVolumeClaim in the same + namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this + volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets + host machine + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon + Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx + volume attached and mounted on kubelets host machine + properties: + fsType: + description: fSType represents the filesystem + type to mount Must be a filesystem type supported + by the host operating system. Ex. "ext4", "xfs". + Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx + volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources + secrets, configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits used + to set permissions on created files by default. + Must be an octal value between 0000 and 0777 + or a decimal value between 0 and 511. YAML accepts + both octal and decimal values, JSON requires + decimal values for mode bits. Directories within + the path are not affected by this setting. This + might be in conflict with other options that + affect the file mode, like fsGroup, and the + result can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume projections + items: + description: Projection that may be projected + along with other supported volume types + properties: + configMap: + description: configMap information about + the configMap data to project + properties: + items: + description: items if unspecified, each + key-value pair in the Data field of + the referenced ConfigMap will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will + be projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not + present in the ConfigMap, the volume + setup will error unless it is marked + optional. Paths must be relative and + may not contain the '..' path or start + with '..'. + items: + description: Maps a string key to + a path within a volume. + properties: + key: + description: key is the key to + project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 + or a decimal value between 0 + and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume + defaultMode will be used. This + might be in conflict with other + options that affect the file + mode, like fsGroup, and the + result can be other mode bits + set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the + key to. May not be an absolute + path. May not contain the path + element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about + the downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile + represents information to create + the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only annotations, + labels, name and namespace are + supported.' + properties: + apiVersion: + description: Version of the + schema the FieldPath is + written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field + to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits + used to set permissions on this + file, must be an octal value + between 0000 and 0777 or a decimal + value between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If not + specified, the volume defaultMode + will be used. This might be + in conflict with other options + that affect the file mode, like + fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file + to be created. Must not be absolute + or contain the ''..'' path. + Must be utf-8 encoded. The first + item of the relative path must + not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource + of the container: only resources + limits and requests (limits.cpu, + limits.memory, requests.cpu + and requests.memory) are currently + supported.' + properties: + containerName: + description: 'Container name: + required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the + output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about the + secret data to project + properties: + items: + description: items if unspecified, each + key-value pair in the Data field of + the referenced Secret will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will + be projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not + present in the Secret, the volume + setup will error unless it is marked + optional. Paths must be relative and + may not contain the '..' path or start + with '..'. + items: + description: Maps a string key to + a path within a volume. + properties: + key: + description: key is the key to + project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 + or a decimal value between 0 + and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume + defaultMode will be used. This + might be in conflict with other + options that affect the file + mode, like fsGroup, and the + result can be other mode bits + set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the + key to. May not be an absolute + path. May not contain the path + element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional field specify + whether the Secret or its key must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to + project + properties: + audience: + description: audience is the intended + audience of the token. A recipient + of a token must identify itself with + an identifier specified in the audience + of the token, and otherwise should + reject the token. The audience defaults + to the identifier of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is the + requested duration of validity of + the service account token. As the + token approaches expiration, the kubelet + volume plugin will proactively rotate + the service account token. The kubelet + will start trying to rotate the token + if the token is older than 80 percent + of its time to live or if the token + is older than 24 hours.Defaults to + 1 hour and must be at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative + to the mount point of the file to + project the token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount on + the host that shares a pod's lifetime + properties: + group: + description: group to map volume access to Default + is no group + type: string + readOnly: + description: readOnly here will force the Quobyte + volume to be mounted with read-only permissions. + Defaults to false. + type: boolean + registry: + description: registry represents a single or multiple + Quobyte Registry services specified as a string + as host:port pair (multiple entries are separated + with commas) which acts as the central registry + for volumes + type: string + tenant: + description: tenant owning the given Quobyte volume + in the Backend Used with dynamically provisioned + Quobyte volumes, value is set by the plugin + type: string + user: + description: user to map volume access to Defaults + to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + image: + description: 'image is the rados image name. More + info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring + for RBDUser. Default is /etc/ceph/keyring. More + info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of Ceph + monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. Default + is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides keyring. + Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. Default + is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of the + ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the + ScaleIO Protection Domain for the configured + storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret + for ScaleIO user and other sensitive information. + If this is not provided, Login operation will + fail. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL + communication with Gateway, default false + type: boolean + storageMode: + description: storageMode indicates whether the + storage for a volume should be ThickProvisioned + or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage + Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage + system as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume + already created in the ScaleIO system that is + associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that should + populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: items If unspecified, each key-value + pair in the Data field of the referenced Secret + will be projected into the volume as a file + whose name is the key and content is the value. + If specified, the listed keys will be projected + into the specified paths, and unlisted keys + will not be present. If a key is specified which + is not present in the Secret, the volume setup + will error unless it is marked optional. Paths + must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 and + 0777 or a decimal value between 0 and + 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. If not specified, the volume + defaultMode will be used. This might be + in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path of + the file to map the key to. May not be + an absolute path. May not contain the + path element '..'. May not start with + the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether the + Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the secret + in the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS volume + attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret to + use for obtaining the StorageOS API credentials. If + not specified, default values will be attempted. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable + name of the StorageOS volume. Volume names + are only unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the scope + of the volume within StorageOS. If no namespace + is specified then the Pod's namespace will be + used. This allows the Kubernetes name scoping + to be mirrored within StorageOS for tighter + integration. Set VolumeName to any name to override + the default behaviour. Set to "default" if you + are not using namespaces within StorageOS. Namespaces + that do not pre-exist within StorageOS will + be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere volume + attached and mounted on kubelets host machine + properties: + fsType: + description: fsType is filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy + Based Management (SPBM) profile ID associated + with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage + Policy Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name type: object - type: object - timeOffset: - description: TimeOffset defines the delta time of injected - program. It's a possibly signed sequence of decimal numbers, - such as "300ms", "-1.5h" or "2h45m". Valid time units are - "ns", "us" (or "µs"), "ms", "s", "m", "h". - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - mode - - selector - - timeOffset - type: object - required: - - name - - template_type - type: object - type: array - required: - - entry - - templates - type: object - status: - description: Most recently observed status of the workflow - properties: - entry_node: - type: string - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: array + type: object + templateType: + type: string + timeChaos: + description: TimeChaosSpec defines the desired state of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id All + available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected + program. It's a possibly signed sequence of decimal numbers, + such as "300ms", "-1.5h" or "2h45m". Valid time units + are "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + required: + - name + - templateType + type: object + type: array + required: + - entry + - templates + type: object + status: + description: Most recently observed status of the workflow + properties: + conditions: + description: Represents the latest available observations of a workflow's + current state. + items: + properties: + reason: + type: string + startTime: + format: date-time + type: string + status: + type: string + type: + type: string + required: + - reason + - status + - type + type: object + type: array + endTime: + format: date-time + type: string + entryNode: + type: string + startTime: + format: date-time + type: string + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: + status: {} diff --git a/helm/chaos-mesh/templates/_certs.tpl b/helm/chaos-mesh/templates/_certs.tpl new file mode 100644 index 0000000000..4796eecb62 --- /dev/null +++ b/helm/chaos-mesh/templates/_certs.tpl @@ -0,0 +1,144 @@ + +{{/* +webhook.apiversion is used to take care compatibility with admissionregistration.k8s.io api groups + +When using this template, it requires the top-level scope +*/}} +{{- define "webhook.apiVersion" -}} + {{- $webhookApiVersion := "v1beta1" -}} + {{- if .Capabilities.APIVersions.Has "admissionregistration.k8s.io/v1" -}} + {{- $webhookApiVersion = "v1" -}} + {{- end -}} + {{- printf "admissionregistration.k8s.io/%s" $webhookApiVersion -}} +{{- end -}} + +{{/* +chaosmesh.selfSignedCABundleCertPEM is the self-signed CA to: +- sign the certification keyparing used by chaos-daemon mTLS +- sign the certification keyparing used by webhook server (if the user does not provide one) +*/}} +{{- define "chaosmesh.selfSignedCABundleCertPEM" -}} + {{- $caKeypair := .selfSignedCAKeypair | default (genCA "chaos-mesh-ca" 1825) -}} + {{- $_ := set . "selfSignedCAKeypair" $caKeypair -}} + {{- $caKeypair.Cert -}} +{{- end -}} + +{{/* +Get the caBundle for clients of the webhooks. +It would use .selfSignedCAKeypair as the place to store the generated CA keypair, it is actually kind of dirty work to prevent generating keypair with multiple times. + +When using this template, it requires the top-level scope. + +*/}} +{{- define "webhook.caBundleCertPEM" -}} + {{- if .Values.webhook.caBundlePEM -}} + {{- trim .Values.webhook.caBundlePEM -}} + {{- else -}} + {{- /* Generate ca with CN "chaos-mesh-ca" and 5 years validity duration if not exists in the current scope.*/ -}} + {{- $caKeypair := .selfSignedCAKeypair | default (genCA "chaos-mesh-ca" 1825) -}} + {{- $_ := set . "selfSignedCAKeypair" $caKeypair -}} + {{- $caKeypair.Cert -}} + {{- end -}} +{{- end -}} + +{{/* +webhook.certPEM is the cert of certification used by validating/mutating admission webhook server. +Like generating CA, it would use .webhookTLSKeypair as the place to store the generated keypair, it is actually kind of dirty work to prevent generating keypair with multiple times. + +When using this template, it requires the top-level scope +*/}} +{{- define "webhook.certPEM" -}} + {{- if .Values.webhook.crtPEM -}} + {{- trim .Values.webhook.crtPEM -}} + {{- else -}} + {{- /* FIXME: Duplicated codes with named template "webhook.keyPEM" because of no way to nested named template.*/ -}} + {{- /* webhookName would be the FQDN of in-cluster service chaos-mesh.*/ -}} + {{- $webhookName := printf "%s.%s.svc" (include "chaos-mesh.svc" .) .Release.Namespace }} + {{- $webhookCA := required "self-signed CA keypair is requried" .selfSignedCAKeypair -}} + {{- /* Generate cert keypair for webhook with 5 years validity duration. */ -}} + {{- $webhookServerTLSKeypair := .webhookTLSKeypair | default (genSignedCert $webhookName nil (list $webhookName) 1825 $webhookCA) }} + {{- $_ := set . "webhookTLSKeypair" $webhookServerTLSKeypair -}} + {{- $webhookServerTLSKeypair.Cert -}} + {{- end -}} +{{- end -}} + +{{/* +webhook.keyPEM is the key of certification used by validating/mutating admission webhook server. +Like generating CA, it would use .webhookTLSKeypair as the place to store the generated keypair, it is actually kind of dirty work to prevent generating keypair with multiple times. + +When using this template, it requires the top-level scope +*/}} +{{- define "webhook.keyPEM" -}} + {{- if .Values.webhook.keyPEM -}} + {{ trim .Values.webhook.keyPEM }} + {{- else -}} + {{- /* FIXME: Duplicated codes with named template "webhook.keyPEM" because of no way to nested named template.*/ -}} + {{- /* webhookName would be the FQDN of in-cluster service chaos-mesh.*/ -}} + {{- $webhookName := printf "%s.%s.svc" (include "chaos-mesh.svc" .) .Release.Namespace -}} + {{- $webhookCA := required "self-signed CA keypair is requried" .selfSignedCAKeypair -}} + {{- /* Generate cert key pair for webhook with 5 years validity duration. */ -}} + {{- $webhookServerTLSKeypair := .webhookTLSKeypair | default (genSignedCert $webhookName nil (list $webhookName) 1825 $webhookCA) -}} + {{- $_ := set . "webhookTLSKeypair" $webhookServerTLSKeypair -}} + {{- $webhookServerTLSKeypair.Key -}} + {{- end -}} +{{- end -}} + +{{/* +chaosDaemon.server.certPEM is the certification used by chaos daemon server for mTLS. +Like generating CA, it would use .chaosDaemonServerTLSKeypair as the place to store the generated keypair, +it is actually kind of dirty work to prevent generating keypair with multiple times. + +When using this template, it requires the top-level scope. +*/}} +{{- define "chaosDaemon.server.certPEM" -}} + {{- $ca := required "self-signed CA keypair is requried" .selfSignedCAKeypair -}} + {{- /* Generate cert keypair with CN "chaos-daemon.chaos-mesh.org" and 5 years validity duration if not exists in the current scope.*/ -}} + {{- $chaosDaemonServerTLSKeypair := .chaosDaemonServerTLSKeypair | default (genSignedCert "chaos-daemon.chaos-mesh.org" nil (list "localhost" "chaos-daemon.chaos-mesh.org") 1825 $ca) -}} + {{- $_ := set . "chaosDaemonServerTLSKeypair" $chaosDaemonServerTLSKeypair -}} + {{- $chaosDaemonServerTLSKeypair.Cert -}} +{{- end -}} + +{{/* +chaosDaemon.server.keyPEM is the key used by chaos daemon server for mTLS. +Like generating CA, it would use .chaosDaemonServerTLSKeypair as the place to store the generated keypair, +it is actually kind of dirty work to prevent generating keypair with multiple times. + +When using this template, it requires the top-level scope. +*/}} +{{- define "chaosDaemon.server.keyPEM" -}} + {{- $ca := required "self-signed CA keypair is requried" .selfSignedCAKeypair -}} + {{- /* Generate cert keypair with CN "chaos-daemon.chaos-mesh.org" and 5 years validity duration if not exists in the current scope.*/ -}} + {{- $chaosDaemonServerTLSKeypair := .chaosDaemonServerTLSKeypair | default (genSignedCert "chaos-daemon.chaos-mesh.org" nil (list "localhost" "chaos-daemon.chaos-mesh.org") 1825 $ca) -}} + {{- $_ := set . "chaosDaemonServerTLSKeypair" $chaosDaemonServerTLSKeypair -}} + {{- $chaosDaemonServerTLSKeypair.Key -}} +{{- end -}} + +{{/* +chaosDaemon.client.certPEM is the certification used by controller-manager (as the client of chaos-daemon server) for mTLS. +Like generating CA, it would use .chaosDaemonClientTLSKeypair as the place to store the generated keypair, +it is actually kind of dirty work to prevent generating keypair with multiple times. + +When using this template, it requires the top-level scope. +*/}} +{{- define "chaosDaemon.client.certPEM" -}} + {{- $ca := required "self-signed CA keypair is requried" .selfSignedCAKeypair -}} + {{- /* Generate cert keypair with CN "controller-manager.chaos-mesh.org" and 5 years validity duration if not exists in the current scope.*/ -}} + {{- $chaosDaemonClientTLSKeypair := .chaosDaemonClientTLSKeypair | default (genSignedCert "controller-manager.chaos-mesh.org" nil (list "localhost" "controller-manager.chaos-mesh.org") 1825 $ca) -}} + {{- $_ := set . "chaosDaemonClientTLSKeypair" $chaosDaemonClientTLSKeypair -}} + {{- $chaosDaemonClientTLSKeypair.Cert -}} +{{- end -}} + +{{/* +chaosDaemon.client.keyPEM is the key used by controller-manager (as the client of chaos-daemon server) for mTLS. +Like generating CA, it would use .chaosDaemonClientTLSKeypair as the place to store the generated keypair, +it is actually kind of dirty work to prevent generating keypair with multiple times. + +When using this template, it requires the top-level scope. +*/}} +{{- define "chaosDaemon.client.keyPEM" -}} + {{- $ca := required "self-signed CA keypair is requried" .selfSignedCAKeypair -}} + {{- /* Generate cert keypair with CN "controller-manager.chaos-mesh.org" and 5 years validity duration if not exists in the current scope.*/ -}} + {{- $chaosDaemonClientTLSKeypair := .chaosDaemonClientTLSKeypair | default (genSignedCert "controller-manager.chaos-mesh.org" nil (list "localhost" "controller-manager.chaos-mesh.org") 1825 $ca) -}} + {{- $_ := set . "chaosDaemonClientTLSKeypair" $chaosDaemonClientTLSKeypair -}} + {{- $chaosDaemonClientTLSKeypair.Key -}} +{{- end -}} diff --git a/helm/chaos-mesh/templates/_helpers.tpl b/helm/chaos-mesh/templates/_helpers.tpl index d27d72d7e1..dc913958dc 100644 --- a/helm/chaos-mesh/templates/_helpers.tpl +++ b/helm/chaos-mesh/templates/_helpers.tpl @@ -1,10 +1,29 @@ {{/* vim: set filetype=mustache: */}} + +{{/* +Handle env variables. + +TODO: in the future, we would like to use the k8s-like format for defining environment variables. +So the `envFollowKubernetesPattern` will become to `env`. +And the original way of writing env will be removed. +Ref: https://github.com/chaos-mesh/chaos-mesh/pull/2955. +*/}} +{{- define "chaos-mesh.helpers.listEnvVars" -}} +{{- with .envFollowKubernetesPattern }} +{{ toYaml . }} +{{- end }} +{{- range $key, $val := .env }} +- name: {{ $key | upper }} + value: {{ $val | quote }} +{{- end }} +{{- end }} + {{/* Expand the name of the chart. */}} {{- define "chaos-mesh.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} {{/* Create a default fully qualified app name. @@ -12,24 +31,45 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this If release name contains chart name it will be used as a full name. */}} {{- define "chaos-mesh.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "chaos-mesh.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* Generate basic labels */}} +{{- define "chaos-mesh.labels" -}} +helm.sh/chart: {{ include "chaos-mesh.chart" . }} +app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/part-of: {{ template "chaos-mesh.name" . }} +app.kubernetes.io/version: {{ .Chart.AppVersion }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels }} +{{- end }} +{{- end }} + +{{/* +Specify default selectors +*/}} +{{- define "chaos-mesh.selectors" -}} +app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} {{/* Define the svc's name @@ -67,6 +107,10 @@ Define the secret's name of certs {{- printf "chaos-mesh-daemon-client-certs" -}} {{- end -}} +{{- define "chaos-mesh.chaosd-client.certs" -}} +{{- printf "chaos-mesh-chaosd-client-certs" -}} +{{- end -}} + {{/* Define the MutatingWebhookConfiguration's name */}} @@ -88,9 +132,62 @@ Define the webhook's name {{- printf "admission-webhook.chaos-mesh.org" -}} {{- end -}} -{{/* -Define the prefix of -*/}} -{{- define "registry-prefix" -}} -{{if .Values.registry}}{{.Values.registry}}/{{end}} +{{/*Define the image for chaos-controller-manager*/}} +{{- define "chaos-controller-manager.image" -}} +{{ .Values.controllerManager.image.registry | default .Values.images.registry }}/{{ .Values.controllerManager.image.repository }}:{{ .Values.controllerManager.image.tag | default .Values.images.tag }} +{{- end -}} + +{{/*Define the image for chaos-daemon*/}} +{{- define "chaos-daemon.image" -}} +{{ .Values.chaosDaemon.image.registry | default .Values.images.registry }}/{{ .Values.chaosDaemon.image.repository }}:{{ .Values.chaosDaemon.image.tag | default .Values.images.tag }} +{{- end -}} + +{{/*Define the image for chaos-dashboard*/}} +{{- define "chaos-dashboard.image" -}} +{{ .Values.dashboard.image.registry | default .Values.images.registry }}/{{ .Values.dashboard.image.repository }}:{{ .Values.dashboard.image.tag | default .Values.images.tag }} +{{- end -}} + +{{/*Define the image for chaos-kernel*/}} +{{- define "chaos-kernel.image" -}} +{{ .Values.bpfki.image.registry | default .Values.images.registry }}/{{ .Values.bpfki.image.repository }}:{{ .Values.bpfki.image.tag | default .Values.images.tag }} +{{- end -}} + +{{/*Define the image for chaos-dlv*/}} +{{- define "chaos-dlv.image" -}} +{{ .Values.chaosDlv.image.registry | default .Values.images.registry }}/{{ .Values.chaosDlv.image.repository }}:{{ .Values.chaosDlv.image.tag | default .Values.images.tag }} +{{- end -}} + +{{/*Define the image for chaos-dns*/}} +{{- define "chaos-dns.image" -}} +{{ .Values.dnsServer.image.registry | default .Values.images.registry }}/{{ .Values.dnsServer.image.repository }}:{{ .Values.dnsServer.image.tag | default .Values.images.tag }} +{{- end -}} + +{{/*Return the appropriate apiVersion for ingress*/}} +{{- define "chaos-dashboard.ingress.apiVersion" -}} +{{- if .Values.dashboard.ingress.apiVersionOverrides -}} +{{- print .Values.dashboard.ingress.apiVersionOverrides -}} +{{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1/Ingress" -}} +{{- print "networking.k8s.io/v1" -}} +{{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1/Ingress" -}} +{{- print "networking.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "extensions/v1beta1" -}} +{{- end -}} +{{- end -}} + +{{/*Define the socket path for chaos-daemon*/}} +{{- define "chaos-daemon.socket-path" -}} +{{- if .Values.chaosDaemon.socketPath -}} + {{- .Values.chaosDaemon.socketPath | dir -}} +{{- else if .Values.chaosDaemon.socketDir -}} + {{- .Values.chaosDaemon.socketDir -}} +{{- else -}} + {{- if eq .Values.chaosDaemon.runtime "docker" -}} + /var/run + {{- else if eq .Values.chaosDaemon.runtime "containerd" -}} + /run/containerd + {{- else if eq .Values.chaosDaemon.runtime "crio" -}} + /var/run/crio + {{- end -}} +{{- end -}} {{- end -}} diff --git a/helm/chaos-mesh/templates/cert-manager-certs.yaml b/helm/chaos-mesh/templates/cert-manager-certs.yaml new file mode 100644 index 0000000000..9b5aec9601 --- /dev/null +++ b/helm/chaos-mesh/templates/cert-manager-certs.yaml @@ -0,0 +1,163 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- $certManagerEnabled := .Values.webhook.certManager.enabled }} + +{{- if $certManagerEnabled }} +--- +{{- if .Capabilities.APIVersions.Has "cert-manager.io/v1" }} +apiVersion: cert-manager.io/v1 +{{- else if .Capabilities.APIVersions.Has "cert-manager.io/v1beta1" }} +apiVersion: cert-manager.io/v1beta1 +{{- else if .Capabilities.APIVersions.Has "cert-manager.io/v1alpha3" }} +apiVersion: cert-manager.io/v1alpha3 +{{- else }} +apiVersion: cert-manager.io/v1alpha2 +{{- end }} +kind: Issuer +metadata: + name: chaos-mesh-selfsigned + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: chaos-mesh-selfsigned +spec: + selfSigned: {} +--- +{{- if .Capabilities.APIVersions.Has "cert-manager.io/v1" }} +apiVersion: cert-manager.io/v1 +{{- else if .Capabilities.APIVersions.Has "cert-manager.io/v1beta1" }} +apiVersion: cert-manager.io/v1beta1 +{{- else if .Capabilities.APIVersions.Has "cert-manager.io/v1alpha3" }} +apiVersion: cert-manager.io/v1alpha3 +{{- else }} +apiVersion: cert-manager.io/v1alpha2 +{{- end }} +kind: Certificate +metadata: + name: chaos-mesh-ca + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: chaos-mesh-ca +spec: + duration: 43800h0m0s # 5 years + secretName: chaos-mesh-ca + commonName: "chaos-mesh-ca" + isCA: true + issuerRef: + name: chaos-mesh-selfsigned + privateKey: + rotationPolicy: Never +--- +{{- if .Capabilities.APIVersions.Has "cert-manager.io/v1" }} +apiVersion: cert-manager.io/v1 +{{- else if .Capabilities.APIVersions.Has "cert-manager.io/v1beta1" }} +apiVersion: cert-manager.io/v1beta1 +{{- else if .Capabilities.APIVersions.Has "cert-manager.io/v1alpha3" }} +apiVersion: cert-manager.io/v1alpha3 +{{- else }} +apiVersion: cert-manager.io/v1alpha2 +{{- end }} +kind: Issuer +metadata: + name: chaos-mesh-ca + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: chaos-mesh-ca +spec: + ca: + secretName: chaos-mesh-ca +--- +{{- if .Capabilities.APIVersions.Has "cert-manager.io/v1" }} +apiVersion: cert-manager.io/v1 +{{- else if .Capabilities.APIVersions.Has "cert-manager.io/v1beta1" }} +apiVersion: cert-manager.io/v1beta1 +{{- else if .Capabilities.APIVersions.Has "cert-manager.io/v1alpha3" }} +apiVersion: cert-manager.io/v1alpha3 +{{- else }} +apiVersion: cert-manager.io/v1alpha2 +{{- end }} +kind: Certificate +metadata: + name: chaos-mesh-cert + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: chaos-mesh-cert +spec: + duration: 43800h0m0s # 5 years + dnsNames: + - {{ template "chaos-mesh.svc" . }} + - {{ template "chaos-mesh.svc" . }}.{{ .Release.Namespace }} + - {{ template "chaos-mesh.svc" . }}.{{ .Release.Namespace }}.svc + secretName: {{ template "chaos-mesh.webhook.certs" . }} + issuerRef: + name: chaos-mesh-ca + privateKey: + rotationPolicy: Never +--- +{{- if .Capabilities.APIVersions.Has "cert-manager.io/v1" }} +apiVersion: cert-manager.io/v1 +{{- else if .Capabilities.APIVersions.Has "cert-manager.io/v1beta1" }} +apiVersion: cert-manager.io/v1beta1 +{{- else if .Capabilities.APIVersions.Has "cert-manager.io/v1alpha3" }} +apiVersion: cert-manager.io/v1alpha3 +{{- else }} +apiVersion: cert-manager.io/v1alpha2 +{{- end }} +kind: Certificate +metadata: + name: chaos-daemon-client-cert + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: chaos-daemon-client-cert +spec: + duration: 43800h0m0s # 5 years + dnsNames: + - controller-manager.chaos-mesh.org + secretName: {{ template "chaos-mesh.daemon-client.certs" . }} + issuerRef: + name: chaos-mesh-ca + privateKey: + rotationPolicy: Never +--- +{{- if .Capabilities.APIVersions.Has "cert-manager.io/v1" }} +apiVersion: cert-manager.io/v1 +{{- else if .Capabilities.APIVersions.Has "cert-manager.io/v1beta1" }} +apiVersion: cert-manager.io/v1beta1 +{{- else if .Capabilities.APIVersions.Has "cert-manager.io/v1alpha3" }} +apiVersion: cert-manager.io/v1alpha3 +{{- else }} +apiVersion: cert-manager.io/v1alpha2 +{{- end }} +kind: Certificate +metadata: + name: chaos-daemon-cert + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: chaos-daemontcert +spec: + duration: 43800h0m0s # 5 years + dnsNames: + - chaos-daemon.chaos-mesh.org + secretName: {{ template "chaos-mesh.daemon.certs" . }} + issuerRef: + name: chaos-mesh-ca + privateKey: + rotationPolicy: Never +{{- end }} diff --git a/helm/chaos-mesh/templates/chaos-daemon-daemonset.yaml b/helm/chaos-mesh/templates/chaos-daemon-daemonset.yaml index 386c84c737..be03aa6238 100644 --- a/helm/chaos-mesh/templates/chaos-daemon-daemonset.yaml +++ b/helm/chaos-mesh/templates/chaos-daemon-daemonset.yaml @@ -1,46 +1,68 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + apiVersion: apps/v1 kind: DaemonSet metadata: namespace: {{ .Release.Namespace | quote }} name: chaos-daemon labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/component: chaos-daemon - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + {{- include "chaos-mesh.labels" . | nindent 4 }} spec: + {{- if .Values.chaosDaemon.updateStrategy }} + updateStrategy: +{{ toYaml .Values.chaosDaemon.updateStrategy | indent 4 }} + {{- end }} selector: matchLabels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.selectors" . | nindent 6 }} app.kubernetes.io/component: chaos-daemon template: metadata: labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 8 }} app.kubernetes.io/component: chaos-daemon annotations: - {{- if .Values.dashboard.securityMode }} + {{- /* it requires to reload the latest re-generated certs for mtls after helm upgrade*/}} + {{- if .Values.chaosDaemon.mtls.enabled }} rollme: {{ randAlphaNum 5 | quote }} {{- end }} {{- with .Values.chaosDaemon.podAnnotations }} {{ toYaml . | indent 8 }} {{- end }} spec: - {{- if .Values.chaosDaemon.hostNetwork }} + {{- if .Values.chaosDaemon.hostNetwork }} hostNetwork: true - {{- end }} - {{- if .Values.chaosDaemon.serviceAccount }} - serviceAccount: {{ .Values.chaosDaemon.serviceAccount }} - {{- end }} - hostIPC: true + {{- end }} + {{- if .Values.chaosDaemon.serviceAccount }} + serviceAccountName: {{ .Values.chaosDaemon.serviceAccount }} + {{- end }} hostPID: true - priorityClassName: {{ .Values.chaosDaemon.priorityClassName}} + {{- if .Values.chaosDaemon.priorityClassName }} + priorityClassName: {{ .Values.chaosDaemon.priorityClassName }} + {{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.imagePullSecrets | nindent 8 }} + {{- end }} + {{- if .Values.chaosDaemon.securityContext }} + securityContext: {{ toYaml .Values.chaosDaemon.securityContext | nindent 8 }} + {{- end }} containers: - name: chaos-daemon - image: {{template "registry-prefix" .}}{{ .Values.chaosDaemon.image }} + image: {{template "chaos-daemon.image" . }} imagePullPolicy: {{ .Values.chaosDaemon.imagePullPolicy | default "IfNotPresent" }} {{- if .Values.chaosDaemon.resources }} resources: @@ -57,7 +79,7 @@ spec: {{- if .Values.enableProfiling }} - --pprof {{- end }} - {{- if .Values.dashboard.securityMode }} + {{- if .Values.chaosDaemon.mtls.enabled }} - --ca - /etc/chaos-daemon/cert/ca.crt - --cert @@ -65,10 +87,21 @@ spec: - --key - /etc/chaos-daemon/cert/tls.key {{- end }} + - --runtime-socket-path + {{- if .Values.chaosDaemon.socketPath }} + - /host-run/{{ .Values.chaosDaemon.socketPath | base }} + {{- else }} + {{- if eq .Values.chaosDaemon.runtime "docker" }} + - /host-run/docker.sock + {{- else if eq .Values.chaosDaemon.runtime "containerd" }} + - /host-run/containerd.sock + {{- else if eq .Values.chaosDaemon.runtime "crio" }} + - /host-run/crio.sock + {{- end }} + {{- end }} env: - {{- range $envKey, $envVal := .Values.chaosDaemon.env }} - - name: {{ $envKey | upper }} - value: {{ $envVal | quote }} + {{- if .Values.chaosDaemon.env }} + {{- include "chaos-mesh.helpers.listEnvVars" .Values.chaosDaemon | trim | nindent 12 }} {{- end }} {{- if not .Values.chaosDaemon.env.TZ }} - name: TZ @@ -82,28 +115,16 @@ spec: - SYS_PTRACE {{- else }} capabilities: - add: - - SYS_PTRACE - - NET_ADMIN - - MKNOD - - SYS_CHROOT - - SYS_ADMIN - - KILL - # CAP_IPC_LOCK is used to lock memory - - IPC_LOCK +{{ toYaml .Values.chaosDaemon.capabilities | indent 14 }} {{- end }} volumeMounts: - name: socket-path - {{- if eq .Values.chaosDaemon.runtime "docker" }} - mountPath: /var/run/docker.sock - {{- else if eq .Values.chaosDaemon.runtime "containerd" }} - mountPath: /run/containerd/containerd.sock - {{- else if eq .Values.chaosDaemon.runtime "crio" }} - mountPath: /var/run/crio/crio.sock - {{- end }} + mountPath: /host-run - name: sys-path - mountPath: /sys - {{- if .Values.dashboard.securityMode}} + mountPath: /host-sys + - name: lib-modules + mountPath: /lib/modules + {{- if .Values.chaosDaemon.mtls.enabled}} - name: chaos-daemon-cert mountPath: /etc/chaos-daemon/cert readOnly: true @@ -111,12 +132,11 @@ spec: ports: - name: grpc containerPort: {{ .Values.chaosDaemon.grpcPort }} - hostPort: {{ .Values.chaosDaemon.grpcPort }} - name: http containerPort: {{ .Values.chaosDaemon.httpPort }} {{- if .Values.bpfki.create }} - name: bpfki - image: {{template "registry-prefix" .}}{{ .Values.bpfki.image }} + image: {{template "chaos-kernel.image" . }} imagePullPolicy: {{ .Values.bpfki.imagePullPolicy | default "IfNotPresent" }} {{- if .Values.bpfki.resources }} resources: @@ -141,16 +161,33 @@ spec: ports: - name: grpc containerPort: {{ .Values.bpfki.grpcPort }} - hostPort: {{ .Values.bpfki.grpcPort }} {{- end }} + {{- if .Values.chaosDlv.enable }} + - name: chaos-mesh-dlv + image: {{template "chaos-dlv.image" . }} + imagePullPolicy: {{ .Values.chaosDlv.imagePullPolicy | default "IfNotPresent" }} + env: + - name: CMD_NAME + value: chaos-daemon + securityContext: + capabilities: + add: + - SYS_PTRACE + ports: + - name: dlv + containerPort: 8000 + {{- end }} volumes: - name: socket-path hostPath: - path: {{ .Values.chaosDaemon.socketPath | default "/var/run/docker.sock" }} + path: {{template "chaos-daemon.socket-path" . }} - name: sys-path hostPath: path: /sys - {{- if .Values.dashboard.securityMode}} + - name: lib-modules + hostPath: + path: /lib/modules + {{- if .Values.chaosDaemon.mtls.enabled}} - name: chaos-daemon-cert secret: secretName: {{ template "chaos-mesh.daemon.certs" . }} diff --git a/helm/chaos-mesh/templates/chaos-daemon-rbac.yaml b/helm/chaos-mesh/templates/chaos-daemon-rbac.yaml index 92e2a6b60b..28f26989a5 100644 --- a/helm/chaos-mesh/templates/chaos-daemon-rbac.yaml +++ b/helm/chaos-mesh/templates/chaos-daemon-rbac.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# {{- if .Values.chaosDaemon.serviceAccount }} --- kind: ServiceAccount @@ -5,12 +19,13 @@ apiVersion: v1 metadata: namespace: {{ .Release.Namespace | quote }} name: {{ .Values.chaosDaemon.serviceAccount }} + {{- with .Values.chaosDaemon.serviceAccountAnnotations }} + annotations: +{{ toYaml . | indent 4 }} + {{- end }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: chaos-daemon - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} {{- end}} {{- if .Values.chaosDaemon.podSecurityPolicy }} --- @@ -19,13 +34,10 @@ kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: {{ .Release.Name }}-chaos-daemon-target-namespace - namespace: chaos-testing + namespace: {{ .Release.Namespace | quote }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: chaos-daemon - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} subjects: - kind: ServiceAccount name: {{ .Values.chaosDaemon.serviceAccount }} @@ -41,11 +53,8 @@ kind: ClusterRole metadata: name: {{ .Release.Name }}-chaos-daemon-psp labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: chaos-daemon - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} rules: - apiGroups: - policy @@ -57,6 +66,7 @@ rules: verbs: - use --- +{{- $chaos_daemon_needs_privileged := or (eq .Values.chaosDaemon.privileged true) (eq .Values.bpfki.create true) -}} # Restricted DEFAULT policy # ( Default policy for all new services ) apiVersion: policy/v1beta1 @@ -64,22 +74,48 @@ kind: PodSecurityPolicy metadata: name: {{ .Release.Name }}-chaos-daemon labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: chaos-daemon - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} spec: - privileged: false - allowPrivilegeEscalation: true + {{- if $chaos_daemon_needs_privileged }} allowedCapabilities: - - '*' + - SYS_PTRACE + {{- else }} + allowedCapabilities: + - SYS_PTRACE + - NET_ADMIN + - MKNOD + - SYS_CHROOT + - SYS_ADMIN + - KILL + # CAP_IPC_LOCK is used to lock memory + - IPC_LOCK + {{- end }} + allowedHostPaths: + - pathPrefix: {{template "chaos-daemon.socket-path" . }} + readOnly: false + - pathPrefix: /sys + readOnly: false + - pathPrefix: /lib/modules + readOnly: false + {{- if .Values.bpfki.create }} + - pathPrefix: /etc/localtime + readOnly: false + - pathPrefix: /usr/src + readOnly: false + {{- end }} + allowPrivilegeEscalation: true + {{- if .Values.chaosDaemon.hostNetwork }} hostNetwork: true + {{- end }} + {{- if .Values.bpfki.create }} hostPorts: - - max: 65535 - min: 0 + - max: {{ .Values.bpfki.grpcPort }} + min: {{ .Values.bpfki.grpcPort }} + {{- end }} hostIPC: true hostPID: true + privileged: {{ $chaos_daemon_needs_privileged }} seLinux: rule: RunAsAny supplementalGroups: @@ -89,6 +125,11 @@ spec: fsGroup: rule: RunAsAny volumes: - - '*' + - configMap + - downwardAPI + - emptyDir + - projected + - secret + - hostPath {{- end }} diff --git a/helm/chaos-mesh/templates/chaos-daemon-service.yaml b/helm/chaos-mesh/templates/chaos-daemon-service.yaml index b5694599c5..707ad67cc9 100644 --- a/helm/chaos-mesh/templates/chaos-daemon-service.yaml +++ b/helm/chaos-mesh/templates/chaos-daemon-service.yaml @@ -1,14 +1,30 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: v1 kind: Service metadata: namespace: {{ .Release.Namespace | quote }} name: {{ template "chaos-daemon.svc" . }} + annotations: + {{- if .Values.chaosDaemon.service.scrape.enabled }} + prometheus.io/scrape: "true" + prometheus.io/port: "{{ .Values.chaosDaemon.httpPort }}" + {{- end }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: chaos-daemon - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} spec: clusterIP: None ports: @@ -20,6 +36,12 @@ spec: port: {{ .Values.chaosDaemon.httpPort }} targetPort: http protocol: TCP + {{- if .Values.chaosDlv.enable }} + - port: 8000 + targetPort: dlv + protocol: TCP + name: dlv + {{- end }} selector: + {{- include "chaos-mesh.selectors" . | nindent 4 }} app.kubernetes.io/component: chaos-daemon - app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/helm/chaos-mesh/templates/chaos-dashboard-deployment.yaml b/helm/chaos-mesh/templates/chaos-dashboard-deployment.yaml index 976ae8160e..e7f79e9832 100644 --- a/helm/chaos-mesh/templates/chaos-dashboard-deployment.yaml +++ b/helm/chaos-mesh/templates/chaos-dashboard-deployment.yaml @@ -1,3 +1,18 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + {{- if .Values.dashboard.create }} apiVersion: apps/v1 kind: Deployment @@ -5,48 +20,61 @@ metadata: namespace: {{ .Release.Namespace | quote }} name: chaos-dashboard labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: chaos-dashboard - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} spec: replicas: {{ .Values.dashboard.replicaCount }} + strategy: + {{- if .Values.dashboard.persistentVolume.enabled }} + type: Recreate + {{- else }} + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + {{- end }} selector: matchLabels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.selectors" . | nindent 6 }} app.kubernetes.io/component: chaos-dashboard template: metadata: labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 8 }} app.kubernetes.io/component: chaos-dashboard - {{- with .Values.dashboard.podAnnotations }} annotations: + {{- with .Values.dashboard.podAnnotations }} {{ toYaml . | indent 8 }} {{- end }} spec: + securityContext: +{{ toYaml .Values.dashboard.securityContext | indent 12 }} {{- if .Values.dashboard.hostNetwork }} hostNetwork: true {{- end }} {{- if .Values.dashboard.serviceAccount }} - serviceAccount: {{ .Values.dashboard.serviceAccount }} + serviceAccountName: {{ .Values.dashboard.serviceAccount }} + {{- end }} + {{- if .Values.dashboard.priorityClassName }} + priorityClassName: {{ .Values.dashboard.priorityClassName }} + {{- end }} + {{- if .Values.chaosDlv.enable }} + shareProcessNamespace: true + {{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.imagePullSecrets | nindent 8 }} {{- end }} - priorityClassName: {{ .Values.dashboard.priorityClassName}} containers: - name: chaos-dashboard - image: {{template "registry-prefix" .}}{{ .Values.dashboard.image }} + image: {{template "chaos-dashboard.image" . }} imagePullPolicy: {{ .Values.dashboard.imagePullPolicy | default "IfNotPresent" }} resources: {{ toYaml .Values.dashboard.resources | indent 12 }} command: - /usr/local/bin/chaos-dashboard env: - {{- range $envKey, $envVal := .Values.dashboard.env }} - - name: {{ $envKey | upper }} - value: {{ $envVal | quote }} + {{- if .Values.dashboard.env }} + {{- include "chaos-mesh.helpers.listEnvVars" .Values.dashboard | trim | nindent 12 }} {{- end }} {{- if not .Values.dashboard.env.TZ }} - name: TZ @@ -60,8 +88,32 @@ spec: value: "{{ .Values.controllerManager.enableFilterNamespace }}" - name: SECURITY_MODE value: "{{ .Values.dashboard.securityMode }}" + - name: GCP_SECURITY_MODE + value: "{{ .Values.dashboard.gcpSecurityMode.enabled }}" + {{- if not .Values.dashboard.gcpSecurityMode.existingSecret }} + - name: GCP_CLIENT_ID + value: "{{ .Values.dashboard.gcpSecurityMode.clientId }}" + - name: GCP_CLIENT_SECRET + value: "{{ .Values.dashboard.gcpSecurityMode.clientSecret }}" + {{- end }} - name: DNS_SERVER_CREATE value: "{{ .Values.dnsServer.create }}" + - name: ROOT_URL + value: "{{ tpl .Values.dashboard.rootUrl . }}" + - name: ENABLE_PROFILING + value: "{{ .Values.enableProfiling }}" + {{- if .Values.dashboard.databaseSecretName }} + - name: DATABASE_DATASOURCE + valueFrom: + secretKeyRef: + name: "{{ .Values.dashboard.databaseSecretName }}" + key: DATABASE_DATASOURCE + {{- end }} + {{- if .Values.dashboard.gcpSecurityMode.existingSecret }} + envFrom: + - secretRef: + name: "{{ .Values.dashboard.gcpSecurityMode.existingSecret }}" + {{- end }} volumeMounts: - name: storage-volume mountPath: {{ .Values.dashboard.persistentVolume.mountPath }} @@ -69,6 +121,26 @@ spec: ports: - name: http containerPort: {{ .Values.dashboard.env.LISTEN_PORT }} + - name: metric + containerPort: {{ .Values.dashboard.env.METRIC_PORT }} + {{- if .Values.chaosDlv.enable }} + - name: chaos-mesh-dlv + image: {{template "chaos-dlv.image" . }} + imagePullPolicy: {{ .Values.chaosDlv.imagePullPolicy | default "IfNotPresent" }} + env: + - name: CMD_NAME + value: chaos-dashboard + securityContext: + capabilities: + add: + - SYS_PTRACE + ports: + - name: dlv + containerPort: 8000 + {{- end }} + {{- with .Values.dashboard.extraContainers }} + {{- tpl (toYaml .) $ | nindent 8 }} + {{- end }} {{- with .Values.dashboard.nodeSelector }} nodeSelector: {{ toYaml . | indent 8 }} @@ -101,8 +173,10 @@ metadata: app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/component: chaos-dashboard helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} -{{- with .Values.dashboard.service.annotations }} annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "{{ .Values.dashboard.env.METRIC_PORT }}" +{{- with .Values.dashboard.service.annotations }} {{ toYaml . | indent 4 }} {{- end }} spec: @@ -121,5 +195,21 @@ spec: name: http {{- if and .Values.dashboard.service.nodePort (eq .Values.dashboard.service.type "NodePort") }} nodePort: {{ .Values.dashboard.service.nodePort }} +{{- end }} + {{- if .Values.chaosDlv.enable }} + - port: 8000 + targetPort: dlv + protocol: TCP + name: dlv + {{- end }} + - protocol: TCP + port: {{ .Values.dashboard.env.METRIC_PORT }} + targetPort: {{ .Values.dashboard.env.METRIC_PORT }} + name: metric +{{- if and .Values.dashboard.service.type (eq .Values.dashboard.service.type "LoadBalancer") .Values.dashboard.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{- with .Values.dashboard.service.loadBalancerSourceRanges }} +{{- toYaml . | nindent 4 }} +{{- end }} {{- end }} {{- end }} diff --git a/helm/chaos-mesh/templates/chaos-dashboard-pvc.yaml b/helm/chaos-mesh/templates/chaos-dashboard-pvc.yaml index 4550998982..ff7e6fe833 100644 --- a/helm/chaos-mesh/templates/chaos-dashboard-pvc.yaml +++ b/helm/chaos-mesh/templates/chaos-dashboard-pvc.yaml @@ -1,23 +1,34 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# {{- if .Values.dashboard.create }} -{{- if .Values.dashboard.persistentVolume.enabled -}} -{{- if not .Values.dashboard.persistentVolume.existingClaim -}} +{{- if .Values.dashboard.persistentVolume.enabled }} +{{- if not .Values.dashboard.persistentVolume.existingClaim }} apiVersion: v1 kind: PersistentVolumeClaim metadata: namespace: {{ .Release.Namespace | quote }} name: {{ template "chaos-mesh.name" . }}-chaos-dashboard labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: chaos-dashboard - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} spec: -{{- if .Values.dashboard.persistentVolume.storageClass }} -{{- if (eq "-" .Values.dashboard.persistentVolume.storageClass) }} +{{- if .Values.dashboard.persistentVolume.storageClassName }} +{{- if (eq "-" .Values.dashboard.persistentVolume.storageClassName) }} storageClassName: "" {{- else }} - storageClassName: "{{ .Values.dashboard.persistentVolume.storageClass }}" + storageClassName: "{{ .Values.dashboard.persistentVolume.storageClassName }}" {{- end }} {{- end }} accessModes: diff --git a/helm/chaos-mesh/templates/chaos-dashboard-rbac.yaml b/helm/chaos-mesh/templates/chaos-dashboard-rbac.yaml new file mode 100644 index 0000000000..fba653d0fd --- /dev/null +++ b/helm/chaos-mesh/templates/chaos-dashboard-rbac.yaml @@ -0,0 +1,126 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.rbac.create }} +# ServiceAccount for component chaos-dashboard +kind: ServiceAccount +apiVersion: v1 +metadata: + namespace: {{ .Release.Namespace | quote }} + name: {{ .Values.dashboard.serviceAccount }} + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: chaos-dashboard + +--- +# ClusterRole for chaos-dashboard at cluster scope +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Release.Name }}-chaos-dashboard-cluster-level + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: chaos-dashboard +rules: + # chaos-dashboard could list namespace for selector hints + - apiGroups: [ "" ] + resources: + - namespaces + verbs: + - get + - list + - watch + # chaos-dashboard use subjectaccessreviews to authorize the requests + - apiGroups: [ "authorization.k8s.io" ] + resources: + - subjectaccessreviews + verbs: + - create + +--- +# ClusterRoleBinding for chaos-dashboard at cluster scope +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Release.Name }}-chaos-dashboard-cluster-level + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: chaos-dashboard +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Release.Name }}-chaos-dashboard-cluster-level +subjects: + - kind: ServiceAccount + name: {{ .Values.dashboard.serviceAccount }} + namespace: {{ .Release.Namespace | quote }} + +--- +# ClusterRole for chaos-dashboard in target namespace +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Release.Name }}-chaos-dashboard-target-namespace + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: chaos-dashboard +rules: + # chaos dashboard could list pods for selector hints + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - watch + # chaos dashboard could record evnets from chaos experiments + - apiGroups: + - "" + resources: + - events + verbs: + - get + - list + - watch + # chaos dashboard could record and manipulate all the Chaos Mesh resources in target namespace + - apiGroups: [ "chaos-mesh.org" ] + resources: + - "*" + verbs: [ "*" ] + +--- +# binding ClusterRole to ServiceAccount for componnet chaos dashboard +{{- if .Values.clusterScoped }} +kind: ClusterRoleBinding +{{- else }} +kind: RoleBinding +{{- end }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Release.Name }}-chaos-dashboard-target-namespace + # TODO: notice that the targetNamespace is still defined as .Values.controllerManager.targetNamespace, .Values.targetNamespace would be better. + namespace: {{ .Values.controllerManager.targetNamespace | quote }} + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: chaos-dashboard +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Release.Name }}-chaos-dashboard-target-namespace +subjects: + - kind: ServiceAccount + name: {{ .Values.dashboard.serviceAccount }} + namespace: {{ .Release.Namespace | quote }} +{{- end }} diff --git a/helm/chaos-mesh/templates/controller-manager-deployment.yaml b/helm/chaos-mesh/templates/controller-manager-deployment.yaml index 04d7e58185..a9ba9d9ed2 100644 --- a/helm/chaos-mesh/templates/controller-manager-deployment.yaml +++ b/helm/chaos-mesh/templates/controller-manager-deployment.yaml @@ -1,49 +1,77 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + apiVersion: apps/v1 kind: Deployment metadata: namespace: {{ .Release.Namespace | quote }} name: chaos-controller-manager labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: controller-manager - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} spec: + {{- if not .Values.controllerManager.leaderElection.enabled }} + replicas: 1 + {{- else }} replicas: {{ .Values.controllerManager.replicaCount }} + {{- end }} selector: matchLabels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.selectors" . | nindent 6 }} app.kubernetes.io/component: controller-manager template: metadata: labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 8 }} app.kubernetes.io/component: controller-manager annotations: + {{- /* it requires to reload the latest re-generated certs for mtls after helm upgrade*/}} rollme: {{ randAlphaNum 5 | quote }} {{- with .Values.controllerManager.podAnnotations }} {{ toYaml . | indent 8 }} {{- end }} spec: - {{- if .Values.controllerManager.hostNetwork }} + securityContext: +{{ toYaml .Values.controllerManager.securityContext | indent 12 }} + {{- if .Values.controllerManager.hostNetwork }} hostNetwork: true - {{- end }} - {{- if .Values.controllerManager.serviceAccount }} - serviceAccount: {{ .Values.controllerManager.serviceAccount }} - {{- end }} - priorityClassName: {{ .Values.controllerManager.priorityClassName}} + {{- end }} + {{- if .Values.controllerManager.serviceAccountCreate }} + serviceAccountName: {{ .Values.controllerManager.serviceAccount }} + {{- end }} + {{- if .Values.controllerManager.priorityClassName }} + priorityClassName: {{ .Values.controllerManager.priorityClassName }} + {{- end }} + {{- if .Values.chaosDlv.enable }} + shareProcessNamespace: true + {{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.imagePullSecrets | nindent 8 }} + {{- end }} containers: - name: chaos-mesh - image: {{template "registry-prefix" .}}{{ .Values.controllerManager.image }} + image: {{template "chaos-controller-manager.image" . }} imagePullPolicy: {{ .Values.controllerManager.imagePullPolicy | default "IfNotPresent" }} resources: {{ toYaml .Values.controllerManager.resources | indent 12 }} command: - /usr/local/bin/chaos-controller-manager env: + {{- if .Values.controllerManager.env }} + {{- include "chaos-mesh.helpers.listEnvVars" .Values.controllerManager | trim | nindent 10 }} + {{- end }} - name: NAMESPACE valueFrom: fieldRef: @@ -60,10 +88,14 @@ spec: value: "{{ .Values.clusterScoped }}" - name: TZ value: {{ .Values.timezone | default "UTC" }} - - name: CHAOS_DAEMON_PORT + - name: CHAOS_DAEMON_SERVICE_PORT value: !!str {{ .Values.chaosDaemon.grpcPort }} - name: BPFKI_PORT value: !!str {{ .Values.bpfki.grpcPort }} + - name: ENABLED_CONTROLLERS + value: {{ .Values.controllerManager.enabledControllers | join "," | quote }} + - name: ENABLED_WEBHOOKS + value: {{ .Values.controllerManager.enabledWebhooks | join "," | quote }} - name: TEMPLATE_LABELS value: "app.kubernetes.io/component:template" - name: CONFIGMAP_LABELS @@ -74,47 +106,119 @@ spec: - name: PPROF_ADDR value: ":10081" {{- end }} + {{- if .Values.enableCtrlServer }} + - name: CTRL_ADDR + value: ":10082" + {{- end }} - name: CHAOS_DNS_SERVICE_NAME value: {{ .Values.dnsServer.name }} - name: CHAOS_DNS_SERVICE_PORT value: !!str {{ .Values.dnsServer.grpcPort }} - name: SECURITY_MODE - value: "{{ .Values.dashboard.securityMode }}" - {{- if .Values.dashboard.securityMode}} + value: {{ .Values.dashboard.securityMode | quote }} + - name: CHAOSD_SECURITY_MODE + value: {{ .Values.controllerManager.chaosdSecurityMode | quote }} + {{- if .Values.chaosDaemon.mtls.enabled }} - name: CHAOS_DAEMON_CLIENT_CERT value: /etc/chaos-daemon/cert/tls.crt - name: CHAOS_DAEMON_CLIENT_KEY value: /etc/chaos-daemon/cert/tls.key - name: CHAOS_MESH_CA_CERT value: /etc/chaos-daemon/cert/ca.crt + - name: QPS + value: "30" + - name: BURST + value: "50" + {{- end }} + {{- if .Values.controllerManager.chaosdSecurityMode }} + - name: CHAOSD_CA_CERT + value: /etc/chaosd/cert/ca.crt + - name: CHAOSD_CLIENT_CERT + value: /etc/chaosd/cert/tls.crt + - name: CHAOSD_CLIENT_KEY + value: /etc/chaosd/cert/tls.key {{- end }} + {{- if .Values.controllerManager.podChaos.podFailure.pauseImage }} + - name: POD_FAILURE_PAUSE_IMAGE + value: {{ .Values.controllerManager.podChaos.podFailure.pauseImage }} + {{- end }} + {{- if .Values.controllerManager.localHelmChart.enabled }} + - name: LOCAL_HELM_CHART_PATH + value: /data/helm + {{- end }} + - name: ENABLE_LEADER_ELECTION + value: {{ .Values.controllerManager.leaderElection.enabled | quote }} + - name: LEADER_ELECT_LEASE_DURATION + value: {{ .Values.controllerManager.leaderElection.leaseDuration | quote }} + - name: LEADER_ELECT_RENEW_DEADLINE + value: {{ .Values.controllerManager.leaderElection.renewDeadline | quote }} + - name: LEADER_ELECT_RETRY_PERIOD + value: {{ .Values.controllerManager.leaderElection.retryPeriod | quote }} volumeMounts: - name: webhook-certs mountPath: /etc/webhook/certs readOnly: true - {{- if .Values.dashboard.securityMode }} + {{- if .Values.chaosDaemon.mtls.enabled }} - name: chaos-daemon-client-cert mountPath: /etc/chaos-daemon/cert readOnly: true {{- end }} + {{- if .Values.controllerManager.chaosdSecurityMode }} + - name: chaosd-client-cert + mountPath: /etc/chaosd/cert + readOnly: true + {{- end }} + {{- if .Values.controllerManager.localHelmChart.enabled }} + - name: chaos-local-helm-chart + mountPath: /data/helm + readOnly: true + {{- end }} ports: - name: webhook - containerPort: 9443 # Customize containerPort + containerPort: {{ .Values.controllerManager.env.WEBHOOK_PORT }} - name: http - containerPort: 10080 + containerPort: {{ .Values.controllerManager.env.METRICS_PORT }} {{- if .Values.enableProfiling }} - name: pprof containerPort: 10081 {{- end }} + {{- if .Values.enableCtrlServer }} + - name: ctrl + containerPort: 10082 + {{- end }} + {{- if .Values.chaosDlv.enable }} + - name: chaos-mesh-dlv + image: {{template "chaos-dlv.image" . }} + imagePullPolicy: {{ .Values.chaosDlv.imagePullPolicy | default "IfNotPresent" }} + env: + - name: CMD_NAME + value: chaos-controller-manager + securityContext: + capabilities: + add: + - SYS_PTRACE + ports: + - name: dlv + containerPort: 8000 + {{- end }} volumes: - name: webhook-certs secret: secretName: {{ template "chaos-mesh.webhook.certs" . }} - {{- if .Values.dashboard.securityMode }} + {{- if .Values.chaosDaemon.mtls.enabled }} - name: chaos-daemon-client-cert secret: secretName: {{ template "chaos-mesh.daemon-client.certs" . }} {{- end }} + {{- if .Values.controllerManager.chaosdSecurityMode }} + - name: chaosd-client-cert + secret: + secretName: {{ template "chaos-mesh.chaosd-client.certs" . }} + {{- end }} + {{- if .Values.controllerManager.localHelmChart.enabled }} + - name: chaos-local-helm-chart +{{ toYaml .Values.controllerManager.localHelmChart.volume | indent 10 }} + {{- end }} {{- with .Values.controllerManager.nodeSelector }} nodeSelector: {{ toYaml . | indent 8 }} diff --git a/helm/chaos-mesh/templates/controller-manager-rbac.yaml b/helm/chaos-mesh/templates/controller-manager-rbac.yaml index 0e1d833bfe..7234e28abd 100644 --- a/helm/chaos-mesh/templates/controller-manager-rbac.yaml +++ b/helm/chaos-mesh/templates/controller-manager-rbac.yaml @@ -1,16 +1,32 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# {{- if .Values.rbac.create }} +{{- if .Values.controllerManager.serviceAccountCreate }} kind: ServiceAccount apiVersion: v1 metadata: namespace: {{ .Release.Namespace | quote }} name: {{ .Values.controllerManager.serviceAccount }} + {{- with .Values.controllerManager.serviceAccountAnnotations }} + annotations: +{{ toYaml . | indent 4 }} + {{- end }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: controller-manager - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} - +{{- end }} --- # roles kind: ClusterRole @@ -18,18 +34,24 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: {{ .Release.Name }}-chaos-controller-manager-target-namespace labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: controller-manager - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} rules: - apiGroups: [ "" ] - resources: [ "endpoints" ] - verbs: [ "get", "list", "watch" ] - - apiGroups: [ "" ] - resources: [ "pods", "secrets" ] - verbs: [ "get", "list", "watch", "delete", "update" ] + resources: [ "pods", "configmaps", "secrets"] + verbs: [ "get", "list", "watch", "delete", "update", "patch" ] + - apiGroups: + - "" + resources: + - pods + verbs: + - "create" + - apiGroups: + - "" + resources: + - "pods/log" + verbs: + - "get" - apiGroups: - "" resources: @@ -37,9 +59,9 @@ rules: verbs: - patch - create - - apiGroups: [ "" ] - resources: [ "configmaps" ] - verbs: [ "*" ] + - watch + - list + - get - apiGroups: [ "chaos-mesh.org" ] resources: - "*" @@ -51,25 +73,23 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: {{ .Release.Name }}-chaos-controller-manager-cluster-level labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: controller-manager - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} rules: - apiGroups: [ "" ] resources: - nodes -{{- if .Values.clusterScoped }} + - persistentvolumes + - persistentvolumeclaims + {{- if .Values.clusterScoped }} - namespaces - services -{{- end }} + {{- end }} verbs: [ "get", "list", "watch" ] - apiGroups: [ "authorization.k8s.io" ] resources: - subjectaccessreviews verbs: [ "create" ] - --- kind: Role @@ -78,20 +98,28 @@ metadata: name: {{ .Release.Name }}-chaos-controller-manager-control-plane namespace: {{ .Release.Namespace | quote }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: controller-manager - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} rules: - apiGroups: [ "" ] - resources: [ "configmaps", "services" ] + resources: [ "services", "secrets" ] verbs: [ "get", "list", "watch" ] + - apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["get", "list", "watch"] - apiGroups: [ "authorization.k8s.io" ] resources: - subjectaccessreviews verbs: [ "create" ] - + - apiGroups: [ "" ] + resources: [ "pods/exec" ] + verbs: [ "create" ] + - apiGroups: [ "coordination.k8s.io" ] + resources: [ "leases" ] + verbs: [ "*" ] + - apiGroups: [ "" ] + resources: [ "configmaps" ] + verbs: [ "*" ] --- # bindings cluster level kind: ClusterRoleBinding @@ -99,11 +127,8 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: {{ .Release.Name }}-chaos-controller-manager-cluster-level labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: controller-manager - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole @@ -121,11 +146,8 @@ metadata: name: {{ .Release.Name }}-chaos-controller-manager-control-plane namespace: {{ .Release.Namespace | quote }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: controller-manager - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} roleRef: apiGroup: rbac.authorization.k8s.io kind: Role @@ -136,21 +158,18 @@ subjects: namespace: {{ .Release.Namespace | quote }} --- -{{- if .Values.clusterScoped }} + {{- if .Values.clusterScoped }} kind: ClusterRoleBinding -{{- else }} + {{- else }} kind: RoleBinding -{{- end }} + {{- end }} apiVersion: rbac.authorization.k8s.io/v1 metadata: name: {{ .Release.Name }}-chaos-controller-manager-target-namespace namespace: {{ .Values.controllerManager.targetNamespace | quote }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: controller-manager - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/helm/chaos-mesh/templates/controller-manager-service.yaml b/helm/chaos-mesh/templates/controller-manager-service.yaml index 2178517b5e..bf824d737f 100644 --- a/helm/chaos-mesh/templates/controller-manager-service.yaml +++ b/helm/chaos-mesh/templates/controller-manager-service.yaml @@ -1,31 +1,57 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: v1 kind: Service metadata: namespace: {{ .Release.Namespace | quote }} name: {{ template "chaos-mesh.svc" . }} + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "{{ .Values.controllerManager.env.METRICS_PORT }}" labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: controller-manager - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} spec: type: {{ .Values.controllerManager.service.type }} ports: + - port: 443 + targetPort: webhook + protocol: TCP + name: webhook {{- if .Values.enableProfiling }} - port: 10081 targetPort: pprof protocol: TCP name: pprof {{- end }} - - port: 10080 + {{- if .Values.enableCtrlServer }} + - port: 10082 + targetPort: ctrl + protocol: TCP + name: ctrl + {{- end }} + {{- if .Values.chaosDlv.enable }} + - port: 8000 + targetPort: dlv + protocol: TCP + name: dlv + {{- end }} + - port: {{ .Values.controllerManager.env.METRICS_PORT }} targetPort: http protocol: TCP name: http - - port: 443 - targetPort: webhook - protocol: TCP - name: webhook selector: + {{- include "chaos-mesh.selectors" . | nindent 4 }} app.kubernetes.io/component: controller-manager - app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/helm/chaos-mesh/templates/dns-configmap.yaml b/helm/chaos-mesh/templates/dns-configmap.yaml index 2aa075f2f0..dcc9605b83 100644 --- a/helm/chaos-mesh/templates/dns-configmap.yaml +++ b/helm/chaos-mesh/templates/dns-configmap.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# {{- if .Values.dnsServer.create }} apiVersion: v1 kind: ConfigMap @@ -5,14 +19,11 @@ metadata: name: dns-server-config namespace: {{ .Release.Namespace | quote }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: chaos-dns-server - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} data: Corefile: | - .:53 { + .:5353 { errors health { lameduck 5s @@ -24,6 +35,7 @@ data: ttl 30 grpcport {{ .Values.dnsServer.grpcPort }} } + prometheus :9153 forward . /etc/resolv.conf { max_concurrent 1000 } diff --git a/helm/chaos-mesh/templates/dns-deployment.yaml b/helm/chaos-mesh/templates/dns-deployment.yaml index 60bb181b3b..2580c6c52f 100644 --- a/helm/chaos-mesh/templates/dns-deployment.yaml +++ b/helm/chaos-mesh/templates/dns-deployment.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# {{- if .Values.dnsServer.create }} apiVersion: apps/v1 kind: Deployment @@ -5,48 +19,33 @@ metadata: name: chaos-dns-server namespace: {{ .Release.Namespace | quote }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: chaos-dns-server - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} spec: - # replicas: not specified here: - # 1. In order to make Addon Manager do not reconcile this replicas parameter. - # 2. Default is 1. - # 3. Will be tuned in real time if DNS horizontal auto-scaling is turned on. + replicas: {{ .Values.dnsServer.replicas | default 1 }} strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1 selector: matchLabels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.selectors" . | nindent 6 }} app.kubernetes.io/component: chaos-dns-server template: metadata: labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 8 }} app.kubernetes.io/component: chaos-dns-server {{- with .Values.dnsServer.podAnnotations }} annotations: {{ toYaml . | indent 8 }} {{- end }} spec: - serviceAccountName: chaos-dns-server + serviceAccountName: {{ .Values.dnsServer.serviceAccount }} + {{- with .Values.dnsServer.affinity }} affinity: - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 100 - podAffinityTerm: - labelSelector: - matchExpressions: - - key: k8s-app - operator: In - values: ["chaos-dns"] - topologyKey: kubernetes.io/hostname +{{ toYaml . | indent 8 }} + {{- end }} {{- with .Values.dnsServer.tolerations }} tolerations: {{ toYaml . | indent 8 }} @@ -56,9 +55,12 @@ spec: {{ toYaml . | indent 8 }} {{- end }} priorityClassName: {{ .Values.dnsServer.priorityClassName}} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.imagePullSecrets | nindent 8 }} + {{- end }} containers: - name: chaos-dns-server - image: {{template "registry-prefix" .}}{{ .Values.dnsServer.image }} + image: {{ template "chaos-dns.image" . }} imagePullPolicy: {{ .Values.dnsServer.imagePullPolicy | default "IfNotPresent" }} resources: {{ toYaml .Values.dnsServer.resources | indent 10 }} @@ -68,10 +70,10 @@ spec: mountPath: /etc/chaos-dns readOnly: true ports: - - containerPort: 53 + - containerPort: 5353 name: dns protocol: UDP - - containerPort: 53 + - containerPort: 5353 name: dns-tcp protocol: TCP - containerPort: 9153 diff --git a/helm/chaos-mesh/templates/dns-rbac.yaml b/helm/chaos-mesh/templates/dns-rbac.yaml index 118ceafade..8db6bd93eb 100644 --- a/helm/chaos-mesh/templates/dns-rbac.yaml +++ b/helm/chaos-mesh/templates/dns-rbac.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# {{- if .Values.dnsServer.create }} kind: ServiceAccount apiVersion: v1 @@ -5,24 +19,18 @@ metadata: namespace: {{ .Release.Namespace | quote }} name: {{ .Values.dnsServer.serviceAccount }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: dns-server - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} --- # roles kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: {{ .Release.Name }}-chaos-dns-server + name: {{ .Release.Name }}-chaos-dns-server-target-namespace labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: dns-server - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} rules: - apiGroups: [ "" ] resources: [ "pods" ] @@ -41,11 +49,8 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: {{ .Release.Name }}-chaos-dns-server-cluster-level labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: dns-server - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} rules: - apiGroups: [ "" ] resources: @@ -62,11 +67,8 @@ metadata: name: {{ .Release.Name }}-chaos-dns-server-control-plane namespace: {{ .Release.Namespace | quote }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: dns-server - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} rules: - apiGroups: [ "" ] resources: [ "configmaps" ] @@ -79,11 +81,8 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: {{ .Release.Name }}-chaos-dns-server-cluster-level labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: dns-server - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole @@ -101,11 +100,8 @@ metadata: name: {{ .Release.Name }}-chaos-dns-server-control-plane namespace: {{ .Release.Namespace | quote }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: dns-server - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} roleRef: apiGroup: rbac.authorization.k8s.io kind: Role @@ -126,11 +122,8 @@ metadata: name: {{ .Release.Name }}-chaos-dns-server-target-namespace namespace: {{ .Values.dnsServer.targetNamespace | quote }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: dns-server - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/helm/chaos-mesh/templates/dns-service.yaml b/helm/chaos-mesh/templates/dns-service.yaml index a6e643fcce..2981a875b5 100644 --- a/helm/chaos-mesh/templates/dns-service.yaml +++ b/helm/chaos-mesh/templates/dns-service.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# {{- if .Values.dnsServer.create }} apiVersion: v1 kind: Service @@ -8,22 +22,20 @@ metadata: prometheus.io/port: "9153" prometheus.io/scrape: "true" labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: dns-server - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} spec: selector: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.selectors" . | nindent 4 }} app.kubernetes.io/component: chaos-dns-server ports: - name: dns port: 53 + targetPort: 5353 protocol: UDP - name: dns-tcp port: 53 + targetPort: 5353 protocol: TCP - name: metrics port: 9153 diff --git a/helm/chaos-mesh/templates/ingress.yaml b/helm/chaos-mesh/templates/ingress.yaml index 2c261b09c9..cb6530acc8 100644 --- a/helm/chaos-mesh/templates/ingress.yaml +++ b/helm/chaos-mesh/templates/ingress.yaml @@ -1,15 +1,27 @@ -{{- if .Values.dashboard.ingress.enabled -}} -apiVersion: extensions/v1beta1 +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.dashboard.ingress.enabled }} +{{- $paths := default (list "/") .Values.dashboard.ingress.paths }} +apiVersion: {{ include "chaos-dashboard.ingress.apiVersion" . }} kind: Ingress metadata: namespace: {{ .Release.Namespace | quote }} name: {{ template "chaos-dashboard.svc" . }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: chaos-dashboard - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} {{- if .Values.dashboard.ingress.labels }} {{ toYaml .Values.dashboard.ingress.labels | indent 4 }} {{- end }} @@ -21,17 +33,52 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} spec: + {{- if eq (include "chaos-dashboard.ingress.apiVersion" $) "networking.k8s.io/v1" }} + {{- with .Values.dashboard.ingress.ingressClassName }} + ingressClassName: {{ . }} + {{- end }} + {{- end }} rules: - {{- range .Values.dashboard.ingress.hosts }} + {{- if .Values.dashboard.ingress.hosts }} + {{- range .Values.dashboard.ingress.hosts }} - host: {{ .name | quote }} http: paths: - {{- $paths := default (list "/") .paths }} {{- range $paths }} - path: {{ . }} + {{- if eq (include "chaos-dashboard.ingress.apiVersion" $) "networking.k8s.io/v1" }} + pathType: Prefix + {{- end }} + backend: + {{- if eq (include "chaos-dashboard.ingress.apiVersion" $) "networking.k8s.io/v1" }} + service: + name: {{ template "chaos-dashboard.svc" . }} + port: + name: http + {{- else }} + serviceName: {{ template "chaos-dashboard.svc" . }} + servicePort: http + {{- end }} + {{- end }} + {{- end }} + {{- else }} + - http: + paths: + {{- range $paths }} + - path: {{ . }} + {{- if eq (include "chaos-dashboard.ingress.apiVersion" $) "networking.k8s.io/v1" }} + pathType: Prefix + {{- end }} backend: + {{- if eq (include "chaos-dashboard.ingress.apiVersion" $) "networking.k8s.io/v1" }} + service: + name: {{ template "chaos-dashboard.svc" . }} + port: + name: http + {{- else }} serviceName: {{ template "chaos-dashboard.svc" . }} servicePort: http + {{- end }} {{- end }} {{- end }} tls: diff --git a/helm/chaos-mesh/templates/mutating-admission-webhooks.yaml b/helm/chaos-mesh/templates/mutating-admission-webhooks.yaml new file mode 100644 index 0000000000..49f16055c4 --- /dev/null +++ b/helm/chaos-mesh/templates/mutating-admission-webhooks.yaml @@ -0,0 +1,80 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +{{- $webhookApiVersion := include "webhook.apiVersion" . -}} +{{- $caCert := include "webhook.caBundleCertPEM" . -}} +{{- $crtPEM := include "webhook.certPEM" . -}} +{{- $keyPEM := include "webhook.keyPEM" . -}} + +{{- $timeoutSeconds := .Values.webhook.timeoutSeconds }} +{{- $supportTimeoutSeconds := false }} +{{- if ge .Capabilities.KubeVersion.Minor "14" }} +{{- $supportTimeoutSeconds = true }} +{{- end }} +{{- $certManagerEnabled := .Values.webhook.certManager.enabled }} + +apiVersion: {{ $webhookApiVersion }} +kind: MutatingWebhookConfiguration +metadata: + name: {{ template "chaos-mesh.mutation" . }} + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: admission-webhook + {{- if $certManagerEnabled }} + annotations: + cert-manager.io/inject-ca-from: {{ printf "%s/%s" .Release.Namespace "chaos-mesh-cert" | quote }} + {{- end }} +webhooks: + {{- range $crd := .Values.webhook.CRDS }} + - clientConfig: + {{- if $certManagerEnabled }} + caBundle: Cg== + {{- else }} + caBundle: {{ ternary (b64enc $caCert) (b64enc (trim $crtPEM)) (empty $crtPEM) }} + {{- end }} + service: + name: {{ template "chaos-mesh.svc" $ }} + namespace: {{ $.Release.Namespace | quote }} + path: /mutate-chaos-mesh-org-v1alpha1-{{ $crd }} + failurePolicy: {{ $.Values.webhook.FailurePolicy }} + name: m{{ $crd }}.kb.io + {{- if $supportTimeoutSeconds }} + timeoutSeconds: {{ $timeoutSeconds }} + {{- if eq $webhookApiVersion "admissionregistration.k8s.io/v1" }} + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + {{- end }} + {{- end }} + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + {{- if eq $crd "schedule" }} + - schedules + {{- else if eq $crd "workflow" }} + - workflows + {{- else if eq $crd "physicalmachine" }} + - physicalmachines + {{- else if eq $crd "statuscheck" }} + - statuschecks + {{- else }} + - {{ $crd }} + {{- end }} + {{- end }} +--- diff --git a/helm/chaos-mesh/templates/prometheus-configmap.yaml b/helm/chaos-mesh/templates/prometheus-configmap.yaml index 496c90330c..c232826d5c 100644 --- a/helm/chaos-mesh/templates/prometheus-configmap.yaml +++ b/helm/chaos-mesh/templates/prometheus-configmap.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# {{- if .Values.prometheus.create }} kind: ConfigMap apiVersion: v1 @@ -5,11 +19,8 @@ metadata: namespace: {{ .Release.Namespace | quote }} name: prometheus-config labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: prometheus - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} data: prometheus.yml: |- global: diff --git a/helm/chaos-mesh/templates/prometheus-deployment.yaml b/helm/chaos-mesh/templates/prometheus-deployment.yaml index a617858b08..c04d9d277d 100644 --- a/helm/chaos-mesh/templates/prometheus-deployment.yaml +++ b/helm/chaos-mesh/templates/prometheus-deployment.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# {{- if .Values.prometheus.create }} apiVersion: apps/v1 @@ -6,23 +20,18 @@ metadata: namespace: {{ .Release.Namespace | quote }} name: chaos-prometheus labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: prometheus - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} spec: replicas: 1 selector: matchLabels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.selectors" . | nindent 6 }} app.kubernetes.io/component: prometheus template: metadata: labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 8 }} app.kubernetes.io/component: prometheus {{- with .Values.prometheus.podAnnotations }} annotations: @@ -33,6 +42,9 @@ spec: serviceAccount: {{ .Values.prometheus.serviceAccount }} {{- end }} priorityClassName: {{ .Values.prometheus.priorityClassName}} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.imagePullSecrets | nindent 8 }} + {{- end }} initContainers: - name: data-permission-fix image: busybox @@ -42,7 +54,7 @@ spec: mountPath: /data containers: - name: prometheus - image: {{template "registry-prefix" .}}{{ .Values.prometheus.image }} + image: {{ .Values.prometheus.image }} imagePullPolicy: {{ .Values.prometheus.imagePullPolicy | default "IfNotPresent" }} {{- if .Values.chaosDaemon.resources }} resources: @@ -95,6 +107,9 @@ kind: PersistentVolumeClaim metadata: namespace: {{ .Release.Namespace | quote }} name: prometheus-pvc + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: prometheus spec: {{- if .Values.prometheus.volume.storageClassName }} storageClassName: {{ .Values.prometheus.volume.storageClassName }} diff --git a/helm/chaos-mesh/templates/prometheus-rbac.yaml b/helm/chaos-mesh/templates/prometheus-rbac.yaml index f60e3a57c5..e3b2db2cc6 100644 --- a/helm/chaos-mesh/templates/prometheus-rbac.yaml +++ b/helm/chaos-mesh/templates/prometheus-rbac.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# {{- if .Values.prometheus.create }} {{- if .Values.rbac.create }} @@ -7,22 +21,16 @@ metadata: namespace: {{ .Release.Namespace | quote }} name: {{ .Values.prometheus.serviceAccount }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: prometheus - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: {{ .Release.Name }}-chaos-prometheus labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: prometheus - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} rules: - apiGroups: [""] resources: ["pods"] @@ -33,11 +41,8 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: {{ .Release.Name }}-chaos-prometheus labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: prometheus - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} subjects: - kind: ServiceAccount name: {{ .Values.prometheus.serviceAccount }} diff --git a/helm/chaos-mesh/templates/prometheus-service.yaml b/helm/chaos-mesh/templates/prometheus-service.yaml index 95d30b5ab6..3c10f6b918 100644 --- a/helm/chaos-mesh/templates/prometheus-service.yaml +++ b/helm/chaos-mesh/templates/prometheus-service.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# {{- if .Values.prometheus.create }} apiVersion: v1 @@ -6,11 +20,8 @@ metadata: namespace: {{ .Release.Namespace | quote }} name: chaos-prometheus labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: prometheus - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} spec: type: {{ .Values.prometheus.service.type }} ports: @@ -18,7 +29,7 @@ spec: targetPort: 9090 name: http selector: + {{- include "chaos-mesh.selectors" . | nindent 4 }} app.kubernetes.io/component: prometheus - app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} diff --git a/helm/chaos-mesh/templates/secrets-configuration.yaml b/helm/chaos-mesh/templates/secrets-configuration.yaml index 09bf5025b1..0ab05a6a4a 100644 --- a/helm/chaos-mesh/templates/secrets-configuration.yaml +++ b/helm/chaos-mesh/templates/secrets-configuration.yaml @@ -1,15 +1,18 @@ -{{- $webhookName := printf "%s.%s.svc" (include "chaos-mesh.svc" .) .Release.Namespace }} -{{- $ca := genCA "chaos-mesh-ca" 1825 }} -{{- $webhookServerCert := genSignedCert $webhookName nil (list $webhookName) 1825 $ca }} +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# {{- $certManagerEnabled := .Values.webhook.certManager.enabled }} -{{- $timeoutSeconds := .Values.webhook.timeoutSeconds }} -{{- $crtPEM := .Values.webhook.crtPEM }} -{{- $keyPEM := .Values.webhook.keyPEM }} - -{{- $supportTimeoutSeconds := false }} -{{- if ge .Capabilities.KubeVersion.Minor "14" }} -{{- $supportTimeoutSeconds = true }} -{{- end }} {{- if not $certManagerEnabled }} kind: Secret @@ -18,281 +21,64 @@ metadata: name: {{ template "chaos-mesh.webhook.certs" . }} namespace: {{ .Release.Namespace | quote }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: webhook-secret - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} type: Opaque data: - ca.crt: {{ b64enc $ca.Cert }} - tls.crt: {{ ternary (b64enc $webhookServerCert.Cert) (b64enc (trim $crtPEM)) (empty $crtPEM) }} - tls.key: {{ ternary (b64enc $webhookServerCert.Key) (b64enc (trim $keyPEM)) (empty $keyPEM) }} + ca.crt: {{ b64enc (include "webhook.caBundleCertPEM" .) }} + tls.crt: {{ b64enc (include "webhook.certPEM" .) }} + tls.key: {{ b64enc (include "webhook.keyPEM" .) }} -{{- if .Values.dashboard.securityMode }} +{{- if .Values.chaosDaemon.mtls.enabled }} --- -{{- $chaosDaemonCert := genSignedCert "chaos-daemon.chaos-mesh.org" nil (list "localhost" "chaos-daemon.chaos-mesh.org") 1825 $ca }} kind: Secret apiVersion: v1 metadata: name: {{ template "chaos-mesh.daemon.certs" . }} namespace: {{ .Release.Namespace | quote }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: chaos-daemon-cert - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} type: Opaque data: - ca.crt: {{ b64enc $ca.Cert }} - tls.crt: {{ b64enc $chaosDaemonCert.Cert }} - tls.key: {{ b64enc $chaosDaemonCert.Key }} + ca.crt: {{ b64enc (include "chaosmesh.selfSignedCABundleCertPEM" .) }} + tls.crt: {{ b64enc (include "chaosDaemon.server.certPEM" .) }} + tls.key: {{ b64enc (include "chaosDaemon.server.keyPEM" .) }} --- -{{- $chaosDaemonClientCert := genSignedCert "controller-manager.chaos-mesh.org" nil (list "localhost" "controller-manager.chaos-mesh.org") 1825 $ca }} kind: Secret apiVersion: v1 metadata: name: {{ template "chaos-mesh.daemon-client.certs" . }} namespace: {{ .Release.Namespace | quote }} labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} + {{- include "chaos-mesh.labels" . | nindent 4 }} app.kubernetes.io/component: chaos-daemon-client-cert - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} type: Opaque data: - ca.crt: {{ b64enc $ca.Cert }} - tls.crt: {{ b64enc $chaosDaemonClientCert.Cert }} - tls.key: {{ b64enc $chaosDaemonClientCert.Key }} + ca.crt: {{ b64enc (include "chaosmesh.selfSignedCABundleCertPEM" .) }} + tls.crt: {{ b64enc (include "chaosDaemon.client.certPEM" .) }} + tls.key: {{ b64enc (include "chaosDaemon.client.keyPEM" .) }} {{- end }} {{- end }} ---- -apiVersion: admissionregistration.k8s.io/v1beta1 -kind: MutatingWebhookConfiguration -metadata: - name: {{ template "chaos-mesh.mutation" . }} - labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/component: admission-webhook - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} - {{- if $certManagerEnabled }} - annotations: - cert-manager.io/inject-ca-from: {{ printf "%s/%s" .Release.Namespace "chaos-mesh-cert" | quote }} - {{- end }} -webhooks: - - name: {{ template "chaos-mesh.webhook" . }} - {{- if $supportTimeoutSeconds }} - timeoutSeconds: {{ $timeoutSeconds }} - {{- end}} - clientConfig: - {{- if $certManagerEnabled }} - caBundle: Cg== - {{- else }} - caBundle: {{ ternary (b64enc $ca.Cert) (b64enc (trim $crtPEM)) (empty $crtPEM) }} - {{- end }} - service: - name: {{ template "chaos-mesh.svc" . }} - namespace: {{ .Release.Namespace | quote }} - path: "/inject-v1-pod" - rules: - - operations: [ "CREATE" ] - apiGroups: [""] - apiVersions: ["v1"] - resources: ["pods"] - namespaceSelector: - matchLabels: - admission-webhook: enabled - failurePolicy: {{ .Values.webhook.FailurePolicy }} - {{- range $crd := .Values.webhook.CRDS }} - - clientConfig: - {{- if $certManagerEnabled }} - caBundle: Cg== - {{- else }} - caBundle: {{ ternary (b64enc $ca.Cert) (b64enc (trim $crtPEM)) (empty $crtPEM) }} - {{- end }} - service: - name: {{ template "chaos-mesh.svc" $ }} - namespace: {{ $.Release.Namespace | quote }} - path: /mutate-chaos-mesh-org-v1alpha1-{{ $crd }} - failurePolicy: Fail - name: m{{ $crd }}.kb.io - {{- if $supportTimeoutSeconds }} - timeoutSeconds: {{ $timeoutSeconds }} - {{- end}} - rules: - - apiGroups: - - chaos-mesh.org - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - {{ $crd }} - {{- end }} ---- - -apiVersion: admissionregistration.k8s.io/v1beta1 -kind: ValidatingWebhookConfiguration -metadata: - name: {{ template "chaos-mesh.validation" . }} - labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/component: admission-webhook - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} - {{- if $certManagerEnabled }} - annotations: - cert-manager.io/inject-ca-from: {{ printf "%s/%s" .Release.Namespace "chaos-mesh-cert" | quote }} - {{- end }} -webhooks: - {{- range $crd := .Values.webhook.CRDS }} - {{- if ne $crd "podiochaos" }} - - clientConfig: - {{- if $certManagerEnabled }} - caBundle: Cg== - {{- else }} - caBundle: {{ ternary (b64enc $ca.Cert) (b64enc (trim $crtPEM)) (empty $crtPEM) }} - {{- end }} - service: - name: {{ template "chaos-mesh.svc" $ }} - namespace: {{ $.Release.Namespace | quote }} - path: /validate-chaos-mesh-org-v1alpha1-{{ $crd }} - failurePolicy: Fail - name: v{{ $crd }}.kb.io - {{- if $supportTimeoutSeconds }} - timeoutSeconds: {{ $timeoutSeconds }} - {{- end}} - rules: - - apiGroups: - - chaos-mesh.org - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - {{ $crd }} - {{- end }} - {{- end }} +{{- if .Values.controllerManager.chaosdSecurityMode }} --- - -apiVersion: admissionregistration.k8s.io/v1beta1 -kind: ValidatingWebhookConfiguration -metadata: - name: validate-auth - labels: - app.kubernetes.io/name: {{ template "chaos-mesh.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/component: admission-webhook - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} - {{- if $certManagerEnabled }} - annotations: - cert-manager.io/inject-ca-from: {{ printf "%s/%s" .Release.Namespace "chaos-mesh-cert" | quote }} - {{- end }} -webhooks: - - clientConfig: - {{- if $certManagerEnabled }} - caBundle: Cg== - {{- else }} - caBundle: {{ ternary (b64enc $ca.Cert) (b64enc (trim $crtPEM)) (empty $crtPEM) }} - {{- end }} - service: - name: {{ template "chaos-mesh.svc" $ }} - namespace: {{ $.Release.Namespace | quote }} - path: /validate-auth - failurePolicy: Fail - name: vauth.kb.io - rules: - - apiGroups: - - chaos-mesh.org - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: [ "*" ] - -{{- if $certManagerEnabled }} ---- -apiVersion: cert-manager.io/v1alpha2 -kind: Issuer -metadata: - name: chaos-mesh-selfsigned - namespace: {{ .Release.Namespace | quote }} -spec: - selfSigned: {} ---- -apiVersion: cert-manager.io/v1alpha2 -kind: Certificate -metadata: - name: chaos-mesh-ca - namespace: {{ .Release.Namespace | quote }} -spec: - secretName: chaos-mesh-ca - commonName: "chaos-mesh-ca" - isCA: true - issuerRef: - name: chaos-mesh-selfsigned ---- -apiVersion: cert-manager.io/v1alpha2 -kind: Issuer -metadata: - name: chaos-mesh-ca - namespace: {{ .Release.Namespace | quote }} -spec: - ca: - secretName: chaos-mesh-ca ---- -apiVersion: cert-manager.io/v1alpha2 -kind: Certificate -metadata: - name: chaos-mesh-cert - namespace: {{ .Release.Namespace | quote }} -spec: - duration: 43800h #5year - dnsNames: - - {{ template "chaos-mesh.svc" . }} - - {{ template "chaos-mesh.svc" . }}.{{ .Release.Namespace }} - - {{ template "chaos-mesh.svc" . }}.{{ .Release.Namespace }}.svc - isCA: false - secretName: {{ template "chaos-mesh.webhook.certs" . }} - issuerRef: - name: chaos-mesh-ca ---- -apiVersion: cert-manager.io/v1alpha2 -kind: Certificate -metadata: - name: chaos-daemon-client-cert - namespace: {{ .Release.Namespace | quote }} -spec: - duration: 43800h #5year - dnsNames: - - controller-manager.chaos-mesh.org - isCA: false - secretName: {{ template "chaos-mesh.daemon-client.certs" . }} - issuerRef: - name: chaos-mesh-ca ---- -apiVersion: cert-manager.io/v1alpha2 -kind: Certificate +{{- $chaosdCA := genCA "chaosd-ca" 1825 }} +{{- $chaosdClientCert := genSignedCert "controller-manager.chaos-mesh.org" nil (list "localhost" "controller-manager.chaos-mesh.org") 1825 $chaosdCA }} +kind: Secret +apiVersion: v1 metadata: - name: chaos-daemon-cert + name: {{ template "chaos-mesh.chaosd-client.certs" . }} namespace: {{ .Release.Namespace | quote }} -spec: - duration: 43800h #5year - dnsNames: - - chaos-daemon.chaos-mesh.org - isCA: false - secretName: {{ template "chaos-mesh.daemon.certs" . }} - issuerRef: - name: chaos-mesh-ca + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: chaosd-client-cert +type: Opaque +data: + ca.crt: {{ b64enc $chaosdCA.Cert }} + ca.key: {{ b64enc $chaosdCA.Key }} + tls.crt: {{ b64enc $chaosdClientCert.Cert }} + tls.key: {{ b64enc $chaosdClientCert.Key }} {{- end }} +--- diff --git a/helm/chaos-mesh/templates/validating-admission-webhooks.yaml b/helm/chaos-mesh/templates/validating-admission-webhooks.yaml new file mode 100644 index 0000000000..d2e0fb2728 --- /dev/null +++ b/helm/chaos-mesh/templates/validating-admission-webhooks.yaml @@ -0,0 +1,124 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +{{- $webhookApiVersion := include "webhook.apiVersion" . -}} +{{- $caCert := include "webhook.caBundleCertPEM" . -}} +{{- $crtPEM := include "webhook.certPEM" . -}} +{{- $keyPEM := include "webhook.keyPEM" . -}} + +{{- $timeoutSeconds := .Values.webhook.timeoutSeconds }} +{{- $supportTimeoutSeconds := false }} +{{- if ge .Capabilities.KubeVersion.Minor "14" }} +{{- $supportTimeoutSeconds = true }} +{{- end }} +{{- $certManagerEnabled := .Values.webhook.certManager.enabled }} + +apiVersion: {{ $webhookApiVersion }} +kind: ValidatingWebhookConfiguration +metadata: + name: {{ template "chaos-mesh.validation" . }} + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: admission-webhook + {{- if $certManagerEnabled }} + annotations: + cert-manager.io/inject-ca-from: {{ printf "%s/%s" .Release.Namespace "chaos-mesh-cert" | quote }} + {{- end }} +webhooks: + {{- range $crd := .Values.webhook.CRDS }} + {{- /* TODO: podiochaos and podhttpchaos are not in CRDS list, we could remove it later. */ -}} + {{- if not (or (eq $crd "podiochaos") (eq $crd "podhttpchaos")) }} + - clientConfig: + {{- if $certManagerEnabled }} + caBundle: Cg== + {{- else }} + caBundle: {{ ternary (b64enc $caCert) (b64enc (trim $crtPEM)) (empty $crtPEM) }} + {{- end }} + service: + name: {{ template "chaos-mesh.svc" $ }} + namespace: {{ $.Release.Namespace | quote }} + path: /validate-chaos-mesh-org-v1alpha1-{{ $crd }} + failurePolicy: {{ $.Values.webhook.FailurePolicy }} + name: v{{ $crd }}.kb.io + {{- if $supportTimeoutSeconds }} + timeoutSeconds: {{ $timeoutSeconds }} + {{- if eq $webhookApiVersion "admissionregistration.k8s.io/v1" }} + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + {{- end }} + {{- end }} + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + {{- if eq $crd "schedule" }} + - schedules + {{- else if eq $crd "workflow" }} + - workflows + {{- else if eq $crd "physicalmachine" }} + - physicalmachines + {{- else if eq $crd "statuscheck" }} + - statuschecks + {{- else }} + - {{ $crd }} + {{- end }} + {{- end }} + {{- end }} +--- + +apiVersion: {{ $webhookApiVersion }} +kind: ValidatingWebhookConfiguration +metadata: + name: {{ template "chaos-mesh.validation" . }}-auth + labels: + {{- include "chaos-mesh.labels" . | nindent 4 }} + app.kubernetes.io/component: admission-webhook + {{- if $certManagerEnabled }} + annotations: + cert-manager.io/inject-ca-from: {{ printf "%s/%s" .Release.Namespace "chaos-mesh-cert" | quote }} + {{- end }} +webhooks: + - clientConfig: + {{- if $certManagerEnabled }} + caBundle: Cg== + {{- else }} + caBundle: {{ ternary (b64enc $caCert) (b64enc (trim $crtPEM)) (empty $crtPEM) }} + {{- end }} + service: + name: {{ template "chaos-mesh.svc" $ }} + namespace: {{ $.Release.Namespace | quote }} + path: /validate-auth + failurePolicy: {{ .Values.webhook.FailurePolicy }} + name: vauth.kb.io + {{- if $supportTimeoutSeconds }} + timeoutSeconds: {{ $timeoutSeconds }} + {{- if eq $webhookApiVersion "admissionregistration.k8s.io/v1" }} + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + {{- end }} + {{- end }} + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: [ "*" ] diff --git a/helm/chaos-mesh/values.schema.json b/helm/chaos-mesh/values.schema.json new file mode 100644 index 0000000000..581111eccb --- /dev/null +++ b/helm/chaos-mesh/values.schema.json @@ -0,0 +1,869 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "bpfki": { + "properties": { + "create": { + "type": "boolean" + }, + "grpcPort": { + "type": "integer" + }, + "image": { + "properties": { + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + }, + "type": "object" + }, + "imagePullPolicy": { + "type": "string" + }, + "resources": { + "properties": {}, + "type": "object" + } + }, + "type": "object" + }, + "chaosDaemon": { + "properties": { + "affinity": { + "properties": {}, + "type": "object" + }, + "capabilities": { + "properties": { + "add": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "env": { + "properties": {}, + "type": "object" + }, + "grpcPort": { + "type": "integer" + }, + "hostNetwork": { + "type": "boolean" + }, + "httpPort": { + "type": "integer" + }, + "image": { + "properties": { + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + }, + "type": "object" + }, + "imagePullPolicy": { + "type": "string" + }, + "mtls": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "nodeSelector": { + "properties": {}, + "type": "object" + }, + "podAnnotations": { + "properties": {}, + "type": "object" + }, + "podSecurityPolicy": { + "type": "boolean" + }, + "priorityClassName": { + "type": "string" + }, + "privileged": { + "type": "boolean" + }, + "resources": { + "properties": {}, + "type": "object" + }, + "runtime": { + "type": "string" + }, + "securityContext": { + "properties": {}, + "type": "object" + }, + "service": { + "properties": { + "scrape": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "serviceAccount": { + "type": "string" + }, + "serviceAccountAnnotations": { + "properties": {}, + "type": "object" + }, + "socketPath": { + "type": "string" + }, + "tolerations": { + "type": "array" + }, + "updateStrategy": { + "properties": {}, + "type": "object" + } + }, + "type": "object" + }, + "chaosDlv": { + "properties": { + "enable": { + "type": "boolean" + }, + "image": { + "properties": { + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + }, + "type": "object" + }, + "imagePullPolicy": { + "type": "string" + } + }, + "type": "object" + }, + "clusterScoped": { + "type": "boolean" + }, + "controllerManager": { + "properties": { + "affinity": { + "properties": {}, + "type": "object" + }, + "allowHostNetworkTesting": { + "type": "boolean" + }, + "chaosdSecurityMode": { + "type": "boolean" + }, + "enableFilterNamespace": { + "type": "boolean" + }, + "enabledControllers": { + "items": { + "type": "string" + }, + "type": "array" + }, + "enabledWebhooks": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "properties": { + "METRICS_PORT": { + "type": "integer" + }, + "WEBHOOK_PORT": { + "type": "integer" + } + }, + "type": "object" + }, + "hostNetwork": { + "type": "boolean" + }, + "image": { + "properties": { + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + }, + "type": "object" + }, + "imagePullPolicy": { + "type": "string" + }, + "leaderElection": { + "properties": { + "enabled": { + "type": "boolean" + }, + "leaseDuration": { + "type": "string" + }, + "renewDeadline": { + "type": "string" + }, + "retryPeriod": { + "type": "string" + } + }, + "type": "object" + }, + "localHelmChart": { + "properties": { + "enabled": { + "type": "boolean" + }, + "volume": { + "properties": { + "hostPath": { + "properties": { + "path": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "nodeSelector": { + "properties": {}, + "type": "object" + }, + "podAnnotations": { + "properties": {}, + "type": "object" + }, + "podChaos": { + "properties": { + "podFailure": { + "properties": { + "pauseImage": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "priorityClassName": { + "type": "string" + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "properties": { + "limits": { + "properties": {}, + "type": "object" + }, + "requests": { + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "securityContext": { + "properties": {}, + "type": "object" + }, + "service": { + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" + }, + "serviceAccount": { + "type": "string" + }, + "serviceAccountAnnotations": { + "properties": {}, + "type": "object" + }, + "serviceAccountCreate": { + "type": "boolean" + }, + "targetNamespace": { + "type": "string" + }, + "tolerations": { + "type": "array" + } + }, + "type": "object" + }, + "customLabels": { + "properties": {}, + "type": "object" + }, + "dashboard": { + "properties": { + "affinity": { + "properties": {}, + "type": "object" + }, + "create": { + "type": "boolean" + }, + "databaseSecretName": { + "type": "string" + }, + "env": { + "properties": { + "CLEAN_SYNC_PERIOD": { + "type": "string" + }, + "DATABASE_DATASOURCE": { + "type": "string" + }, + "DATABASE_DRIVER": { + "type": "string" + }, + "LISTEN_HOST": { + "type": "string" + }, + "LISTEN_PORT": { + "type": "integer" + }, + "METRIC_HOST": { + "type": "string" + }, + "METRIC_PORT": { + "type": "integer" + }, + "TTL_EVENT": { + "type": "string" + }, + "TTL_EXPERIMENT": { + "type": "string" + }, + "TTL_SCHEDULE": { + "type": "string" + }, + "TTL_WORKFLOW": { + "type": "string" + } + }, + "type": "object" + }, + "extraContainers": { + "type": "array" + }, + "gcpSecurityMode": { + "properties": { + "clientId": { + "type": "string" + }, + "clientSecret": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "existingSecret": { + "type": "string" + } + }, + "type": "object" + }, + "hostNetwork": { + "type": "boolean" + }, + "image": { + "properties": { + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + }, + "type": "object" + }, + "imagePullPolicy": { + "type": "string" + }, + "ingress": { + "properties": { + "apiVersionOverrides": { + "type": "string" + }, + "certManager": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "hosts": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "tls": { + "type": "boolean" + }, + "tlsSecret": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "ingressClassName": { + "type": "string" + }, + "paths": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "nodeSelector": { + "properties": {}, + "type": "object" + }, + "persistentVolume": { + "properties": { + "enabled": { + "type": "boolean" + }, + "existingClaim": { + "type": "string" + }, + "mountPath": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClassName": { + "type": "string" + }, + "subPath": { + "type": "string" + } + }, + "type": "object" + }, + "podAnnotations": { + "properties": {}, + "type": "object" + }, + "priorityClassName": { + "type": "string" + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "properties": { + "limits": { + "properties": {}, + "type": "object" + }, + "requests": { + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "rootUrl": { + "type": "string" + }, + "securityContext": { + "properties": {}, + "type": "object" + }, + "securityMode": { + "type": "boolean" + }, + "service": { + "properties": { + "annotations": { + "properties": {}, + "type": "object" + }, + "type": { + "type": "string" + } + }, + "type": "object" + }, + "serviceAccount": { + "type": "string" + }, + "tolerations": { + "type": "array" + } + }, + "type": "object" + }, + "dnsServer": { + "properties": { + "affinity": { + "properties": { + "podAntiAffinity": { + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "podAffinityTerm": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "topologyKey": { + "type": "string" + } + }, + "type": "object" + }, + "weight": { + "type": "integer" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "create": { + "type": "boolean" + }, + "env": { + "properties": { + "LISTEN_HOST": { + "type": "string" + }, + "LISTEN_PORT": { + "type": "integer" + } + }, + "type": "object" + }, + "grpcPort": { + "type": "integer" + }, + "image": { + "properties": { + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + }, + "type": "object" + }, + "imagePullPolicy": { + "type": "string" + }, + "name": { + "type": "string" + }, + "nodeSelector": { + "properties": {}, + "type": "object" + }, + "podAnnotations": { + "properties": {}, + "type": "object" + }, + "priorityClassName": { + "type": "string" + }, + "replicas": { + "type": "integer" + }, + "resources": { + "properties": { + "limits": { + "properties": {}, + "type": "object" + }, + "requests": { + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "serviceAccount": { + "type": "string" + }, + "tolerations": { + "type": "array" + } + }, + "type": "object" + }, + "enableCtrlServer": { + "type": "boolean" + }, + "enableProfiling": { + "type": "boolean" + }, + "fullnameOverride": { + "type": "string" + }, + "imagePullSecrets": { + "type": "array" + }, + "images": { + "properties": { + "registry": { + "type": "string" + }, + "tag": { + "type": "string" + } + }, + "type": "object" + }, + "nameOverride": { + "type": "string" + }, + "prometheus": { + "properties": { + "affinity": { + "properties": {}, + "type": "object" + }, + "create": { + "type": "boolean" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "nodeSelector": { + "properties": {}, + "type": "object" + }, + "podAnnotations": { + "properties": {}, + "type": "object" + }, + "priorityClassName": { + "type": "string" + }, + "resources": { + "properties": { + "limits": { + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + }, + "type": "object" + }, + "requests": { + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "service": { + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" + }, + "serviceAccount": { + "type": "string" + }, + "tolerations": { + "type": "array" + }, + "volume": { + "properties": { + "storage": { + "type": "string" + }, + "storageClassName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "rbac": { + "properties": { + "create": { + "type": "boolean" + } + }, + "type": "object" + }, + "timezone": { + "type": "string" + }, + "webhook": { + "properties": { + "CRDS": { + "items": { + "type": "string" + }, + "type": "array" + }, + "FailurePolicy": { + "type": "string" + }, + "caBundlePEM": { + "type": "string" + }, + "certManager": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "crtPEM": { + "type": "string" + }, + "keyPEM": { + "type": "string" + }, + "timeoutSeconds": { + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" +} diff --git a/helm/chaos-mesh/values.yaml b/helm/chaos-mesh/values.yaml index 84a368df15..220ecbf37f 100644 --- a/helm/chaos-mesh/values.yaml +++ b/helm/chaos-mesh/values.yaml @@ -1,14 +1,32 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# # Default values for chaos-mesh. # This is a YAML-formatted file. # Declare variables to be passed into your templates. +# nameOverride: "" fullnameOverride: "" +# Custom labels to add +customLabels: {} + # clusterScoped is whether chaos-mesh should manage kubernetes cluster wide chaos # Also see rbac.create and controllerManager.serviceAccount clusterScoped: true -# Also see clusterScoped and controllerManager.serviceAccount +# Creating rbac API Objects. Also see clusterScoped and controllerManager.serviceAccount rbac: create: true @@ -23,26 +41,66 @@ timezone: "UTC" # enableProfiling is a flag to enable pprof in controller-manager and chaos-daemon. enableProfiling: true -registry: "" +# enableCtrlServer is a flag to enable ctrlserver which provides service to chaosctl in controller-manager. +enableCtrlServer: true + +images: + # images.registry is the global container registry for the images, you could replace it with your self-hosted container registry. + registry: "ghcr.io" + # images.tag is the global image tag (for example, semiVer with prefix v, or latest). + tag: "latest" + +## Optional array of imagePullSecrets containing private registry credentials +## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ +imagePullSecrets: [] +# - name: secretName controllerManager: + # securityContext if needed + securityContext: {} + # running chaos-controller-manager on host network hostNetwork: false + # Allow testing on `hostNetwork` pods. This is Dangerous. Please run only as temporary solution. + allowHostNetworkTesting: false + # The serviceAccount for chaos-controller-manager serviceAccount: chaos-controller-manager - - replicaCount: 1 - + # ServiceAccount annotations for chaos-controller-manager + serviceAccountAnnotations: {} + # Create the serviceAccount for chaos-controller-manager + serviceAccountCreate: true + # Custom priorityClassName for using pod priorities priorityClassName: "" - - image: pingcap/chaos-mesh:latest + # Replicas for chaos-controller-manager + replicaCount: 3 + # image would be constructed by /: + image: + # override global registry, empty value means using the global images.registry + registry: "" + # repository part for image of chaos-controller-manager + repository: chaos-mesh/chaos-mesh + # override global tag, empty value means using the global images.tag + tag: "" + # Image pull policy imagePullPolicy: IfNotPresent + # The keys within the "env" map are mounted as environment variables on the pod. + env: + # WEBHOOK_PORT is configured the port for chaos-controller-manager provides webhooks. + # In GKE private clusters, by default kubernetes apiservers are allowed to + # talk to the cluster nodes only on 443 and 10250. so configuring + # WEBHOOK_PORT: 10250, will work out of the box without needing to add firewall + # rules or requiring NET_BIND_SERVICE capabilities to bind port numbers <1000 + WEBHOOK_PORT: 10250 + # METRICS_PORT is configured the port for chaos-controller-manager exposing prometheus metrics + METRICS_PORT: 10080 + # If enabled, only pods in the namespace annotated with `"chaos-mesh.org/inject": "enabled"` could be injected enableFilterNamespace: false - # targetNamespace only works with clusterScoped is false(namespace scoped mode). # It means namespace which will be injected chaos - targetNamespace: chaos-testing + targetNamespace: chaos-mesh service: + # Kubernetes Service type for service chaos-controller-manager type: ClusterIP resources: @@ -56,56 +114,100 @@ controllerManager: requests: cpu: 25m memory: 256Mi - + # Node labels for chaos-controller-manager pod assignment nodeSelector: {} - + # Toleration labels for chaos-controller-manager pod assignment tolerations: [] - + # Map of chaos-controller-manager node/pod affinities affinity: {} - + # Pod annotations of chaos-controller-manager podAnnotations: {} - - # This is Dangerous. Run only on temporary clusters. - allowHostNetworkTesting: false + # A list of controllers to enable. "*" enables all controllers by default. + enabledControllers: + - "*" + # A list of webhooks to enable. "*" enables all webhooks by default. + enabledWebhooks: + - "*" + podChaos: + podFailure: + # Custom Pause Container Image for Pod Failure Chaos + pauseImage: gcr.io/google-containers/pause:latest + leaderElection: + # Enable leader election for controller manager. + enabled: true + # The duration that non-leader candidates will wait to force acquire leadership. This is measured against time of last observed ack. + leaseDuration: 15s + # The duration that the acting control-plane will retry refreshing leadership before giving up. + renewDeadline: 10s + # The duration the LeaderElector clients should wait between tries of actions. + retryPeriod: 2s + # chaosdSecurityMode is enabled for mTLS connection between chaos-controller-manager and chaosd + chaosdSecurityMode: true + # multi cluster install offline helm chart path + localHelmChart: + enabled: false + volume: + hostPath: + path: /data/helm + type: DirectoryOrCreate chaosDaemon: - image: pingcap/chaos-daemon:latest + # image would be constructed by /: + image: + # override global registry, empty value means using the global images.registry + registry: "" + # repository part for image of chaos-daemon + repository: chaos-mesh/chaos-daemon + # empty tag means using the global images.tag + tag: "" + # Image pull policy imagePullPolicy: IfNotPresent + # The port which grpc server listens on. grpcPort: 31767 + # The port which http server listens on. httpPort: 31766 + # extra chaosDaemon envs env: {} + # securityContext if needed + securityContext: {} + # running chaosDaemon on host network hostNetwork: false + # configurations about mtls. + # currently we do not support use specified ca and cert for mtls, it would generate the ca and certs when chaos mesh deploy by helm. + mtls: + # enable mtls on the grpc connection between chaos-controller-manager and chaos-daemon + enabled: true # Run chaos-daemon container in privileged mode. Processes in privileged containers # are essentially equivalent to root on the host. # If it is set to false, the following capabilities will be set. You can grant certain privileges # to a process without granting all the privileges of the root user. - ## capabilities: - ## add: - ## - SYS_PTRACE - ## - NET_ADMIN - ## - MKNOD - ## - SYS_CHROOT - ## - SYS_ADMIN - ## - KILL - ## # CAP_IPC_LOCK is used to lock memory - ## - IPC_LOCK + capabilities: + add: + - SYS_PTRACE + - NET_ADMIN + - NET_RAW + - MKNOD + - SYS_CHROOT + - SYS_ADMIN + - KILL + # CAP_IPC_LOCK is used to lock memory + - IPC_LOCK privileged: true - + # Custom priorityClassName for using pod priorities priorityClassName: "" - + # Pod annotations of chaos-daemon podAnnotations: {} - + # ServiceAccount name for chaos-daemon serviceAccount: chaos-daemon - - # enable a podSecurityPolicy(psp) + # ServiceAccount annotations for chaos-daemon + serviceAccountAnnotations: {} + # Specify PodSecurityPolicy(psp) on chaos-daemon pods podSecurityPolicy: false - # runtime specifies which container runtime to use. Currently - # we only supports docker and containerd. + # we only supports docker, containerd and CRI-O. runtime: docker - - # socketPath specifies the container runtime socket. + # socketPath specifies the path of container runtime socket on the host. socketPath: /var/run/docker.sock # If you are using Kind or using containerd as CRI, you can use the @@ -113,7 +215,17 @@ chaosDaemon: # runtime: containerd # socketPath: /run/containerd/containerd.sock - resources: {} + # If you are using CRI-O as CRI, you can use the + # config below to use CRI-O as the runtime in chaos-daemon. + # runtime: crio + # socketPath: /var/run/crio/crio.sock + + # You can customize socket dir via socketDir + # If you set socketPath and socketDir at the same time, only socketPath will work. + + # CPU/Memory resource requests/limits for chaosDaemon container + resources: + {} # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little # resources, such as Minikube. If you do want to specify resources, uncomment the following @@ -124,42 +236,87 @@ chaosDaemon: # requests: # cpu: 250m # memory: 512Mi - + # Node labels for chaos-daemon pod assignment nodeSelector: {} - + # Toleration labels for chaos-daemon pod assignment tolerations: [] - + # Map of chaos-controller-manager node/pod affinities affinity: {} + # Specify DaemonSetUpdateStrategy for chaos-daemon + updateStrategy: + {} + # Example update strategy: + # type: RollingUpdate + # rollingUpdate: + # maxUnavailable: 33% + + # Service setting for chaos-daemon + service: + scrape: + # Enable metric scraping from Promethues by annotations + enabled: true + dashboard: + # Enable chaos-dashboard create: true + # Optional, the secret name that has `DATABASE_DATASOURCE` defined. + # It's recommended to use a secret to store the database credentials. + databaseSecretName: "" + # rootUrl specify the base url for openid/oauth2 (like GCP Auth Integration) callback URL. + rootUrl: http://localhost:2333 + # securityContext if needed + securityContext: {} + # running chaos-dashboard on host network hostNetwork: false - + # replicas of chaos-dashboard replicaCount: 1 - + # Custom priorityClassName for using pod priorities priorityClassName: "" - - serviceAccount: chaos-controller-manager - - image: pingcap/chaos-dashboard:latest + # The serviceAccount for chaos-dashboard + serviceAccount: chaos-dashboard + image: + # override global registry, empty value means using the global images.registry + registry: "" + # repository part for image of chaos-dashboard + repository: chaos-mesh/chaos-dashboard + # override global tag, empty value means using the global images.tag + tag: "" + # Image pull policy imagePullPolicy: IfNotPresent - + # securityMode requires user to provide credentials on Chaos Dashboard, instead of using chaos-dashboard service account securityMode: true - + # Enable GCP Authentication Integration, see: https://chaos-mesh.org/docs/gcp-authentication/ for more details + gcpSecurityMode: + enabled: false + clientId: "" + clientSecret: "" + # References existing Kubernetes secret containing `GCP_CLIENT_ID` and `GCP_CLIENT_SECRET`. + existingSecret: "" + # Node labels for chaos-dashboard pod assignment nodeSelector: {} - + # Toleration labels for chaos-dashboard pod assignment tolerations: [] - + # Map of chaos-dashboard node/pod affinities affinity: {} - + # Deployment chaos-dashboard annotations podAnnotations: {} - + # list of extra sidecar containers + extraContainers: [] service: + # Service annotations for the dashboard annotations: {} + # Service type of the service created for exposing the dashboard type: NodePort + # Set the `clusterIP` of the dashboard service if the type is `ClusterIP` # clusterIP: + # Set the `nodePort` of the dashboard service if the type is `NodePort` # nodePort: + # Set the `loadBalancerSourceRanges` of the dashboard service if the type is `LoadBalancer` and + # you want to specify the IP ranges that are allowed to access the dashboard service. + # loadBalancerSourceRanges: [] + # CPU/Memory resource requests/limits for chaos-dashboard pod resources: # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little @@ -201,19 +358,33 @@ dashboard: # subPath: "" - # The keys within the "env" map are mounted as environment variables on the Chaos Dashboard pod. + # The keys within the "env" map are mounted as environment variables on the pod. env: - LISTEN_HOST: "0.0.0.0" + # The address which chaos-dashboard would listen on. + LISTEN_HOST: 0.0.0.0 + # The port which chaos-dashboard would listen on. LISTEN_PORT: 2333 + # The address which metrics endpoints would listen on. + METRIC_HOST: 0.0.0.0 + # The ports which metrics endpoints would listen on. + METRIC_PORT: 2334 # If you'd like to use a DB other than SQLite (the default), set a driver + DSN here. DATABASE_DRIVER: sqlite3 + # **Deprecated**, use `dashboard.databaseSecretName` instead. + # Database DSN used for Chaos Dashboard. DATABASE_DATASOURCE: /data/core.sqlite - # If you are going to store build secrets in the Chaos Dashboard database, it is suggested that - # you set a database encryption secret. This must be set before any secrets are stored - # in the database. - # DATABASE_SECRET: + # Set the sync period to clean up archived data + CLEAN_SYNC_PERIOD: 12h + # Set TTL of archived event data + TTL_EVENT: 168h + # Set TTL of archived experiment data + TTL_EXPERIMENT: 336h + # Set TTL of archived schedule data + TTL_SCHEDULE: 336h + # Set TTL of archived workflow data + TTL_WORKFLOW: 336h ingress: ## Set to true to enable ingress record generation enabled: false @@ -234,7 +405,6 @@ dashboard: ## Most likely this will be just one host, but in the event more hosts are needed, this is an array hosts: - name: dashboard.local - paths: ["/"] ## Set this to true in order to enable TLS on the ingress record tls: false @@ -249,27 +419,45 @@ dashboard: ## If TLS is set to true, you must declare what secret will store the key/certificate for TLS tlsSecret: dashboard.local-tls -dnsServer: - create: false + # Paths that map requests to chaos dashboard + paths: ["/"] - serviceAccount: chaos-dns-server + # Override apiVersion of ingress rendered by this helm chart + apiVersionOverrides: "" - image: pingcap/coredns:v0.2.0 + # Defines which ingress controller will implement the resource + ingressClassName: "" +dnsServer: + # Enable DNS Server which required by DNSChaos + create: true + # Name of serviceaccount for chaos-dns-server. + serviceAccount: chaos-dns-server + # image would be constructed by /: + image: + # override global registry, empty value means using the global images.registry + registry: "" + # repository part for image of chaos-dns-server + repository: chaos-mesh/chaos-coredns + # override global tag, empty value means using the global images.tag + tag: "v0.2.6" + # Image pull policy imagePullPolicy: IfNotPresent - + # Customized priorityClassName for chaos-dns-server priorityClassName: "" - + # Node labels for chaos-dns-server pod assignment nodeSelector: {} - + # Toleration labels for chaos-dns-server pod assignment + tolerations: [] + # Pod annotations of chaos-dns-server podAnnotations: {} - - runtime: docker - + # the service name of chaos-dns-server name: chaos-mesh-dns-server - + # grpc port for chaos-dns-server grpcPort: 9288 - + # Number of replicas + replicas: 1 + # CPU/Memory resource requests/limits for chaos-dns-server pod resources: # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little @@ -281,31 +469,44 @@ dnsServer: requests: cpu: 100m memory: 70Mi - - tolerations: [] - env: + # The address of chaos-dns-server listen on LISTEN_HOST: "0.0.0.0" + # The port of chaos-dns-server listen on LISTEN_PORT: 53 + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/component + operator: In + values: + - chaos-dns-server + topologyKey: kubernetes.io/hostname + weight: 100 prometheus: + # Enable prometheus create: false - + # The serviceAccount for prometheus serviceAccount: prometheus - + # Docker image for prometheus image: prom/prometheus:v2.18.1 + # Image pull policy imagePullPolicy: IfNotPresent - + # Custom priorityClassName for using pod priorities priorityClassName: "" - + # Node labels for prometheus pod assignment nodeSelector: {} - + # Toleration labels for prometheus pod assignment tolerations: [] - + # Map of prometheus node/pod affinities affinity: {} - + # Deployment prometheus annotations podAnnotations: {} - + # CPU/Memory resource requests/limits for prometheus pod resources: # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little @@ -317,23 +518,26 @@ prometheus: requests: cpu: 250m memory: 512Mi - + # Kubernetes Service type service: type: ClusterIP volume: + # storage size of PVC storage: 2Gi + # storage class of PVC storageClassName: standard webhook: + certManager: + # Setup the webhook using cert-manager + enabled: false # if empty and disable certManager, Helm will auto-generate these fields - crtPEM: | + caBundlePEM: "" - keyPEM: | + crtPEM: "" - # Setup the webhook using cert-manager - certManager: - enabled: false + keyPEM: "" # It is recommended that admission webhooks should evaluate as quickly as possible (typically in milliseconds), # since they add to API request latency. It is encouraged to use a small timeout for webhooks. @@ -341,7 +545,7 @@ webhook: timeoutSeconds: 5 # FailurePolicy defines how unrecognized errors and timeout errors from the admission webhook are handled. # https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#failure-policy - FailurePolicy: Ignore + FailurePolicy: Fail CRDS: - podchaos @@ -351,18 +555,36 @@ webhook: - kernelchaos - stresschaos - awschaos + - azurechaos - gcpchaos - - podiochaos - - podnetworkchaos - dnschaos - jvmchaos + - schedule + - workflow + - httpchaos + - blockchaos + - physicalmachinechaos + - physicalmachine + - statuscheck + - remotecluster bpfki: + # Enable chaos-kernel create: false - image: pingcap/chaos-kernel:latest + # image would be constructed by /: + image: + # empty registry means using the global images.registry + registry: "" + repository: chaos-mesh/chaos-kernel + # empty tag means using the global images.tag + tag: "" + # Image pull policy imagePullPolicy: IfNotPresent + # The port which grpc server listens on grpcPort: 50051 - resources: {} + # CPU/Memory resource requests/limits for chaos-kernel container + resources: + {} # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little # resources, such as Minikube. If you do want to specify resources, uncomment the following @@ -373,3 +595,14 @@ bpfki: # requests: # cpu: 250m # memory: 512Mi + +chaosDlv: + enable: false + # image would be constructed by /: + image: + # empty registry means using the global images.registry + registry: "" + repository: chaos-mesh/chaos-dlv + # empty tag means using the global images.tag + tag: "" + imagePullPolicy: IfNotPresent diff --git a/images/build-env/Dockerfile b/images/build-env/Dockerfile index 14a4630321..addc6f58dd 100644 --- a/images/build-env/Dockerfile +++ b/images/build-env/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM debian:buster-slim +FROM debian:bullseye-slim ENV DEBIAN_FRONTEND noninteractive @@ -10,19 +10,20 @@ ARG HTTP_PROXY ENV http_proxy $HTTP_PROXY ENV https_proxy $HTTPS_PROXY -RUN apt-get update && apt-get install build-essential curl git pkg-config libfuse-dev fuse -y +RUN apt update && \ + apt install build-essential curl git pkg-config libfuse-dev fuse -y && \ + rm -rf /var/lib/apt/lists/* -# require nodejs >= 12 -RUN curl -fsSL https://deb.nodesource.com/setup_14.x | bash - -RUN apt-get install -y nodejs -RUN npm config set unsafe-perm true -RUN npm install yarn -g - -RUN if [[ -n "$HTTP_PROXY" ]]; then yarn config set proxy $HTTP_PROXY; fi +RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \ + apt install -y nodejs && \ + rm -rf /var/lib/apt/lists/* +RUN npm install pnpm@9 -g ARG TARGET_PLATFORM=amd64 -RUN curl https://dl.google.com/go/go1.15.11.linux-$TARGET_PLATFORM.tar.gz | tar -xz -C /usr/local + +RUN curl -vvv https://dl.google.com/go/go1.20.8.linux-$TARGET_PLATFORM.tar.gz | tar -xz -C /usr/local ENV PATH "/usr/local/go/bin:${PATH}" -ENV GO111MODULE=on ENV GOCACHE /tmp/go-build ENV GOPATH /tmp/go + +LABEL org.opencontainers.image.source https://github.com/chaos-mesh/chaos-mesh diff --git a/images/chaos-daemon/Dockerfile b/images/chaos-daemon/Dockerfile index b34ba1bba5..975505f8a8 100644 --- a/images/chaos-daemon/Dockerfile +++ b/images/chaos-daemon/Dockerfile @@ -1,4 +1,6 @@ -FROM debian:buster-slim +FROM curlimages/curl:7.88.1 as binaryimage + +USER root ARG HTTPS_PROXY ARG HTTP_PROXY @@ -6,20 +8,62 @@ ARG HTTP_PROXY ENV http_proxy $HTTP_PROXY ENV https_proxy $HTTPS_PROXY -RUN apt-get update && apt-get install -y tzdata iptables ipset stress-ng iproute2 fuse util-linux procps curl && rm -rf /var/lib/apt/lists/* +ARG TARGET_PLATFORM=amd64 + +RUN mkdir -p /tmp/bin && \ + curl -L https://mirrors.chaos-mesh.org/byteman-chaos-mesh-download-v4.0.22-0.12.tar.gz -o /usr/local/byteman.tar.gz && \ + tar xvf /usr/local/byteman.tar.gz -C /usr/local && \ + mv /usr/local/byteman-chaos-mesh-download-v4.0.22-0.12 /tmp/byteman && \ + rm /usr/local/byteman.tar.gz + +# toda doesn't support arm64 yet +RUN curl -L https://github.com/chaos-mesh/toda/releases/download/v0.2.4/toda-linux-amd64.tar.gz | tar xz -C /tmp/bin +RUN case "$TARGET_PLATFORM" in \ + 'amd64') \ + export NSEXEC_ARCH='x86_64'; \ + ;; \ + 'arm64') \ + export NSEXEC_ARCH='aarch64'; \ + ;; \ + *) echo >&2 "error: unsupported architecture '$TARGET_PLATFORM'"; exit 1 ;; \ + esac; \ + curl -L https://github.com/chaos-mesh/nsexec/releases/download/v0.1.6/nsexec-$NSEXEC_ARCH-unknown-linux-gnu.tar.gz | tar xz -C /tmp/bin; \ + curl -L https://github.com/chaos-mesh/chaos-tproxy/releases/download/v0.5.3/tproxy-$NSEXEC_ARCH.tar.gz | tar xz -C /tmp/bin; \ + curl -L https://github.com/chaos-mesh/memStress/releases/download/v0.3/memStress_v0.3-$NSEXEC_ARCH-linux-gnu.tar.gz | tar xz -C /tmp/bin -RUN update-alternatives --set iptables /usr/sbin/iptables-legacy -ENV RUST_BACKTRACE 1 -RUN curl -L https://github.com/chaos-mesh/toda/releases/download/v0.2.0/toda-linux-amd64.tar.gz -o /usr/local/bin/toda.tar.gz -RUN curl -L https://github.com/chaos-mesh/nsexec/releases/download/v0.1.5/nsexec-linux-amd64.tar.gz -o /usr/local/bin/nsexec.tar.gz -RUN tar xvf /usr/local/bin/toda.tar.gz -C /usr/local/bin -RUN rm /usr/local/bin/toda.tar.gz -RUN tar xvf /usr/local/bin/nsexec.tar.gz -C /usr/local/bin -RUN rm /usr/local/bin/nsexec.tar.gz -RUN cp /usr/local/bin/libnsenter.so /usr/local/lib/libnsenter.so +# --- +FROM debian:bullseye-slim + +ARG HTTPS_PROXY +ARG HTTP_PROXY + +ENV http_proxy $HTTP_PROXY +ENV https_proxy $HTTPS_PROXY + +RUN mkdir -p /usr/share/man/man1 /usr/share/man/man2 + +RUN apt-get update && \ + echo "deb http://security.debian.org/debian-security bullseye-security main contrib non-free" >> /etc/apt/sources.list && \ + echo "deb http://deb.debian.org/debian bullseye-proposed-updates main contrib non-free" >> /etc/apt/sources.list && \ + apt --allow-releaseinfo-change update && apt upgrade -y && \ + apt-get install -y tzdata iptables ebtables net-tools ipset stress-ng iproute2 fuse util-linux procps openjdk-11-jre && \ + rm -rf /var/lib/apt/lists/* + +RUN update-alternatives --set iptables /usr/sbin/iptables-legacy && \ + update-alternatives --set ebtables /usr/sbin/ebtables-legacy + +ENV RUST_BACKTRACE 1 +ENV BYTEMAN_HOME /usr/local/byteman +ENV PATH $PATH:/usr/local/byteman/bin +ENV JAVA_HOME /usr/lib/jvm/java-11-openjdk-amd64 +ENV PATH $PATH:/usr/local/bin COPY bin/chaos-daemon /usr/local/bin/chaos-daemon COPY bin/pause /usr/local/bin/pause +COPY bin/cdh /usr/local/bin/cdh +COPY --from=binaryimage /tmp/byteman /usr/local/byteman +COPY --from=binaryimage /tmp/bin/* /usr/local/bin/ +RUN mv /usr/local/bin/libnsenter.so /usr/local/lib/libnsenter.so diff --git a/images/chaos-dashboard/Dockerfile b/images/chaos-dashboard/Dockerfile index e2165ae224..8731559888 100644 --- a/images/chaos-dashboard/Dockerfile +++ b/images/chaos-dashboard/Dockerfile @@ -1,4 +1,4 @@ -FROM debian:buster-slim +FROM debian:bullseye-slim ARG HTTPS_PROXY ARG HTTP_PROXY @@ -9,7 +9,12 @@ ENV https_proxy $HTTPS_PROXY ARG UI ARG SWAGGER -RUN apt-get update && apt-get install tzdata -y && rm -rf /var/lib/apt/lists/* +RUN apt-get update && \ + echo "deb http://security.debian.org/debian-security bullseye-security main contrib non-free" >> /etc/apt/sources.list && \ + echo "deb http://deb.debian.org/debian bullseye-proposed-updates main contrib non-free" >> /etc/apt/sources.list && \ + apt --allow-releaseinfo-change update && apt upgrade -y && \ + apt-get install tzdata ca-certificates -y && \ + rm -rf /var/lib/apt/lists/* ENV http_proxy= ENV https_proxy= diff --git a/images/chaos-dlv/Dockerfile b/images/chaos-dlv/Dockerfile new file mode 100644 index 0000000000..7925962450 --- /dev/null +++ b/images/chaos-dlv/Dockerfile @@ -0,0 +1,13 @@ +# syntax=docker/dockerfile:experimental + +FROM golang:1.20 AS build-env +RUN go install github.com/go-delve/delve/cmd/dlv@v1.21.0 + +FROM debian:buster + +RUN apt-get update && \ + apt-get install procps -y && \ + rm -rf /var/lib/apt/lists/* + +COPY --from=build-env /go/bin/dlv / +CMD ["bash", "-c", "/dlv attach $(ps axf | grep $CMD_NAME | grep -v grep | awk '{print $1}') --listen=:8000 --headless=true --api-version=2 --accept-multiclient --continue"] diff --git a/images/chaos-dlv/README.md b/images/chaos-dlv/README.md new file mode 100644 index 0000000000..bb89a717b8 --- /dev/null +++ b/images/chaos-dlv/README.md @@ -0,0 +1,81 @@ +This image will be used to run `dlv` inside the chaos mesh pods. If Chaos Mesh +is configured properly, you can use it to debug the process on remote machine. + +## Deploy + +To deploy the `dlv` image, you need to compile the chaos-mesh with symbols: + +```bash +make DEBUGGER=1 image +``` + +Then you need to install with the corresponding helm configuration to integrate +this container with the chaos mesh: + +```bash +helm install chaos-mesh ./helm/chaos-mesh -n chaos-mesh --set chaosDlv.enable=true +``` + +After deploying the image, you can find the `chaos-mesh-dlv` container under +every pods of chaos mesh. The command: + +```bash +kubectl get pods -n chaos-mesh -o jsonpath="{.items[*].spec.containers[*].name}" +``` + +Will print: + +```bash +chaos-mesh chaos-mesh-dlv chaos-daemon chaos-mesh-dlv +``` + +## Usage + +### CLI + +After deploying the chaos mesh with `dlv` support, you can use the `kubectl` +command to forward the remote port, and use a `dlv` command to connect to it. +For example: + +```bash +kubectl port-forward -n chaos-mesh svc/chaos-mesh-controller-manager 2345:8000 +dlv connect localhost:2345 +``` + +Then you have entered the `dlv` debug environment and can debug the process. + +### VSCode + +A more fashion way would be configuring the Visual Studio Code tasks to attach +to specific pod automatically. + +Firstly, use `kubectl port-forward` to export the port on local machine: + +```bash +kubectl port-forward -n chaos-mesh svc/chaos-mesh-controller-manager 2345:8000 +``` + +Then add a vscode attach configuration and save it in `.vscode/launch.json`: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Attach chaos-mesh", + "type": "go", + "request": "attach", + "mode": "remote", + "port": 2345, + "host": "127.0.0.1", + "apiVersion": 2, + "showLog": true, + "remotePath": "/mnt", + "trace": "verbose" + }, + ] +} +``` + +Click `Start Debugging` in "RUN AND DEBUG" section, and you will be able to +pause the process and see the backtrace, variables and set breakpoints. diff --git a/images/chaos-jvm/Dockerfile b/images/chaos-jvm/Dockerfile deleted file mode 100644 index 162298b861..0000000000 --- a/images/chaos-jvm/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM maven:3.6.3-jdk-8 AS jvmchaos_build - -ARG HTTPS_PROXY -ARG HTTP_PROXY - -ENV http_proxy $HTTP_PROXY -ENV https_proxy $HTTPS_PROXY - -RUN apt-get update && apt-get install -y make && rm -rf /var/lib/apt/lists/* - -RUN mkdir -p /opt/sandbox - -WORKDIR /opt/sandbox - -RUN curl -fsSL -o /opt/sandbox/jvmchaos.zip https://github.com/chaosblade-io/chaosblade-exec-jvm/archive/v0.9.0.zip && unzip jvmchaos.zip - -WORKDIR /opt/sandbox/chaosblade-exec-jvm-0.9.0 - -RUN make - -FROM alpine:3.12 - -WORKDIR /bin - -COPY --from=jvmchaos_build /opt/sandbox/chaosblade-exec-jvm-0.9.0/build-target/chaosblade-0.9.0/lib/ /bin diff --git a/images/chaos-kernel/Dockerfile b/images/chaos-kernel/Dockerfile index 9c72af1d38..ae44e5e87b 100644 --- a/images/chaos-kernel/Dockerfile +++ b/images/chaos-kernel/Dockerfile @@ -2,7 +2,7 @@ FROM ubuntu:bionic ARG HTTPS_PROXY ARG HTTP_PROXY -ARG MAKE_JOBS +ARG MAKE_JOBS=4 ARG MIRROR=http://archive.ubuntu.com/ubuntu RUN apt-get update && apt-get install -y ca-certificates gnupg2 wget @@ -14,9 +14,10 @@ RUN echo "deb https://apt.kitware.com/ubuntu/ bionic main" >> /etc/apt/sources.l RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | apt-key add - -RUN apt-get update && apt-get install -y gcc-8 g++-8 bison build-essential \ +RUN ulimit -n 1024 && apt-get update && apt-get install -y gcc-8 g++-8 bison build-essential \ flex git libedit-dev libllvm6.0 llvm-6.0-dev libclang-6.0-dev python python-pip \ - zlib1g-dev libelf-dev libssl-dev && pip install cmake==3.13.3 + zlib1g-dev libelf-dev libssl-dev +RUN apt install -y cmake RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 70 RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 70 @@ -25,7 +26,7 @@ RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 80 RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 80 RUN update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-8 80 -RUN git clone https://github.com/iovisor/bcc.git +RUN git clone --depth 1 --branch v0.23.0 https://github.com/iovisor/bcc.git WORKDIR /bcc/build RUN cmake .. -DCMAKE_INSTALL_PREFIX=/usr && make -j${MAKE_JOBS} && make install @@ -33,6 +34,6 @@ WORKDIR / RUN git clone https://github.com/chaos-mesh/bpfki WORKDIR /bpfki/build -RUN cmake .. && make -j && mv bin/bpfki /usr/local/bin/ && mv examples/fail* /usr/local/bin/ +RUN cmake .. && make -j${MAKE_JOBS} && mv bin/bpfki /usr/local/bin/ && mv examples/fail* /usr/local/bin/ WORKDIR /usr/local/bin diff --git a/images/chaos-mesh/Dockerfile b/images/chaos-mesh/Dockerfile index 2eb4ad6434..d5f64af4ee 100644 --- a/images/chaos-mesh/Dockerfile +++ b/images/chaos-mesh/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.12 +FROM alpine:3.17 ARG HTTPS_PROXY ARG HTTP_PROXY diff --git a/images/dev-env/Dockerfile b/images/dev-env/Dockerfile new file mode 100644 index 0000000000..95843cb547 --- /dev/null +++ b/images/dev-env/Dockerfile @@ -0,0 +1,86 @@ +# syntax=docker/dockerfile:experimental + +FROM golang:1.20 AS go_install + +ENV GOPATH /go +ENV CGO_ENABLED 0 + +RUN go install golang.org/x/tools/cmd/goimports@v0.13.0 +RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.13.0 +RUN go install github.com/mgechev/revive@v1.2.4 +RUN go install github.com/pingcap/failpoint/failpoint-ctl@v0.0.0-20200210140405-f8f9fb234798 +RUN go install github.com/securego/gosec/cmd/gosec@v0.0.0-20200401082031-e946c8c39989 +RUN go install github.com/99designs/gqlgen@v0.17.2 +RUN go install github.com/golang/protobuf/protoc-gen-go@v1.4.2 +RUN go install github.com/axw/gocov/gocov@v1.1.0 +RUN go install github.com/AlekSi/gocov-xml@v1.1.0 +RUN go install github.com/matm/gocov-html@v0.0.0-20200509184451-71874e2e203b +RUN go install github.com/swaggo/swag/cmd/swag@v1.8.7 +RUN go install github.com/onsi/ginkgo/v2/ginkgo@v2.12.0 +RUN go install github.com/apache/skywalking-eyes/cmd/license-eye@v0.2.0 + +FROM debian:bookworm-slim + +ENV DEBIAN_FRONTEND noninteractive + +ARG HTTPS_PROXY +ARG HTTP_PROXY + +ENV http_proxy $HTTP_PROXY +ENV https_proxy $HTTPS_PROXY + +RUN apt update && \ + apt install unzip git build-essential curl musl musl-dev -y && \ + rm -rf /var/lib/apt/lists/* + +# The `TARGET_PLATFORM` would be `amd64` or `arm64` +ARG TARGET_PLATFORM=amd64 + +# The architecture part of the url is `aarch_64` or `x86_64` +RUN case "$TARGET_PLATFORM" in \ + 'amd64') \ + export PROTOC_ARCH='x86_64'; \ + ;; \ + 'arm64') \ + export PROTOC_ARCH='aarch_64'; \ + ;; \ + *) echo >&2 "error: unsupported architecture '$TARGET_PLATFORM'"; exit 1 ;; \ + esac; \ + curl -L https://github.com/protocolbuffers/protobuf/releases/download/v3.12.2/protoc-3.12.2-linux-$PROTOC_ARCH.zip > /protoc.zip && \ + unzip /protoc.zip -d /usr/local && \ + rm /protoc.zip +RUN chmod +rx -R /usr/local/include +RUN chmod +x /usr/local/bin/protoc + +RUN mkdir -p /go/bin + +COPY --from=go_install /usr/local/go /usr/local/go +COPY --from=go_install /go/bin /go/bin + +# The `gqlgen` depends on the plugin in it +COPY --from=go_install /go/pkg/mod/github.com/99designs/gqlgen@v0.17.2 /go/pkg/mod/github.com/99designs/gqlgen@v0.17.2 + +ENV PATH "/usr/local/go/bin:${PATH}:/tmp/go/bin:/go/bin" + +RUN curl -L https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v4.3.0/kustomize_v4.3.0_$(go env GOOS)_$(go env GOARCH).tar.gz | tar -xz -C /usr/local/bin/ + +RUN curl -L https://storage.googleapis.com/kubebuilder-tools/kubebuilder-tools-1.19.2-$(go env GOOS)-$(go env GOARCH).tar.gz | tar -xz -C /usr/local/ + +RUN curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 && \ + chmod 700 get_helm.sh && \ + ./get_helm.sh && \ + rm get_helm.sh + +# Create and grant permissions to plugins directory. +RUN mkdir -p /opt/helm/plugins && chmod a+rwx /opt/helm +ENV HELM_PLUGINS=/opt/helm/plugins +RUN helm plugin install https://github.com/losisin/helm-values-schema-json.git + +RUN mkdir /.cache +RUN chmod -R 777 /.cache + +ENV GOCACHE /tmp/go-build +ENV GOPATH /tmp/go +ENV CGO_ENABLED 0 + +LABEL org.opencontainers.image.source https://github.com/chaos-mesh/chaos-mesh diff --git a/install.sh b/install.sh index 34c35a3d70..1f1f3d44b7 100755 --- a/install.sh +++ b/install.sh @@ -1,23 +1,26 @@ #!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. +# Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# # This is a script to quickly install chaos-mesh. # This script will check if docker and kubernetes are installed. If local mode is set and kubernetes is not installed, # it will use kind or minikube to install the kubernetes cluster according to the configuration. # Finally, when all dependencies are installed, chaos-mesh will be installed. +VERSION=${VERSION:-latest} + usage() { cat << EOF This script is used to install chaos-mesh. @@ -34,7 +37,6 @@ FLAGS: --force-local-kube Force reinstall local Kubernetes cluster if it is already installed --force-kubectl Force reinstall kubectl client if it is already installed --force-kind Force reinstall Kind if it is already installed - --docker-mirror Use docker mirror to pull image, dockerhub.azk8s.cn => docker.io, gcr.azk8s.cn => gcr.io --volume-provisioner Deploy volume provisioner in local Kubernetes cluster --local-registry Deploy local docker registry in local Kubernetes cluster --template Locally render templates @@ -42,38 +44,37 @@ FLAGS: --microk8s Install chaos-mesh in microk8s environment --host-network Install chaos-mesh using hostNetwork OPTIONS: - -v, --version Version of chaos-mesh, default value: latest + -v, --version Version of chaos-mesh, default value: ${VERSION} -l, --local [kind] Choose a way to run a local kubernetes cluster, supported value: kind, If this value is not set and the Kubernetes is not installed, this script will exit with 1. -n, --name Name of Kubernetes cluster, default value: kind -c --crd The path of the crd files. Get the crd file from "https://mirrors.chaos-mesh.org" if the crd path is empty. -r --runtime Runtime specifies which container runtime to use. Currently we only supports docker and containerd. default value: docker - --kind-version Version of the Kind tool, default value: v0.7.0 + --kind-version Version of the Kind tool, default value: v0.11.1 --node-num The count of the cluster nodes,default value: 3 --k8s-version Version of the Kubernetes cluster,default value: v1.17.2 --volume-num The volumes number of each kubernetes node,default value: 5 --release-name Release name of chaos-mesh, default value: chaos-mesh - --namespace Namespace of chaos-mesh, default value: chaos-testing - --timezone Specifies timezone to be used by chaos-dashboard, chaos-daemon and controlller. + --namespace Namespace of chaos-mesh, default value: chaos-mesh + --timezone Specifies timezone to be used by chaos-dashboard, chaos-daemon and controller. EOF } main() { local local_kube="" - local cm_version="latest" + local cm_version="${VERSION}" local kind_name="kind" - local kind_version="v0.7.0" + local kind_version="v0.11.1" local node_num=3 local k8s_version="v1.17.2" local volume_num=5 local release_name="chaos-mesh" - local namespace="chaos-testing" + local namespace="chaos-mesh" local timezone="UTC" local force_chaos_mesh=false local force_local_kube=false local force_kubectl=false local force_kind=false - local docker_mirror=false local volume_provisioner=false local local_registry=false local crd="" @@ -83,7 +84,7 @@ main() { local k3s=false local microk8s=false local host_network=false - local docker_registry="docker.io" + local docker_registry="ghcr.io" while [[ $# -gt 0 ]] do @@ -149,10 +150,6 @@ main() { template=true shift ;; - --docker-mirror) - docker_mirror=true - shift - ;; --volume-provisioner) volume_provisioner=true shift @@ -222,7 +219,7 @@ main() { done if [ "${runtime}" != "docker" ] && [ "${runtime}" != "containerd" ]; then - printf "container runtime %s is not supported\n" "${local_kube}" + printf "container runtime %s is not supported\n" "${runtime}" exit 1 fi @@ -261,7 +258,7 @@ main() { check_docker install_kind "${kind_version}" ${force_kind} - install_kubernetes_by_kind "${kind_name}" "${k8s_version}" "${node_num}" "${volume_num}" ${force_local_kube} ${docker_mirror} ${volume_provisioner} ${local_registry} + install_kubernetes_by_kind "${kind_name}" "${k8s_version}" "${node_num}" "${volume_num}" ${force_local_kube} ${volume_provisioner} ${local_registry} fi if [ "${install_dependency_only}" = true ]; then @@ -269,7 +266,7 @@ main() { fi check_kubernetes - install_chaos_mesh "${release_name}" "${namespace}" "${local_kube}" ${force_chaos_mesh} ${docker_mirror} "${crd}" "${runtime}" "${k3s}" "${cm_version}" "${timezone}" "${docker_registry}" "${microk8s}" + install_chaos_mesh "${release_name}" "${namespace}" "${local_kube}" ${force_chaos_mesh} "${crd}" "${runtime}" "${k3s}" "${cm_version}" "${timezone}" "${docker_registry}" "${microk8s}" ensure_pods_ready "${namespace}" "app.kubernetes.io/component=controller-manager" 100 ensure_pods_ready "${namespace}" "app.kubernetes.io/component=chaos-daemon" 100 ensure_pods_ready "${namespace}" "app.kubernetes.io/component=chaos-dashboard" 100 @@ -289,7 +286,7 @@ prepare_env() { check_kubernetes() { need_cmd "kubectl" - kubectl_err_msg=$(kubectl version 2>&1 1>/dev/null) + kubectl_err_msg=$(kubectl version --output=yaml 2>&1 1>/dev/null) if [ "$kubectl_err_msg" != "" ]; then printf "check Kubernetes failed, error: %s\n" "${kubectl_err_msg}" exit 1 @@ -299,7 +296,7 @@ check_kubernetes() { } check_kubernetes_version() { - version_info=$(kubectl version | sed 's/.*GitVersion:\"v\([0-9.]*\).*/\1/g') + version_info=$(kubectl version --output=yaml | grep gitVersion | sed 's/.*gitVersion: v\([0-9.]*\).*/\1/g') for v in $version_info do @@ -316,9 +313,9 @@ install_kubectl() { printf "Install kubectl client\n" - err_msg=$(kubectl version --client=true 2>&1 1>/dev/null) + err_msg=$(kubectl version --client=true --output=yaml 2>&1 1>/dev/null) if [ "$err_msg" == "" ]; then - v=$(kubectl version --client=true | sed 's/.*GitVersion:\"v\([0-9.]*\).*/\1/g') + v=$(kubectl version --client=true --output=yaml | grep gitVersion | sed 's/.*gitVersion: v\([0-9.]*\).*/\1/g') target_version=$(echo "${kubectl_version}" | sed s/v//g) if version_lt "$v" "${target_version}"; then printf "Chaos Mesg requires kubectl version %s or later\n" "${target_version}" @@ -346,9 +343,8 @@ install_kubernetes_by_kind() { local node_num=$3 local volume_num=$4 local force_install=$5 - local docker_mirror=$6 - local volume_provisioner=$7 - local local_registry=$8 + local volume_provisioner=$6 + local local_registry=$7 printf "Install local Kubernetes %s\n" "${cluster_name}" @@ -393,10 +389,9 @@ install_kubernetes_by_kind() { config_file=${work_dir}/kind-config.yaml cat < "${config_file}" kind: Cluster -apiVersion: kind.sigs.k8s.io/v1alpha3 +apiVersion: kind.x-k8s.io/v1alpha4 kubeadmConfigPatches: - | - apiVersion: kubeadm.k8s.io/v1alpha3 kind: ClusterConfiguration metadata: name: config @@ -429,9 +424,6 @@ EOF done local kind_image="kindest/node:${cluster_version}" - if [ "$docker_mirror" == "true" ]; then - azk8spull "${kind_image}" || true - fi printf "start to create kubernetes cluster %s" "${cluster_name}" ensure kind create cluster --config "${config_file}" --image="${kind_image}" --name="${cluster_name}" --retain -v 1 @@ -439,20 +431,15 @@ EOF ensure export KUBECONFIG="${kubeconfig_path}" if [ "$volume_provisioner" == "true" ]; then - deploy_volume_provisioner "${work_dir}" ${docker_mirror} + deploy_volume_provisioner "${work_dir}" fi } deploy_volume_provisioner() { local data_dir=$1 - local docker_mirror=$2 local config_file=${data_dir}/local-volume-provisionser.yaml volume_provisioner_image="quay.io/external_storage/local-volume-provisioner:v2.3.2" - if [ "$docker_mirror" == "true" ]; then - azk8spull volume_provisioner_image || true - kind load docker-image ${volume_provisioner_image} > /dev/null 2>&1 || true - fi cat <"${config_file}" apiVersion: storage.k8s.io/v1 @@ -592,7 +579,7 @@ install_kind() { err_msg=$(kind version 2>&1 1>/dev/null) if [ "$err_msg" == "" ]; then v=$(kind version | awk '{print $2}' | sed s/v//g) - target_version=$(echo "${kind_version}" | sed s/v//g) + target_version=${kind_version//v} if version_lt "$v" "${target_version}"; then printf "Chaos Mesh requires Kind version %s or later\n" "${target_version}" else @@ -615,32 +602,17 @@ install_chaos_mesh() { local namespace=$2 local local_kube=$3 local force_install=$4 - local docker_mirror=$5 - local crd=$6 - local runtime=$7 - local k3s=$8 - local version=$9 - local timezone=${10} - local docker_registry=${11} - local microk8s=${12} - printf "Install Chaos Mesh %s\n" "${release_name}" + local crd=$5 + local runtime=$6 + local k3s=$7 + local version=$8 + local timezone=$9 + local docker_registry=${10} + local microk8s=${11} - local chaos_mesh_image="${docker_registry}/pingcap/chaos-mesh:${version}" - local chaos_daemon_image="${docker_registry}/pingcap/chaos-daemon:${version}" - local chaos_dashboard_image="${docker_registry}/pingcap/chaos-dashboard:${version}" - - if [ "$docker_mirror" == "true" ]; then - azk8spull "${chaos_mesh_image}" || true - azk8spull "${chaos_daemon_image}" || true - azk8spull "${chaos_dashboard_image}" || true - if [ "${local_kube}" == "kind" ]; then - kind load docker-image "${chaos_mesh_image}" > /dev/null 2>&1 || true - kind load docker-image "${chaos_daemon_image}" > /dev/null 2>&1 || true - kind load docker-image "${chaos_dashboard_image}" > /dev/null 2>&1 || true - fi - fi + printf "Install Chaos Mesh %s\n" "${release_name}" - gen_crd_manifests "${crd}" | kubectl apply --validate=false -f - || exit 1 + gen_crd_manifests "${crd}" | kubectl create --validate=false -f - || exit 1 gen_chaos_mesh_manifests "${runtime}" "${k3s}" "${version}" "${timezone}" "${host_network}" "${docker_registry}" "${microk8s}" | kubectl apply -f - || exit 1 } @@ -659,7 +631,9 @@ vercomp () { return 0 fi local IFS=. - local i ver1=($1) ver2=($2) + local i ver1 ver2 + read -ra ver1 <<< "$1" + read -ra ver2 <<< "$2" # fill empty fields in ver1 with zeros for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)) do @@ -748,60 +722,6 @@ ensure_pods_ready() { done } -azk8spull() { - image=$1 - if [ -z $image ]; then - echo "## azk8spull image name cannot be null." - else - array=(`echo $image | tr '/' ' '` ) - - domainName="" - repoName="" - imageName="" - - if [ ${#array[*]} -eq 3 ]; then - repoName=${array[1]} - imageName=${array[2]} - if [ "${array[0]}"x = "docker.io"x ]; then - domainName="dockerhub.azk8s.cn" - elif [ "${array[0]}"x = "gcr.io"x ]; then - domainName="gcr.azk8s.cn" - elif [ "${array[0]}"x = "quay.io"x ]; then - domainName="quay.azk8s.cn" - else - echo '## azk8spull can not support pulling $image right now.' - fi - elif [ ${#array[*]} -eq 2 ]; then - if [ "${array[0]}"x = "k8s.gcr.io"x ]; then - domainName="gcr.azk8s.cn" - repoName="google_containers" - imageName=${array[1]} - else - domainName="dockerhub.azk8s.cn" - repoName=${array[0]} - imageName=${array[1]} - fi - elif [ ${#array[*]} -eq 1 ]; then - domainName="dockerhub.azk8s.cn" - repoName="library" - imageName=${array[0]} - else - echo '## azk8spull can not support pulling $image right now.' - fi - if [ $domainName != "" ]; then - echo "## azk8spull try to pull image from mirror $domainName/$repoName/$imageName." - docker pull $domainName/$repoName/$imageName - if [ $? -eq 0 ]; then - echo "## azk8spull try to tag $domainName/$repoName/$imageName to $image." - docker tag $domainName/$repoName/$imageName $image - if [ $? -eq 0 ]; then - echo '## azk8spull finish pulling. ' - fi - fi - fi - fi -} - gen_crd_manifests() { local crd=$1 @@ -832,21 +752,21 @@ gen_chaos_mesh_manifests() { local host_network=$5 local docker_registry=$6 local microk8s=$7 - local socketPath="/var/run/docker.sock" - local mountPath="/var/run/docker.sock" + local socketDir="/var/run" + local socketName="docker.sock" if [ "${runtime}" == "containerd" ]; then - socketPath="/run/containerd/containerd.sock" - mountPath="/run/containerd/containerd.sock" + socketDir="/run/containerd" + socketName="containerd.sock" fi if [ "${k3s}" == "true" ]; then - socketPath="/run/k3s/containerd/containerd.sock" - mountPath="/run/containerd/containerd.sock" + socketDir="/run/k3s/containerd" + socketName="containerd.sock" fi if [ "${microk8s}" == "true" ]; then - socketPath="/var/snap/microk8s/common/run/containerd.sock" - mountPath="/run/containerd/containerd.sock" + socketDir="/var/snap/microk8s/common/run" + socketName="containerd.sock" fi need_cmd mktemp @@ -854,10 +774,10 @@ gen_chaos_mesh_manifests() { need_cmd curl K8S_SERVICE="chaos-mesh-controller-manager" - K8S_NAMESPACE="chaos-testing" + K8S_NAMESPACE="chaos-mesh" VERSION_TAG="${version}" - DOCKER_REGISTRY_PREFIX="${docker_registry}" + IMAGE_REGISTRY_PREFIX="${docker_registry}" tmpdir=$(mktemp -d) ensure openssl genrsa -out ${tmpdir}/ca.key 2048 > /dev/null 2>&1 @@ -895,39 +815,128 @@ EOF apiVersion: v1 kind: Namespace metadata: - name: chaos-testing + name: chaos-mesh --- # Source: chaos-mesh/templates/chaos-daemon-rbac.yaml kind: ServiceAccount apiVersion: v1 metadata: - namespace: "chaos-testing" + namespace: "chaos-mesh" name: chaos-daemon labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: chaos-daemon --- +# Source: chaos-mesh/templates/chaos-dashboard-rbac.yaml +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ServiceAccount for component chaos-dashboard +kind: ServiceAccount +apiVersion: v1 +metadata: + namespace: "chaos-mesh" + name: chaos-dashboard + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: chaos-dashboard +--- # Source: chaos-mesh/templates/controller-manager-rbac.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# kind: ServiceAccount apiVersion: v1 metadata: - namespace: "chaos-testing" + namespace: "chaos-mesh" name: chaos-controller-manager labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: controller-manager --- +# Source: chaos-mesh/templates/dns-rbac.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +kind: ServiceAccount +apiVersion: v1 +metadata: + namespace: "chaos-mesh" + name: chaos-dns-server + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: dns-server +--- # Source: chaos-mesh/templates/secrets-configuration.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# kind: Secret apiVersion: v1 metadata: name: chaos-mesh-webhook-certs - namespace: "chaos-testing" + namespace: "chaos-mesh" labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: webhook-secret type: Opaque data: @@ -935,6 +944,121 @@ data: tls.crt: "${TLS_CRT}" tls.key: "${TLS_KEY}" --- +# Source: chaos-mesh/templates/dns-configmap.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: v1 +kind: ConfigMap +metadata: + name: dns-server-config + namespace: "chaos-mesh" + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: chaos-dns-server +data: + Corefile: | + .:5353 { + errors + health { + lameduck 5s + } + ready + k8s_dns_chaos cluster.local in-addr.arpa ip6.arpa { + pods insecure + fallthrough in-addr.arpa ip6.arpa + ttl 30 + grpcport 9288 + } + prometheus :9153 + forward . /etc/resolv.conf { + max_concurrent 1000 + } + cache 30 + loop + reload + loadbalance + } +--- +# Source: chaos-mesh/templates/chaos-dashboard-rbac.yaml +# ClusterRole for chaos-dashboard at cluster scope +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: chaos-mesh-chaos-dashboard-cluster-level + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: chaos-dashboard +rules: + # chaos-dashboard could list namespace for selector hints + - apiGroups: [ "" ] + resources: + - namespaces + verbs: + - get + - list + - watch + # chaos-dashboard use subjectaccessreviews to authorize the requests + - apiGroups: [ "authorization.k8s.io" ] + resources: + - subjectaccessreviews + verbs: + - create +--- +# Source: chaos-mesh/templates/chaos-dashboard-rbac.yaml +# ClusterRole for chaos-dashboard in target namespace +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: chaos-mesh-chaos-dashboard-target-namespace + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: chaos-dashboard +rules: + # chaos dashboard could list pods for selector hints + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - watch + # chaos dashboard could record evnets from chaos experiments + - apiGroups: + - "" + resources: + - events + verbs: + - get + - list + - watch + # chaos dashboard could record and manipulate all the Chaos Mesh resources in target namespace + - apiGroups: [ "chaos-mesh.org" ] + resources: + - "*" + verbs: [ "*" ] +--- # Source: chaos-mesh/templates/controller-manager-rbac.yaml # roles kind: ClusterRole @@ -944,14 +1068,25 @@ metadata: labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: controller-manager rules: - apiGroups: [ "" ] - resources: [ "endpoints" ] - verbs: [ "get", "list", "watch" ] - - apiGroups: [ "" ] - resources: [ "pods", "secrets" ] - verbs: [ "get", "list", "watch", "delete", "update" ] + resources: [ "pods", "configmaps", "secrets"] + verbs: [ "get", "list", "watch", "delete", "update", "patch" ] + - apiGroups: + - "" + resources: + - pods + verbs: + - "create" + - apiGroups: + - "" + resources: + - "pods/log" + verbs: + - "get" - apiGroups: - "" resources: @@ -959,9 +1094,9 @@ rules: verbs: - patch - create - - apiGroups: [ "" ] - resources: [ "configmaps" ] - verbs: [ "*" ] + - watch + - list + - get - apiGroups: [ "chaos-mesh.org" ] resources: - "*" @@ -975,11 +1110,15 @@ metadata: labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: controller-manager rules: - apiGroups: [ "" ] resources: - nodes + - persistentvolumes + - persistentvolumeclaims - namespaces - services verbs: [ "get", "list", "watch" ] @@ -988,6 +1127,94 @@ rules: - subjectaccessreviews verbs: [ "create" ] --- +# Source: chaos-mesh/templates/dns-rbac.yaml +# roles +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: chaos-mesh-chaos-dns-server-target-namespace + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: dns-server +rules: + - apiGroups: [ "" ] + resources: [ "pods" ] + verbs: [ "get", "list", "watch" ] + - apiGroups: [ "" ] + resources: [ "configmaps" ] + verbs: [ "*" ] + - apiGroups: [ "chaos-mesh.org" ] + resources: + - "*" + verbs: [ "*" ] +--- +# Source: chaos-mesh/templates/dns-rbac.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: chaos-mesh-chaos-dns-server-cluster-level + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: dns-server +rules: + - apiGroups: [ "" ] + resources: + - namespaces + - services + - endpoints + - pods + verbs: [ "get", "list", "watch" ] +--- +# Source: chaos-mesh/templates/chaos-dashboard-rbac.yaml +# ClusterRoleBinding for chaos-dashboard at cluster scope +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: chaos-mesh-chaos-dashboard-cluster-level + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: chaos-dashboard +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: chaos-mesh-chaos-dashboard-cluster-level +subjects: + - kind: ServiceAccount + name: chaos-dashboard + namespace: "chaos-mesh" +--- +# Source: chaos-mesh/templates/chaos-dashboard-rbac.yaml +# binding ClusterRole to ServiceAccount for componnet chaos dashboard +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: chaos-mesh-chaos-dashboard-target-namespace + # TODO: notice that the targetNamespace is still defined as .Values.controllerManager.targetNamespace, .Values.targetNamespace would be better. + namespace: "chaos-mesh" + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: chaos-dashboard +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: chaos-mesh-chaos-dashboard-target-namespace +subjects: + - kind: ServiceAccount + name: chaos-dashboard + namespace: "chaos-mesh" +--- # Source: chaos-mesh/templates/controller-manager-rbac.yaml # bindings cluster level kind: ClusterRoleBinding @@ -997,6 +1224,8 @@ metadata: labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: controller-manager roleRef: apiGroup: rbac.authorization.k8s.io @@ -1005,17 +1234,19 @@ roleRef: subjects: - kind: ServiceAccount name: chaos-controller-manager - namespace: "chaos-testing" + namespace: "chaos-mesh" --- # Source: chaos-mesh/templates/controller-manager-rbac.yaml kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: chaos-mesh-chaos-controller-manager-target-namespace - namespace: "chaos-testing" + namespace: "chaos-mesh" labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: controller-manager roleRef: apiGroup: rbac.authorization.k8s.io @@ -1024,26 +1255,99 @@ roleRef: subjects: - kind: ServiceAccount name: chaos-controller-manager - namespace: "chaos-testing" + namespace: "chaos-mesh" +--- +# Source: chaos-mesh/templates/dns-rbac.yaml +# bindings cluster level +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: chaos-mesh-chaos-dns-server-cluster-level + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: dns-server +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: chaos-mesh-chaos-dns-server-cluster-level +subjects: + - kind: ServiceAccount + name: chaos-dns-server + namespace: "chaos-mesh" +--- +# Source: chaos-mesh/templates/dns-rbac.yaml +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: chaos-mesh-chaos-dns-server-target-namespace + namespace: + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: dns-server +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: chaos-mesh-chaos-dns-server-target-namespace +subjects: + - kind: ServiceAccount + name: chaos-dns-server + namespace: "chaos-mesh" --- # Source: chaos-mesh/templates/controller-manager-rbac.yaml kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: chaos-mesh-chaos-controller-manager-control-plane - namespace: "chaos-testing" + namespace: "chaos-mesh" labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: controller-manager rules: - apiGroups: [ "" ] - resources: [ "configmaps", "services" ] + resources: [ "services", "secrets" ] verbs: [ "get", "list", "watch" ] + - apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["get", "list", "watch"] - apiGroups: [ "authorization.k8s.io" ] resources: - subjectaccessreviews verbs: [ "create" ] + - apiGroups: [ "" ] + resources: [ "pods/exec" ] + verbs: [ "create" ] + - apiGroups: [ "coordination.k8s.io" ] + resources: [ "leases" ] + verbs: [ "*" ] + - apiGroups: [ "" ] + resources: [ "configmaps" ] + verbs: [ "*" ] +--- +# Source: chaos-mesh/templates/dns-rbac.yaml +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: chaos-mesh-chaos-dns-server-control-plane + namespace: "chaos-mesh" + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: dns-server +rules: + - apiGroups: [ "" ] + resources: [ "configmaps" ] + verbs: [ "get", "list" ] --- # Source: chaos-mesh/templates/controller-manager-rbac.yaml # binding for control plane namespace @@ -1051,10 +1355,12 @@ kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: chaos-mesh-chaos-controller-manager-control-plane - namespace: "chaos-testing" + namespace: "chaos-mesh" labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: controller-manager roleRef: apiGroup: rbac.authorization.k8s.io @@ -1063,23 +1369,64 @@ roleRef: subjects: - kind: ServiceAccount name: chaos-controller-manager - namespace: "chaos-testing" + namespace: "chaos-mesh" --- -# Source: chaos-mesh/templates/chaos-daemon-service.yaml -apiVersion: v1 -kind: Service +# Source: chaos-mesh/templates/dns-rbac.yaml +# binding for control plane namespace +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 metadata: - namespace: "chaos-testing" - name: chaos-daemon + name: chaos-mesh-chaos-dns-server-control-plane + namespace: "chaos-mesh" labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh - app.kubernetes.io/component: chaos-daemon -spec: - clusterIP: None - ports: - - name: grpc - port: 31767 + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: dns-server +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: chaos-mesh-chaos-dns-server-control-plane +subjects: + - kind: ServiceAccount + name: chaos-dns-server + namespace: "chaos-mesh" +--- +# Source: chaos-mesh/templates/chaos-daemon-service.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: v1 +kind: Service +metadata: + namespace: "chaos-mesh" + name: chaos-daemon + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "31766" + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: chaos-daemon +spec: + clusterIP: None + ports: + - name: grpc + port: 31767 targetPort: grpc protocol: TCP - name: http @@ -1087,19 +1434,23 @@ spec: targetPort: http protocol: TCP selector: - app.kubernetes.io/component: chaos-daemon + app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/component: chaos-daemon --- # Source: chaos-mesh/templates/chaos-dashboard-deployment.yaml apiVersion: v1 kind: Service metadata: - namespace: "chaos-testing" + namespace: "chaos-mesh" name: chaos-dashboard labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh app.kubernetes.io/component: chaos-dashboard + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "2334" spec: selector: app.kubernetes.io/name: chaos-mesh @@ -1111,46 +1462,141 @@ spec: port: 2333 targetPort: 2333 name: http + - protocol: TCP + port: 2334 + targetPort: 2334 + name: metric --- # Source: chaos-mesh/templates/controller-manager-service.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: v1 kind: Service metadata: - namespace: "chaos-testing" + namespace: "chaos-mesh" name: chaos-mesh-controller-manager + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "10080" labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: controller-manager spec: type: ClusterIP ports: + - port: 443 + targetPort: webhook + protocol: TCP + name: webhook - port: 10081 targetPort: pprof protocol: TCP name: pprof + - port: 10082 + targetPort: ctrl + protocol: TCP + name: ctrl - port: 10080 targetPort: http protocol: TCP name: http - - port: 443 - targetPort: webhook - protocol: TCP - name: webhook selector: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh app.kubernetes.io/component: controller-manager +--- +# Source: chaos-mesh/templates/dns-service.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: v1 +kind: Service +metadata: + name: chaos-mesh-dns-server + namespace: "chaos-mesh" + annotations: + prometheus.io/port: "9153" + prometheus.io/scrape: "true" + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: dns-server +spec: + selector: + app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/component: chaos-dns-server + ports: + - name: dns + port: 53 + targetPort: 5353 + protocol: UDP + - name: dns-tcp + port: 53 + targetPort: 5353 + protocol: TCP + - name: metrics + port: 9153 + protocol: TCP + - name: grpc + port: 9288 + protocol: TCP --- # Source: chaos-mesh/templates/chaos-daemon-daemonset.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + apiVersion: apps/v1 kind: DaemonSet metadata: - namespace: "chaos-testing" + namespace: "chaos-mesh" name: chaos-daemon labels: + app.kubernetes.io/component: chaos-daemon app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh - app.kubernetes.io/component: chaos-daemon + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} spec: selector: matchLabels: @@ -1162,17 +1608,17 @@ spec: labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: chaos-daemon annotations: spec: hostNetwork: ${host_network} - serviceAccount: chaos-daemon - hostIPC: true + serviceAccountName: chaos-daemon hostPID: true - priorityClassName: containers: - name: chaos-daemon - image: ${DOCKER_REGISTRY_PREFIX}/pingcap/chaos-daemon:${VERSION_TAG} + image: ${IMAGE_REGISTRY_PREFIX}/chaos-mesh/chaos-daemon:${VERSION_TAG} imagePullPolicy: IfNotPresent command: - /usr/local/bin/chaos-daemon @@ -1183,6 +1629,8 @@ spec: - --grpc-port - !!str 31767 - --pprof + - --runtime-socket-path + - /host-run/${socketName} env: - name: TZ value: ${timezone} @@ -1193,35 +1641,60 @@ spec: - SYS_PTRACE volumeMounts: - name: socket-path - mountPath: ${mountPath} + mountPath: /host-run - name: sys-path - mountPath: /sys + mountPath: /host-sys + - name: lib-modules + mountPath: /lib/modules ports: - name: grpc containerPort: 31767 - hostPort: 31767 - name: http containerPort: 31766 volumes: - name: socket-path hostPath: - path: ${socketPath} + path: ${socketDir} - name: sys-path hostPath: path: /sys + - name: lib-modules + hostPath: + path: /lib/modules --- # Source: chaos-mesh/templates/chaos-dashboard-deployment.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: apps/v1 kind: Deployment metadata: - namespace: "chaos-testing" + namespace: "chaos-mesh" name: chaos-dashboard labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: chaos-dashboard spec: replicas: 1 + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 selector: matchLabels: app.kubernetes.io/name: chaos-mesh @@ -1232,13 +1705,17 @@ spec: labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: chaos-dashboard + annotations: spec: - serviceAccount: chaos-controller-manager - priorityClassName: + securityContext: + {} + serviceAccountName: chaos-dashboard containers: - name: chaos-dashboard - image: ${DOCKER_REGISTRY_PREFIX}/pingcap/chaos-dashboard:${VERSION_TAG} + image: ${IMAGE_REGISTRY_PREFIX}/chaos-mesh/chaos-dashboard:${VERSION_TAG} imagePullPolicy: IfNotPresent resources: limits: {} @@ -1248,6 +1725,8 @@ spec: command: - /usr/local/bin/chaos-dashboard env: + - name: CLEAN_SYNC_PERIOD + value: "12h" - name: DATABASE_DATASOURCE value: "/data/core.sqlite" - name: DATABASE_DRIVER @@ -1256,18 +1735,40 @@ spec: value: "0.0.0.0" - name: LISTEN_PORT value: "2333" + - name: METRIC_HOST + value: "0.0.0.0" + - name: METRIC_PORT + value: "2334" + - name: TTL_EVENT + value: "168h" + - name: TTL_EXPERIMENT + value: "336h" + - name: TTL_SCHEDULE + value: "336h" + - name: TTL_WORKFLOW + value: "336h" - name: TZ value: ${timezone} - name: CLUSTER_SCOPED value: "true" - name: TARGET_NAMESPACE - value: "chaos-testing" + value: "chaos-mesh" - name: ENABLE_FILTER_NAMESPACE value: "false" - name: SECURITY_MODE value: "false" - - name: DNS_SERVER_CREATE + - name: GCP_SECURITY_MODE value: "false" + - name: GCP_CLIENT_ID + value: "" + - name: GCP_CLIENT_SECRET + value: "" + - name: DNS_SERVER_CREATE + value: "true" + - name: ROOT_URL + value: "http://localhost:2333" + - name: ENABLE_PROFILING + value: "true" volumeMounts: - name: storage-volume mountPath: /data @@ -1275,22 +1776,41 @@ spec: ports: - name: http containerPort: 2333 + - name: metric + containerPort: 2334 volumes: - name: storage-volume emptyDir: {} --- # Source: chaos-mesh/templates/controller-manager-deployment.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + apiVersion: apps/v1 kind: Deployment metadata: - namespace: "chaos-testing" + namespace: "chaos-mesh" name: chaos-controller-manager labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: controller-manager spec: - replicas: 1 + replicas: 3 selector: matchLabels: app.kubernetes.io/name: chaos-mesh @@ -1301,16 +1821,19 @@ spec: labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: controller-manager annotations: rollme: "install.sh" spec: + securityContext: + {} hostNetwork: ${host_network} - serviceAccount: chaos-controller-manager - priorityClassName: + serviceAccountName: chaos-controller-manager containers: - name: chaos-mesh - image: ${DOCKER_REGISTRY_PREFIX}/pingcap/chaos-mesh:${VERSION_TAG} + image: ${IMAGE_REGISTRY_PREFIX}/chaos-mesh/chaos-mesh:${VERSION_TAG} imagePullPolicy: IfNotPresent resources: limits: {} @@ -1320,6 +1843,10 @@ spec: command: - /usr/local/bin/chaos-controller-manager env: + - name: METRICS_PORT + value: "10080" + - name: WEBHOOK_PORT + value: "10250" - name: NAMESPACE valueFrom: fieldRef: @@ -1331,15 +1858,19 @@ spec: - name: ALLOW_HOST_NETWORK_TESTING value: "false" - name: TARGET_NAMESPACE - value: "chaos-testing" + value: "chaos-mesh" - name: CLUSTER_SCOPED value: "true" - name: TZ value: ${timezone} - - name: CHAOS_DAEMON_PORT + - name: CHAOS_DAEMON_SERVICE_PORT value: !!str 31767 - name: BPFKI_PORT value: !!str 50051 + - name: ENABLED_CONTROLLERS + value: "*" + - name: ENABLED_WEBHOOKS + value: "*" - name: TEMPLATE_LABELS value: "app.kubernetes.io/component:template" - name: CONFIGMAP_LABELS @@ -1348,64 +1879,432 @@ spec: value: "false" - name: PPROF_ADDR value: ":10081" + - name: CTRL_ADDR + value: ":10082" - name: CHAOS_DNS_SERVICE_NAME value: chaos-mesh-dns-server - name: CHAOS_DNS_SERVICE_PORT value: !!str 9288 - name: SECURITY_MODE value: "false" + - name: CHAOSD_SECURITY_MODE + value: "false" + - name: POD_FAILURE_PAUSE_IMAGE + value: gcr.io/google-containers/pause:latest + - name: ENABLE_LEADER_ELECTION + value: "true" + - name: LEADER_ELECT_LEASE_DURATION + value: "15s" + - name: LEADER_ELECT_RENEW_DEADLINE + value: "10s" + - name: LEADER_ELECT_RETRY_PERIOD + value: "2s" volumeMounts: - name: webhook-certs mountPath: /etc/webhook/certs readOnly: true ports: - name: webhook - containerPort: 9443 # Customize containerPort + containerPort: 10250 - name: http containerPort: 10080 - name: pprof containerPort: 10081 + - name: ctrl + containerPort: 10082 volumes: - name: webhook-certs secret: secretName: chaos-mesh-webhook-certs --- -# Source: chaos-mesh/templates/secrets-configuration.yaml -apiVersion: admissionregistration.k8s.io/v1beta1 +# Source: chaos-mesh/templates/dns-deployment.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: apps/v1 +kind: Deployment +metadata: + name: chaos-dns-server + namespace: "chaos-mesh" + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: chaos-dns-server +spec: + replicas: 1 + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/component: chaos-dns-server + template: + metadata: + labels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} + app.kubernetes.io/component: chaos-dns-server + spec: + serviceAccountName: chaos-dns-server + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/component + operator: In + values: + - chaos-dns-server + topologyKey: kubernetes.io/hostname + weight: 100 + priorityClassName: + containers: + - name: chaos-dns-server + image: ghcr.io/chaos-mesh/chaos-coredns:v0.2.6 + imagePullPolicy: IfNotPresent + resources: + limits: {} + requests: + cpu: 100m + memory: 70Mi + args: [ "-conf", "/etc/chaos-dns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/chaos-dns + readOnly: true + ports: + - containerPort: 5353 + name: dns + protocol: UDP + - containerPort: 5353 + name: dns-tcp + protocol: TCP + - containerPort: 9153 + name: metrics + protocol: TCP + - containerPort: 9288 + name: grpc + protocol: TCP + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /ready + port: 8181 + scheme: HTTP + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - NET_BIND_SERVICE + drop: + - all + readOnlyRootFilesystem: true + dnsPolicy: Default + volumes: + - name: config-volume + configMap: + name: dns-server-config + items: + - key: Corefile + path: Corefile +--- +# Source: chaos-mesh/templates/cert-manager-certs.yaml +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +# Source: chaos-mesh/templates/chaos-daemon-rbac.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +# Source: chaos-mesh/templates/chaos-dashboard-pvc.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +# Source: chaos-mesh/templates/ingress.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +# Source: chaos-mesh/templates/prometheus-configmap.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +# Source: chaos-mesh/templates/prometheus-deployment.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +# Source: chaos-mesh/templates/prometheus-rbac.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +# Source: chaos-mesh/templates/prometheus-service.yaml +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +# Source: chaos-mesh/templates/mutating-admission-webhooks.yaml +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: name: chaos-mesh-mutation labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: admission-webhook webhooks: - - name: admission-webhook.chaos-mesh.org + - clientConfig: + caBundle: "${CA_BUNDLE}" + service: + name: chaos-mesh-controller-manager + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-podchaos + failurePolicy: Fail + name: mpodchaos.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - podchaos + - clientConfig: + caBundle: "${CA_BUNDLE}" + service: + name: chaos-mesh-controller-manager + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-iochaos + failurePolicy: Fail + name: miochaos.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - iochaos + - clientConfig: + caBundle: "${CA_BUNDLE}" + service: + name: chaos-mesh-controller-manager + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-timechaos + failurePolicy: Fail + name: mtimechaos.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - timechaos + - clientConfig: + caBundle: "${CA_BUNDLE}" + service: + name: chaos-mesh-controller-manager + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-networkchaos + failurePolicy: Fail + name: mnetworkchaos.kb.io timeoutSeconds: 5 - clientConfig: + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - networkchaos + - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: "/inject-v1-pod" + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-kernelchaos + failurePolicy: Fail + name: mkernelchaos.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - - operations: [ "CREATE" ] - apiGroups: [""] - apiVersions: ["v1"] - resources: ["pods"] - namespaceSelector: - matchLabels: - admission-webhook: enabled - failurePolicy: Ignore + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - kernelchaos - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: /mutate-chaos-mesh-org-v1alpha1-podchaos + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-stresschaos failurePolicy: Fail - name: mpodchaos.kb.io + name: mstresschaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1415,16 +2314,18 @@ webhooks: - CREATE - UPDATE resources: - - podchaos + - stresschaos - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: /mutate-chaos-mesh-org-v1alpha1-iochaos + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-awschaos failurePolicy: Fail - name: miochaos.kb.io + name: mawschaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1434,16 +2335,18 @@ webhooks: - CREATE - UPDATE resources: - - iochaos + - awschaos - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: /mutate-chaos-mesh-org-v1alpha1-timechaos + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-azurechaos failurePolicy: Fail - name: mtimechaos.kb.io + name: mazurechaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1453,16 +2356,18 @@ webhooks: - CREATE - UPDATE resources: - - timechaos + - azurechaos - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: /mutate-chaos-mesh-org-v1alpha1-networkchaos + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-gcpchaos failurePolicy: Fail - name: mnetworkchaos.kb.io + name: mgcpchaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1472,16 +2377,18 @@ webhooks: - CREATE - UPDATE resources: - - networkchaos + - gcpchaos - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: /mutate-chaos-mesh-org-v1alpha1-kernelchaos + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-dnschaos failurePolicy: Fail - name: mkernelchaos.kb.io + name: mdnschaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1491,16 +2398,18 @@ webhooks: - CREATE - UPDATE resources: - - kernelchaos + - dnschaos - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: /mutate-chaos-mesh-org-v1alpha1-stresschaos + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-jvmchaos failurePolicy: Fail - name: mstresschaos.kb.io + name: mjvmchaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1510,16 +2419,18 @@ webhooks: - CREATE - UPDATE resources: - - stresschaos + - jvmchaos - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: /mutate-chaos-mesh-org-v1alpha1-awschaos + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-schedule failurePolicy: Fail - name: mawschaos.kb.io + name: mschedule.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1529,16 +2440,18 @@ webhooks: - CREATE - UPDATE resources: - - awschaos + - schedules - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: /mutate-chaos-mesh-org-v1alpha1-gcpchaos + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-workflow failurePolicy: Fail - name: mgcpchaos.kb.io + name: mworkflow.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1548,16 +2461,18 @@ webhooks: - CREATE - UPDATE resources: - - gcpchaos + - workflows - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: /mutate-chaos-mesh-org-v1alpha1-podiochaos + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-httpchaos failurePolicy: Fail - name: mpodiochaos.kb.io + name: mhttpchaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1567,16 +2482,18 @@ webhooks: - CREATE - UPDATE resources: - - podiochaos + - httpchaos - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: /mutate-chaos-mesh-org-v1alpha1-podnetworkchaos + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-blockchaos failurePolicy: Fail - name: mpodnetworkchaos.kb.io + name: mblockchaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1586,16 +2503,18 @@ webhooks: - CREATE - UPDATE resources: - - podnetworkchaos + - blockchaos - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: /mutate-chaos-mesh-org-v1alpha1-dnschaos + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-physicalmachinechaos failurePolicy: Fail - name: mdnschaos.kb.io + name: mphysicalmachinechaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1605,16 +2524,18 @@ webhooks: - CREATE - UPDATE resources: - - dnschaos + - physicalmachinechaos - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: /mutate-chaos-mesh-org-v1alpha1-jvmchaos + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-physicalmachine failurePolicy: Fail - name: mjvmchaos.kb.io + name: mphysicalmachine.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1624,27 +2545,87 @@ webhooks: - CREATE - UPDATE resources: - - jvmchaos + - physicalmachines + - clientConfig: + caBundle: "${CA_BUNDLE}" + service: + name: chaos-mesh-controller-manager + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-statuscheck + failurePolicy: Fail + name: mstatuscheck.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - statuschecks + - clientConfig: + caBundle: "${CA_BUNDLE}" + service: + name: chaos-mesh-controller-manager + namespace: "chaos-mesh" + path: /mutate-chaos-mesh-org-v1alpha1-remotecluster + failurePolicy: Fail + name: mremotecluster.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - remotecluster --- -# Source: chaos-mesh/templates/secrets-configuration.yaml -apiVersion: admissionregistration.k8s.io/v1beta1 +# Source: chaos-mesh/templates/validating-admission-webhooks.yaml +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: name: chaos-mesh-validation labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: admission-webhook webhooks: - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" + namespace: "chaos-mesh" path: /validate-chaos-mesh-org-v1alpha1-podchaos failurePolicy: Fail name: vpodchaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1659,11 +2640,13 @@ webhooks: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" + namespace: "chaos-mesh" path: /validate-chaos-mesh-org-v1alpha1-iochaos failurePolicy: Fail name: viochaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1678,11 +2661,13 @@ webhooks: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" + namespace: "chaos-mesh" path: /validate-chaos-mesh-org-v1alpha1-timechaos failurePolicy: Fail name: vtimechaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1697,11 +2682,13 @@ webhooks: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" + namespace: "chaos-mesh" path: /validate-chaos-mesh-org-v1alpha1-networkchaos failurePolicy: Fail name: vnetworkchaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1716,11 +2703,13 @@ webhooks: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" + namespace: "chaos-mesh" path: /validate-chaos-mesh-org-v1alpha1-kernelchaos failurePolicy: Fail name: vkernelchaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1735,11 +2724,13 @@ webhooks: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" + namespace: "chaos-mesh" path: /validate-chaos-mesh-org-v1alpha1-stresschaos failurePolicy: Fail name: vstresschaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1754,11 +2745,13 @@ webhooks: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" + namespace: "chaos-mesh" path: /validate-chaos-mesh-org-v1alpha1-awschaos failurePolicy: Fail name: vawschaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1773,11 +2766,13 @@ webhooks: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: /validate-chaos-mesh-org-v1alpha1-gcpchaos + namespace: "chaos-mesh" + path: /validate-chaos-mesh-org-v1alpha1-azurechaos failurePolicy: Fail - name: vgcpchaos.kb.io + name: vazurechaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1787,16 +2782,18 @@ webhooks: - CREATE - UPDATE resources: - - gcpchaos + - azurechaos - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" - path: /validate-chaos-mesh-org-v1alpha1-podnetworkchaos + namespace: "chaos-mesh" + path: /validate-chaos-mesh-org-v1alpha1-gcpchaos failurePolicy: Fail - name: vpodnetworkchaos.kb.io + name: vgcpchaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1806,16 +2803,18 @@ webhooks: - CREATE - UPDATE resources: - - podnetworkchaos + - gcpchaos - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" + namespace: "chaos-mesh" path: /validate-chaos-mesh-org-v1alpha1-dnschaos failurePolicy: Fail name: vdnschaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1830,11 +2829,13 @@ webhooks: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" + namespace: "chaos-mesh" path: /validate-chaos-mesh-org-v1alpha1-jvmchaos failurePolicy: Fail name: vjvmchaos.kb.io timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org @@ -1845,25 +2846,198 @@ webhooks: - UPDATE resources: - jvmchaos + - clientConfig: + caBundle: "${CA_BUNDLE}" + service: + name: chaos-mesh-controller-manager + namespace: "chaos-mesh" + path: /validate-chaos-mesh-org-v1alpha1-schedule + failurePolicy: Fail + name: vschedule.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - schedules + - clientConfig: + caBundle: "${CA_BUNDLE}" + service: + name: chaos-mesh-controller-manager + namespace: "chaos-mesh" + path: /validate-chaos-mesh-org-v1alpha1-workflow + failurePolicy: Fail + name: vworkflow.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - workflows + - clientConfig: + caBundle: "${CA_BUNDLE}" + service: + name: chaos-mesh-controller-manager + namespace: "chaos-mesh" + path: /validate-chaos-mesh-org-v1alpha1-httpchaos + failurePolicy: Fail + name: vhttpchaos.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - httpchaos + - clientConfig: + caBundle: "${CA_BUNDLE}" + service: + name: chaos-mesh-controller-manager + namespace: "chaos-mesh" + path: /validate-chaos-mesh-org-v1alpha1-blockchaos + failurePolicy: Fail + name: vblockchaos.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - blockchaos + - clientConfig: + caBundle: "${CA_BUNDLE}" + service: + name: chaos-mesh-controller-manager + namespace: "chaos-mesh" + path: /validate-chaos-mesh-org-v1alpha1-physicalmachinechaos + failurePolicy: Fail + name: vphysicalmachinechaos.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - physicalmachinechaos + - clientConfig: + caBundle: "${CA_BUNDLE}" + service: + name: chaos-mesh-controller-manager + namespace: "chaos-mesh" + path: /validate-chaos-mesh-org-v1alpha1-physicalmachine + failurePolicy: Fail + name: vphysicalmachine.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - physicalmachines + - clientConfig: + caBundle: "${CA_BUNDLE}" + service: + name: chaos-mesh-controller-manager + namespace: "chaos-mesh" + path: /validate-chaos-mesh-org-v1alpha1-statuscheck + failurePolicy: Fail + name: vstatuscheck.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - statuschecks + - clientConfig: + caBundle: "${CA_BUNDLE}" + service: + name: chaos-mesh-controller-manager + namespace: "chaos-mesh" + path: /validate-chaos-mesh-org-v1alpha1-remotecluster + failurePolicy: Fail + name: vremotecluster.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + rules: + - apiGroups: + - chaos-mesh.org + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - remotecluster --- -# Source: chaos-mesh/templates/secrets-configuration.yaml -apiVersion: admissionregistration.k8s.io/v1beta1 +# Source: chaos-mesh/templates/validating-admission-webhooks.yaml +apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: - name: validate-auth + name: chaos-mesh-validation-auth labels: app.kubernetes.io/name: chaos-mesh app.kubernetes.io/instance: chaos-mesh + app.kubernetes.io/part-of: chaos-mesh + app.kubernetes.io/version: ${VERSION_TAG##v} app.kubernetes.io/component: admission-webhook webhooks: - clientConfig: caBundle: "${CA_BUNDLE}" service: name: chaos-mesh-controller-manager - namespace: "chaos-testing" + namespace: "chaos-mesh" path: /validate-auth failurePolicy: Fail name: vauth.kb.io + timeoutSeconds: 5 + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] rules: - apiGroups: - chaos-mesh.org diff --git a/local-binary.generated.mk b/local-binary.generated.mk new file mode 100644 index 0000000000..1c44d26955 --- /dev/null +++ b/local-binary.generated.mk @@ -0,0 +1,16 @@ +# Generated by ./cmd/generate-makefile. DO NOT EDIT. + +##@ Generated targets in local-binary.generated.mk + +.PHONY: bin/chaos-controller-manager +local/chaos-controller-manager: ## Build binary chaos-controller-manager in local environment + $(GO) build -ldflags "$(LDFLAGS)" -tags "${BUILD_TAGS}" -o bin/chaos-controller-manager cmd/chaos-controller-manager/main.go + +.PHONY: bin/chaos-dashboard +local/chaos-dashboard: ## Build binary chaos-dashboard in local environment + $(CGO) build -ldflags "$(LDFLAGS)" -tags "${BUILD_TAGS}" -o bin/chaos-dashboard cmd/chaos-dashboard/main.go + +.PHONY: clean-local-binary +clean-local-binary: + rm -f bin/chaos-controller-manager + rm -f bin/chaos-dashboard diff --git a/manifests/crd.yaml b/manifests/crd.yaml index 560bc4f2d9..9b7071240e 100644 --- a/manifests/crd.yaml +++ b/manifests/crd.yaml @@ -1,2718 +1,1580 @@ -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.13.0 name: awschaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: AwsChaos - listKind: AwsChaosList + kind: AWSChaos + listKind: AWSChaosList plural: awschaos singular: awschaos - preserveUnknownFields: false scope: Namespaced - validation: - openAPIV3Schema: - description: AwsChaos is the Schema for the awschaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: AwsChaosSpec is the content of the specification for an AwsChaos - properties: - action: - description: 'Action defines the specific aws chaos action. Supported - action: ec2-stop / ec2-restart / detach-volume Default action: ec2-stop' - enum: - - ec2-stop - - ec2-restart - - detach-volume - type: string - awsRegion: - description: AwsRegion defines the region of aws. - type: string - deviceName: - description: DeviceName indicates the name of the device. Needed in - detach-volume. - type: string - duration: - description: Duration represents the duration of the chaos action. - type: string - ec2Instance: - description: Ec2Instance indicates the ID of the ec2 instance. - type: string - endpoint: - description: Endpoint indicates the endpoint of the aws server. Just - used it in test now. - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. - type: string - volumeID: - description: EbsVolume indicates the ID of the EBS volume. Needed in - detach-volume. - type: string - required: - - action - - awsRegion - - ec2Instance - type: object - status: - description: AwsChaosStatus represents the status of an AwsChaos - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: AWSChaos is the Schema for the awschaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AWSChaosSpec is the content of the specification for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. Supported + action: ec2-stop / ec2-restart / detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. Needed in + detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws server. Just + used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. Needed + in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + status: + description: AWSChaosStatus represents the status of an AWSChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null - name: dnschaos.chaos-mesh.org + controller-gen.kubebuilder.io/version: v0.13.0 + name: azurechaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: DNSChaos - listKind: DNSChaosList - plural: dnschaos - singular: dnschaos - preserveUnknownFields: false + kind: AzureChaos + listKind: AzureChaosList + plural: azurechaos + singular: azurechaos scope: Namespaced - validation: - openAPIV3Schema: - description: DNSChaos is the Schema for the networkchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a pod chaos experiment - properties: - action: - description: 'Action defines the specific DNS chaos action. Supported - action: error, random Default action: error' - enum: - - error - - random - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - patterns: - description: "Choose which domain names to take effect, support the - placeholder ? and wildcard *, or the Specified domain name. Note: - \ 1. The wildcard * must be at the end of the string. For example, - chaos-*.org is invalid. 2. if the patterns is empty, will take - effect on all the domain names. For example: \t\tThe value is [\"google.com\", - \"github.*\", \"chaos-mes?.org\"], \t\twill take effect on \"google.com\", - \"github.com\" and \"chaos-mesh.org\"" - items: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: AzureChaos is the Schema for the azurechaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AzureChaosSpec is the content of the specification for an + AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. Supported + action: vm-stop / vm-restart / disk-detach Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach type: string - type: array - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. + diskName: + description: DiskName indicates the name of the disk. Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the data disk. + Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. It + is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + status: + description: AzureChaosStatus represents the status of an AzureChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status items: - type: string + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - status: - description: Most recently observed status of the chaos experiment about - pods - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null - name: gcpchaos.chaos-mesh.org + controller-gen.kubebuilder.io/version: v0.13.0 + name: blockchaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: GcpChaos - listKind: GcpChaosList - plural: gcpchaos - singular: gcpchaos - preserveUnknownFields: false + kind: BlockChaos + listKind: BlockChaosList + plural: blockchaos + singular: blockchaos scope: Namespaced - validation: - openAPIV3Schema: - description: GcpChaos is the Schema for the gcpchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: GcpChaosSpec is the content of the specification for a GcpChaos - properties: - action: - description: 'Action defines the specific gcp chaos action. Supported - action: node-stop / node-reset / disk-loss Default action: node-stop' - enum: - - node-stop - - node-reset - - disk-loss - type: string - deviceName: - description: The device name of the disk to detach. Needed in disk-loss. - type: string - duration: - description: Duration represents the duration of the chaos action. - type: string - instance: - description: Instance defines the name of the instance - type: string - project: - description: Project defines the name of gcp project. - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. It is - used for GCP credentials. - type: string - zone: - description: Zone defines the zone of gcp project. - type: string - required: - - action - - instance - - project - - zone - type: object - status: - description: GcpChaosStatus represents the status of a GcpChaos - properties: - attachedDiskString: - description: The attached disk info string. Needed in disk-loss. - type: string - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: BlockChaos is the Schema for the blockchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BlockChaosSpec is the content of the specification for a + BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. Supported + action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every io request. + type: string + type: object + duration: + description: Duration represents the duration of the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + status: + description: BlockChaosStatus represents the status of a BlockChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + ids: + additionalProperties: + type: integer + description: InjectionIds always specifies the number of injected + chaos action + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null - name: httpchaos.chaos-mesh.org + controller-gen.kubebuilder.io/version: v0.13.0 + name: dnschaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: HTTPChaos - listKind: HTTPChaosList - plural: httpchaos - singular: httpchaos - preserveUnknownFields: false + kind: DNSChaos + listKind: DNSChaosList + plural: dnschaos + singular: dnschaos scope: Namespaced - validation: - openAPIV3Schema: - description: HTTPChaos is the Schema for the HTTPchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: delay | abort | mixed Default action: delay' - enum: - - delay - - abort - - mixed - type: string - duration: - description: Duration represents the duration of the chaos action. It - is required when the action is `PodFailureAction`. 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". - type: string - headers: - description: Specifies how the header match will be performed to route - the request. - items: - properties: - exact_match: - type: string - invert_match: - type: string - name: - type: string - prefix_match: - type: string - present_match: - type: string - range_match: - type: string - regex_match: - type: string - safe_regex_match: - type: string - suffix_match: - type: string - required: - - name - type: object - type: array - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - percent: - description: 'Percent defines the percentage of injection errors and - provides a number from 0-100. default: 100.' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: DNSChaos is the Schema for the networkchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a pod chaos experiment + properties: + action: + description: 'Action defines the specific DNS chaos action. Supported + action: error, random Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, support the + placeholder ? and wildcard *, or the Specified domain name. Note: + 1. The wildcard * must be at the end of the string. For example, + chaos-*.org is invalid. 2. if the patterns is empty, will take effect + on all the domain names. For example: The value is ["google.com", + "github.*", "chaos-mes?.org"], will take effect on "google.com", + "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. IF `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - status: - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + status: + description: Most recently observed status of the chaos experiment about + pods + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null - name: iochaos.chaos-mesh.org + controller-gen.kubebuilder.io/version: v0.13.0 + name: gcpchaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: IoChaos - listKind: IoChaosList - plural: iochaos - singular: iochaos - preserveUnknownFields: false + kind: GCPChaos + listKind: GCPChaosList + plural: gcpchaos + singular: gcpchaos scope: Namespaced - validation: - openAPIV3Schema: - description: IoChaos is the Schema for the iochaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: IoChaosSpec defines the desired state of IoChaos - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: latency / fault / attrOverride / mistake' - enum: - - latency - - fault - - attrOverride - - mistake - type: string - attr: - description: Attr defines the overrided attribution - properties: - atime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - blocks: - format: int64 - type: integer - ctime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - gid: - format: int32 - type: integer - ino: - format: int64 - type: integer - kind: - description: FileType represents type of a file - type: string - mtime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - nlink: - format: int32 - type: integer - perm: - type: integer - rdev: - format: int32 - type: integer - size: - format: int64 - type: integer - uid: - format: int32 - type: integer - type: object - containerName: - description: ContainerName indicates the target container to inject - iochaos in - type: string - delay: - description: Delay defines the value of I/O chaos action delay. A delay - string is a possibly signed sequence of decimal numbers, each with - optional fraction and a unit suffix, such as "300ms". Valid time units - are "ns", "us" (or "µs"), "ms", "s", "m", "h". - type: string - duration: - description: Duration represents the duration of the chaos action. It - is required when the action is `PodFailureAction`. 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". - type: string - errno: - description: 'Errno defines the error code that returned by I/O action. - refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' - format: int32 - type: integer - methods: - description: 'Methods defines the I/O methods for injecting I/O chaos - action. default: all I/O methods.' - items: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: GCPChaos is the Schema for the gcpchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: GCPChaosSpec is the content of the specification for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. Supported + action: node-stop / node-reset / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss type: string - type: array - mistake: - description: Mistake defines what types of incorrectness are injected - to IO operations - properties: - filling: - description: Filling determines what is filled in the miskate data. - enum: - - zero - - random + deviceNames: + description: The device name of disks to detach. Needed in disk-loss. + items: type: string - maxLength: - description: Max length of each wrong data segment in bytes - format: int64 - minimum: 1 - type: integer - maxOccurrences: - description: There will be [1, MaxOccurrences] segments of wrong - data. - format: int64 - minimum: 1 - type: integer - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - path: - description: Path defines the path of files for injecting I/O chaos - action. - type: string - percent: - description: 'Percent defines the percentage of injection errors and - provides a number from 0-100. default: 100.' - type: integer - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + type: array + duration: + description: Duration represents the duration of the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. It + is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + status: + description: GCPChaosStatus represents the status of a GCPChaos + properties: + attachedDiskStrings: + description: The attached disk info strings. Needed in disk-loss. + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. + type: array + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status items: - type: string + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. IF `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - volumePath: - description: VolumePath represents the mount path of injected volume - type: string - required: - - action - - mode - - selector - - volumePath - type: object - status: - description: IoChaosStatus defines the observed state of IoChaos - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null - name: jvmchaos.chaos-mesh.org + controller-gen.kubebuilder.io/version: v0.13.0 + name: httpchaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: JVMChaos - listKind: JVMChaosList - plural: jvmchaos - singular: jvmchaos - preserveUnknownFields: false + kind: HTTPChaos + listKind: HTTPChaosList + plural: httpchaos + singular: httpchaos scope: Namespaced - validation: - openAPIV3Schema: - description: JVMChaos is the Schema for the jvmchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: JVMChaosSpec defines the desired state of JVMChaos - properties: - action: - description: 'Action defines the specific jvm chaos action. Supported - action: delay;return;script;cfl;oom;ccf;tce;cpf;tde;tpf' - enum: - - delay - - return - - script - - cfl - - oom - - ccf - - tce - - cpf - - tde - - tpf - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - flags: - additionalProperties: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: HTTPChaos is the Schema for the HTTPchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status code in + response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal numbers, + each with optional fraction and a unit suffix, such as "300ms", + "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", + "h". type: string - description: Flags represents the flags of action - type: object - matchers: - additionalProperties: + duration: + description: Duration represents the duration of the chaos action. type: string - description: Matchers represents the matching rules for the target - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. + method: + description: Method is a rule to select target by http method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of target. properties: - key: - description: key is the label key that the selector applies - to. + type: + description: Type represents the patch type, only support + `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. + value: + description: Value is the patch contents. type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: - type: string - type: array required: - - key - - operator + - type + - value type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + headers: + description: 'Headers is a rule to append http headers of target. + For example: `[["Set-Cookie", ""], ["Set-Cookie", + ""]]`.' items: - type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - target: - description: 'Target defines the specific jvm chaos target. Supported - target: servlet;psql;jvm;jedis;http;dubbo;rocketmq;tars;mysql;druid;redisson;rabbitmq;mongodb' - enum: - - servlet - - psql - - jvm - - jedis - - http - - dubbo - - rocketmq - - tars - - mysql - - druid - - redisson - - rabbitmq - - mongodb - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the % of pods to do chaos action - type: string - required: - - action - - mode - - selector - - target - type: object - status: - description: JVMChaosStatus defines the observed state of JVMChaos - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: + items: type: string - podIP: + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries of target(Request + only). For example: `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri path in http request. + type: string + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents in target. + properties: + body: + description: Body is a rule to replace http message body in target. + format: byte + type: string + code: + description: Code is a rule to replace http status code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers of target. + The key-value pairs represent header name and header value pairs. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time + method: + description: Method is a rule to replace http method in request. + type: string + path: + description: Path is rule to to replace uri path in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries in http + request. For example, with value `{ "foo": "unknown" }`, the + `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: type: string - type: object - required: - - experiment - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 - served: true - storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null - name: kernelchaos.chaos-mesh.org -spec: - group: chaos-mesh.org - names: - kind: KernelChaos - listKind: KernelChaosList - plural: kernelchaos - singular: kernelchaos - preserveUnknownFields: false - scope: Namespaced - validation: - openAPIV3Schema: - description: KernelChaos is the Schema for the kernelchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a kernel chaos experiment - properties: - duration: - description: Duration represents the duration of the chaos action - type: string - failKernRequest: - description: FailKernRequest defines the request of kernel injection - properties: - callchain: - description: 'Callchain indicate a special call chain, such as: ext4_mount -> - mount_subtree -> ... -> should_failslab With - an optional set of predicates and an optional set of parameters, - which used with predicates. You can read call chan and predicate - examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples - to learn more. If no special call chain, just keep Callchain empty, - which means it will fail at any call chain with slab alloc (eg: - kmalloc).' - items: - description: Frame defines the function signature and predicate - in function's body - properties: - funcname: - description: Funcname can be find from kernel source or `/proc/kallsyms`, - such as `ext4_mount` - type: string - parameters: - description: Parameters is used with predicate, for example, - if you want to inject slab error in `d_alloc_parallel(struct - dentry *parent, const struct qstr *name)` with a special - name `bananas`, you need to set it to `struct dentry *parent, - const struct qstr *name` otherwise omit it. - type: string - predicate: - description: Predicate will access the arguments of this Frame, - example with Parameters's, you can set it to `STRNCMP(name->name, - "bananas", 8)` to make inject only with it, or omit it to - inject for all d_alloc_parallel call chain. - type: string - type: object - type: array - failtype: - description: 'FailType indicates what to fail, can be set to ''0'' - / ''1'' / ''2'' If `0`, indicates slab to fail (should_failslab) - If `1`, indicates alloc_page to fail (should_fail_alloc_page) - If `2`, indicates bio to fail (should_fail_bio) You can read: 1. - https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html 2. - http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt - to learn more' - format: int32 - maximum: 2 - minimum: 0 - type: integer - headers: - description: 'Headers indicates the appropriate kernel headers you - need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so on' - items: - type: string - type: array - probability: - description: Probability indicates the fails with probability. If - you want 1%, please set this field with 1. - format: int32 - maximum: 100 - minimum: 0 - type: integer - times: - description: Times indicates the max times of fails. - format: int32 - minimum: 0 - type: integer - required: - - failtype - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + description: RequestHeaders is a rule to select target by http headers + in request. The key-value pairs represent header name and header + value pairs. + type: object + response_headers: + additionalProperties: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: + description: ResponseHeaders is a rule to select target by http headers + in response. The key-value pairs represent header name and header + value pairs. + type: object + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - fieldSelectors: - additionalProperties: + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos if + there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file in secret, + `ca.crt` for example type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: + certName: + description: CertName represents the data name of cert file in + secret, `tls.crt` for example type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: + keyName: + description: KeyName represents the data name of key file in secret, + `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required secret + resource type: string - type: array - nodeSelectors: - additionalProperties: + secretNamespace: + description: SecretNamespace represents the namespace of required + secret resource type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + status: + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status items: - type: string + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - failKernRequest - - mode - - selector - type: object - status: - description: Most recently observed status of the kernel chaos experiment - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + instances: + additionalProperties: + format: int64 + type: integer + description: Instances always specifies podhttpchaos generation or + empty + type: object + required: + - experiment + type: object + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null - name: networkchaos.chaos-mesh.org + controller-gen.kubebuilder.io/version: v0.13.0 + name: iochaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: NetworkChaos - listKind: NetworkChaosList - plural: networkchaos - singular: networkchaos - preserveUnknownFields: false + kind: IOChaos + listKind: IOChaosList + plural: iochaos + singular: iochaos scope: Namespaced - validation: - openAPIV3Schema: - description: NetworkChaos is the Schema for the networkchaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a pod chaos experiment - properties: - action: - description: 'Action defines the specific network chaos action. Supported - action: partition, netem, delay, loss, duplicate, corrupt Default - action: delay' - enum: - - netem - - delay - - loss - - duplicate - - corrupt - - partition - - bandwidth - type: string - bandwidth: - description: Bandwidth represents the detail about bandwidth control - action - properties: - buffer: - description: Buffer is the maximum amount of bytes that tokens can - be available for instantaneously. - format: int32 - minimum: 1 - type: integer - limit: - description: Limit is the number of bytes that can be queued waiting - for tokens to become available. - format: int32 - minimum: 1 - type: integer - minburst: - description: Minburst specifies the size of the peakrate bucket. - For perfect accuracy, should be set to the MTU of the interface. If - a peakrate is needed, but some burstiness is acceptable, this - size can be raised. A 3000 byte minburst allows around 3mbit/s - of peakrate, given 1000 byte packets. - format: int32 - minimum: 0 - type: integer - peakrate: - description: Peakrate is the maximum depletion rate of the bucket. - The peakrate does not need to be set, it is only necessary if - perfect millisecond timescale shaping is required. - format: int64 - minimum: 0 - type: integer - rate: - description: Rate is the speed knob. Allows bps, kbps, mbps, gbps, - tbps unit. bps means bytes per second. - type: string - required: - - buffer - - limit - - rate - type: object - corrupt: - description: Corrupt represents the detail about corrupt action - properties: - correlation: - type: string - corrupt: - type: string - required: - - correlation - - corrupt - type: object - delay: - description: Delay represents the detail about delay action - properties: - correlation: - type: string - jitter: - type: string - latency: - type: string - reorder: - description: ReorderSpec defines details of packet reorder. - properties: - correlation: - type: string - gap: - type: integer - reorder: - type: string - required: - - correlation - - gap - - reorder - type: object - required: - - latency - type: object - direction: - description: Direction represents the direction, this applies on netem - and network partition action - enum: - - to - - from - - both - - "" - type: string - duplicate: - description: DuplicateSpec represents the detail about loss action - properties: - correlation: - type: string - duplicate: - type: string - required: - - correlation - - duplicate - type: object - duration: - description: Duration represents the duration of the chaos action - type: string - externalTargets: - description: ExternalTargets represents network targets outside k8s - items: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: IOChaos is the Schema for the iochaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake type: string - type: array - loss: - description: Loss represents the detail about loss action - properties: - correlation: - type: string - loss: - type: string - required: - - correlation - - loss - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: - type: string - type: array + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer required: - - key - - operator + - nsec + - sec type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - target: - description: Target represents network target, this applies on netem - and network partition action - properties: - mode: - description: TargetMode defines the target selector mode - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - - "" - type: string - selector: - description: TargetSelector defines the target selector - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: TargetValue is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - mode - - selector - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - status: - description: Most recently observed status of the chaos experiment about - pods - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 - served: true - storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null - name: podchaos.chaos-mesh.org -spec: - group: chaos-mesh.org - names: - kind: PodChaos - listKind: PodChaosList - plural: podchaos - singular: podchaos - preserveUnknownFields: false - scope: Namespaced - validation: - openAPIV3Schema: - description: PodChaos is the control script`s spec. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a pod chaos experiment - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: pod-kill / pod-failure / container-kill Default action: pod-kill' - enum: - - pod-kill - - pod-failure - - container-kill - type: string - containerName: - description: ContainerName indicates the name of the container. Needed - in container-kill. - type: string - duration: - description: Duration represents the duration of the chaos action. It - is required when the action is `PodFailureAction`. 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". - type: string - gracePeriod: - description: GracePeriod is used in pod-kill action. It represents the - duration in seconds before the pod should be deleted. Value must be - non-negative integer. The default value is zero that indicates delete - immediately. - format: int64 - minimum: 0 - type: integer - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. IF `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - status: - description: Most recently observed status of the chaos experiment about - pods - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 - served: true - storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null - name: podiochaos.chaos-mesh.org -spec: - group: chaos-mesh.org - names: - kind: PodIoChaos - listKind: PodIoChaosList - plural: podiochaos - singular: podiochaos - preserveUnknownFields: false - scope: Namespaced - validation: - openAPIV3Schema: - description: PodIoChaos is the Schema for the podiochaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: PodIoChaosSpec defines the desired state of IoChaos - properties: - actions: - description: Actions are a list of IoChaos actions - items: - description: IoChaosAction defines an possible action of IoChaos - properties: - atime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - blocks: - format: int64 - type: integer - ctime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - faults: - description: Faults represents the fault to inject - items: - description: IoFault represents the fault to inject and their - weight - properties: - errno: - format: int32 - type: integer - weight: - format: int32 - type: integer - required: - - errno - - weight - type: object - type: array - gid: - format: int32 - type: integer - ino: - format: int64 - type: integer - kind: - description: FileType represents type of a file - type: string - latency: - description: Latency represents the latency to inject - type: string - methods: - description: Methods represents the method that the action will - inject in - items: - type: string - type: array - mistake: - description: MistakeSpec represents the mistake to inject - properties: - filling: - description: Filling determines what is filled in the miskate - data. - enum: - - zero - - random - type: string - maxLength: - description: Max length of each wrong data segment in bytes - format: int64 - minimum: 1 - type: integer - maxOccurrences: - description: There will be [1, MaxOccurrences] segments of - wrong data. - format: int64 - minimum: 1 - type: integer - type: object mtime: description: Timespec represents a time properties: @@ -2729,13 +1591,6 @@ spec: nlink: format: int32 type: integer - path: - description: Path represents a glob of injecting path - type: string - percent: - description: Percent represents the percent probability of injecting - this action - type: integer perm: type: integer rdev: @@ -2744,5090 +1599,48995 @@ spec: size: format: int64 type: integer - source: - description: Source represents the source of current rules - type: string - type: - description: IoChaosType represents the type of an IoChaos Action - type: string uid: format: int32 type: integer - required: - - path - - percent - - type type: object - type: array - container: - description: 'TODO: support multiple different container to inject in - one pod' - type: string - pid: - description: Pid represents a running toda process id - format: int64 - type: integer - startTime: - description: StartTime represents the start time of a toda process - format: int64 - type: integer - volumeMountPath: - description: 'VolumeMountPath represents the target mount path It must - be a root of mount path now. TODO: search the mount parent of any - path automatically. TODO: support multiple different volume mount - path in one pod' - type: string - required: - - volumeMountPath - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 - served: true - storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null - name: podnetworkchaos.chaos-mesh.org -spec: - group: chaos-mesh.org - names: - kind: PodNetworkChaos - listKind: PodNetworkChaosList - plural: podnetworkchaos - singular: podnetworkchaos - preserveUnknownFields: false - scope: Namespaced - validation: - openAPIV3Schema: - description: PodNetworkChaos is the Schema for the PodNetworkChaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a pod chaos experiment - properties: - ipsets: - description: The ipset on the pod - items: - description: RawIPSet represents an ipset on specific pod + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action delay. A + delay string is a possibly signed sequence of decimal numbers, each + with optional fraction and a unit suffix, such as "300ms". Valid + time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that returned by I/O action. + refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting I/O chaos + action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness are injected + to IO operations properties: - cidrs: - description: The contents of ipset - items: - type: string - type: array - name: - description: The name of ipset - type: string - source: + filling: + description: Filling determines what is filled in the mistake + data. + enum: + - zero + - random type: string - required: - - cidrs - - name - - source - type: object - type: array - iptables: - description: The iptables rules on the pod - items: - description: RawIptables represents the iptables rules on specific - pod + maxLength: + description: Max length of each wrong data segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments of wrong + data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting I/O chaos + action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection errors and + provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. properties: - direction: - description: The block direction of this iptables rule - type: string - ipsets: - description: The name of related ipset - items: + annotationSelectors: + additionalProperties: type: string - type: array - name: - description: The name of iptables chain - type: string - source: - type: string - required: - - direction - - ipsets - - name - - source - type: object - type: array - tcs: - description: The tc rules on the pod - items: - description: RawTrafficControl represents the traffic control chaos - on specific pod - properties: - bandwidth: - description: Bandwidth represents the detail about bandwidth control - action - properties: - buffer: - description: Buffer is the maximum amount of bytes that tokens - can be available for instantaneously. - format: int32 - minimum: 1 - type: integer - limit: - description: Limit is the number of bytes that can be queued - waiting for tokens to become available. - format: int32 - minimum: 1 - type: integer - minburst: - description: Minburst specifies the size of the peakrate bucket. - For perfect accuracy, should be set to the MTU of the interface. If - a peakrate is needed, but some burstiness is acceptable, - this size can be raised. A 3000 byte minburst allows around - 3mbit/s of peakrate, given 1000 byte packets. - format: int32 - minimum: 0 - type: integer - peakrate: - description: Peakrate is the maximum depletion rate of the - bucket. The peakrate does not need to be set, it is only - necessary if perfect millisecond timescale shaping is required. - format: int64 - minimum: 0 - type: integer - rate: - description: Rate is the speed knob. Allows bps, kbps, mbps, - gbps, tbps unit. bps means bytes per second. - type: string - required: - - buffer - - limit - - rate - type: object - corrupt: - description: Corrupt represents the detail about corrupt action - properties: - correlation: - type: string - corrupt: - type: string - required: - - correlation - - corrupt + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. type: object - delay: - description: Delay represents the detail about delay action - properties: - correlation: - type: string - jitter: - type: string - latency: - type: string - reorder: - description: ReorderSpec defines details of packet reorder. - properties: - correlation: - type: string - gap: - type: integer - reorder: + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: type: string - required: - - correlation - - gap - - reorder - type: object - required: - - latency - type: object - duplicate: - description: DuplicateSpec represents the detail about loss action - properties: - correlation: - type: string - duplicate: - type: string - required: - - correlation - - duplicate - type: object - ipset: - description: The name of target ipset - type: string - loss: - description: Loss represents the detail about loss action - properties: - correlation: - type: string - loss: - type: string - required: - - correlation - - loss + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. type: object - source: - description: The name and namespace of the source network chaos - type: string - type: - description: The type of traffic control - type: string - required: - - source - - type - type: object - type: array - type: object - status: - description: Most recently observed status of the chaos experiment about - pods - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 - served: true - storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null - name: stresschaos.chaos-mesh.org -spec: - group: chaos-mesh.org - names: - kind: StressChaos - listKind: StressChaosList - plural: stresschaos - singular: stresschaos - preserveUnknownFields: false - scope: Namespaced - validation: - openAPIV3Schema: - description: StressChaos is the Schema for the stresschaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a time chaos experiment - properties: - containerName: - description: ContainerName indicates the target container to inject - stress in - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - stressngStressors: - description: StressngStressors defines plenty of stressors just like - `Stressors` except that it's an experimental feature and more powerful. - You can define stressors in `stress-ng` (see also `man stress-ng`) - dialect, however not all of the supported stressors are well tested. - It maybe retired in later releases. You should always use `Stressors` - to define the stressors and use this only when you want more stressors - unsupported by `Stressors`. When both `StressngStressors` and `Stressors` - are defined, `StressngStressors` wins. - type: string - stressors: - description: Stressors defines plenty of stressors supported to stress - system components out. You can use one or more of them to make up - various kinds of stresses. At least one of the stressors should be - specified. - properties: - cpu: - description: CPUStressor stresses CPU out - properties: - load: - description: Load specifies P percent loading per CPU worker. - 0 is effectively a sleep (no load) and 100 is full loading. - type: integer - options: - description: extend stress-ng options + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: items: type: string type: array - workers: - description: Workers specifies N workers to apply the stressor. - type: integer - required: - - workers - type: object - memory: - description: MemoryStressor stresses virtual memory out + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + status: + description: IOChaosStatus defines the observed state of IOChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: properties: - options: - description: extend stress-ng options - items: - type: string - type: array - size: - description: Size specifies N bytes consumed per vm worker, - default is the total available memory. One can specify the - size as % of total available memory or in units of B, KB/KiB, - MB/MiB, GB/GiB, TB/TiB. + reason: + type: string + status: + type: string + type: type: string - workers: - description: Workers specifies N workers to apply the stressor. - type: integer required: - - workers + - status + - type type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the % of pods to do chaos action - type: string - required: - - mode - - selector - type: object - status: - description: Most recently observed status of the time chaos experiment - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: - type: string - required: - - action - - hostIP - - name - - namespace - - podIP - type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - instances: - additionalProperties: - description: StressInstance is an instance generates stresses + type: array + experiment: + description: Experiment records the last experiment state. properties: - startTime: - description: StartTime specifies when the instance starts - format: date-time - type: string - uid: - description: UID is the instance identifier + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop type: string type: object - description: Instances always specifies stressing instances - type: object - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + instances: + additionalProperties: + format: int64 + type: integer + description: Instances always specifies podiochaos generation or empty + type: object + required: + - experiment + type: object + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null - name: timechaos.chaos-mesh.org + controller-gen.kubebuilder.io/version: v0.13.0 + name: jvmchaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: TimeChaos - listKind: TimeChaosList - plural: timechaos - singular: timechaos - preserveUnknownFields: false + kind: JVMChaos + listKind: JVMChaosList + plural: jvmchaos + singular: jvmchaos scope: Namespaced - validation: - openAPIV3Schema: - description: TimeChaos is the Schema for the timechaos API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a time chaos experiment - properties: - clockIds: - description: ClockIds defines all affected clock id All available options - are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", - "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", - "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] - items: + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: JVMChaos is the Schema for the jvmchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. Supported + action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql type: string - type: array - containerNames: - description: ContainerName indicates the name of affected container. - If not set, all containers will be injected - items: + class: + description: Java class type: string - type: array - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported mode: - one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the running - time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" \"@hourly\" - \ means to \"Every hour\" \"@every 1h30m\" means to \"Every - hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can be used - to select objects. A list of selectors based on set-based label - expressions. - items: - description: A label selector requirement is a selector that contains - values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator - is In or NotIn, the values array must be non-empty. If the - operator is Exists or DoesNotExist, the values array must - be empty. This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator + type: array + cpuCount: + description: the CPU core number needs to use, only set it when action + is stress + type: integer + database: + description: the match database default value is "", means match all + database + type: string + duration: + description: Duration represents the duration of the chaos action + type: string + exception: + description: the exception which needs to throw for action `exception` + or the exception message needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', unit ms or + the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it when action + is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support 5.X.X(set + to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will generate + one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used to select - nodes. Selector which must match a node's labels, and objects - must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod at - the current time. supported value: Pending / Running / Succeeded - / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - timeOffset: - description: TimeOffset defines the delta time of injected program. - It's a possibly signed sequence of decimal numbers, such as "300ms", - "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", - "s", "m", "h". - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the max percent of pods to do chaos action - type: string - required: - - mode - - selector - - timeOffset - type: object - status: - description: Most recently observed status of the time chaos experiment - properties: - experiment: - description: Experiment records the last experiment state. - properties: - duration: - type: string - endTime: - format: date-time - type: string - phase: - description: ExperimentPhase is the current status of chaos experiment. - type: string - podRecords: - items: - description: PodStatus represents information about the status - of a pod in chaos experiment. - properties: - action: - type: string - hostIP: - type: string - message: - description: A brief CamelCase message indicating details - about the chaos action. e.g. "delete this pod" or "pause - this pod duration 5m" - type: string - name: - type: string - namespace: - type: string - podIP: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - action - - hostIP - - name - - namespace - - podIP + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - reason: - type: string - startTime: - format: date-time - type: string - type: object - failedMessage: - type: string - scheduler: - description: ScheduleStatus is the current status of chaos scheduler. - properties: - nextRecover: - description: Next time when this action will be recovered - format: date-time - type: string - nextStart: - description: Next time when this action will be applied again - format: date-time - type: string - type: object - required: - - experiment - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: object + sqlType: + description: the match sql type default value is "", means match all + SQL type. The value can be 'select', 'insert', 'update', 'delete', + 'replace'. + type: string + table: + description: the match table default value is "", means match all + table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + status: + description: JVMChaosStatus defines the observed state of JVMChaos + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null - name: workflownodes.chaos-mesh.org + controller-gen.kubebuilder.io/version: v0.13.0 + name: kernelchaos.chaos-mesh.org spec: group: chaos-mesh.org names: - kind: WorkflowNode - listKind: WorkflowNodeList - plural: workflownodes - shortNames: - - wfn - singular: workflownode - preserveUnknownFields: false + kind: KernelChaos + listKind: KernelChaosList + plural: kernelchaos + singular: kernelchaos scope: Namespaced - validation: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a node of workflow - properties: - aws_chaos: - description: AwsChaosSpec is the content of the specification for an - AwsChaos - properties: - action: - description: 'Action defines the specific aws chaos action. Supported - action: ec2-stop / ec2-restart / detach-volume Default action: - ec2-stop' - enum: - - ec2-stop - - ec2-restart - - detach-volume - type: string - awsRegion: - description: AwsRegion defines the region of aws. - type: string - deviceName: - description: DeviceName indicates the name of the device. Needed - in detach-volume. - type: string - duration: - description: Duration represents the duration of the chaos action. - type: string - ec2Instance: - description: Ec2Instance indicates the ID of the ec2 instance. - type: string - endpoint: - description: Endpoint indicates the endpoint of the aws server. - Just used it in test now. + versions: + - additionalPrinterColumns: + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: KernelChaos is the Schema for the kernelchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a kernel chaos experiment + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call chain, such as: + ext4_mount -> mount_subtree -> ... -> should_failslab With an + optional set of predicates and an optional set of parameters, + which used with predicates. You can read call chan and predicate + examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep Callchain + empty, which means it will fail at any call chain with slab + alloc (eg: kmalloc).' + items: + description: Frame defines the function signature and predicate + in function's body + properties: + funcname: + description: Funcname can be find from kernel source or + `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, for example, + if you want to inject slab error in `d_alloc_parallel(struct + dentry *parent, const struct qstr *name)` with a special + name `bananas`, you need to set it to `struct dentry *parent, + const struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments of this + Frame, example with Parameters's, you can set it to `STRNCMP(name->name, + "bananas", 8)` to make inject only with it, or omit it + to inject for all d_alloc_parallel call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be set to ''0'' + / ''1'' / ''2'' If `0`, indicates slab to fail (should_failslab) + If `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) You can read: + 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel headers + you need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so on' + items: type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. - type: string - volumeID: - description: EbsVolume indicates the ID of the EBS volume. Needed - in detach-volume. - type: string - required: - - action - - awsRegion - - ec2Instance - type: object - deadline: - format: date-time - type: string - dns_chaos: - description: DNSChaosSpec defines the desired state of DNSChaos - properties: - action: - description: 'Action defines the specific DNS chaos action. Supported - action: error, random Default action: error' - enum: - - error - - random - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - patterns: - description: "Choose which domain names to take effect, support - the placeholder ? and wildcard *, or the Specified domain name. - Note: 1. The wildcard * must be at the end of the string. - For example, chaos-*.org is invalid. 2. if the patterns is - empty, will take effect on all the domain names. For example: - \t\tThe value is [\"google.com\", \"github.*\", \"chaos-mes?.org\"], - \t\twill take effect on \"google.com\", \"github.com\" and \"chaos-mesh.org\"" - items: - type: string - type: array - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - action - - mode - - selector - type: object - gcp_chaos: - description: GcpChaosSpec is the content of the specification for a - GcpChaos - properties: - action: - description: 'Action defines the specific gcp chaos action. Supported - action: node-stop / node-reset / disk-loss Default action: node-stop' - enum: - - node-stop - - node-reset - - disk-loss - type: string - deviceName: - description: The device name of the disk to detach. Needed in disk-loss. - type: string - duration: - description: Duration represents the duration of the chaos action. - type: string - instance: - description: Instance defines the name of the instance - type: string - project: - description: Project defines the name of gcp project. - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + type: array + fieldSelectors: + additionalProperties: type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. It - is used for GCP credentials. - type: string - zone: - description: Zone defines the zone of gcp project. - type: string - required: - - action - - instance - - project - - zone - type: object - http_chaos: - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: delay | abort | mixed Default action: delay' - enum: - - delay - - abort - - mixed - type: string - duration: - description: Duration represents the duration of the chaos action. - It is required when the action is `PodFailureAction`. 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". - type: string - headers: - description: Specifies how the header match will be performed to - route the request. - items: - properties: - exact_match: - type: string - invert_match: - type: string - name: - type: string - prefix_match: - type: string - present_match: - type: string - range_match: - type: string - regex_match: - type: string - safe_regex_match: - type: string - suffix_match: + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - required: - - name + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. type: object - type: array - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - percent: - description: 'Percent defines the percentage of injection errors - and provides a number from 0-100. default: 100.' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about pods. + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + status: + description: Most recently observed status of the kernel chaos experiment + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + reason: + type: string + status: + type: string + type: type: string required: - - cron + - status + - type type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - action - - mode - - selector - type: object - io_chaos: - description: IoChaosSpec defines the desired state of IoChaos - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: latency / fault / attrOverride / mistake' - enum: - - latency - - fault - - attrOverride - - mistake - type: string - attr: - description: Attr defines the overrided attribution - properties: - atime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - blocks: - format: int64 - type: integer - ctime: - description: Timespec represents a time + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: properties: - nsec: - format: int64 + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections type: integer - sec: - format: int64 + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries type: integer + selectorKey: + type: string required: - - nsec - - sec + - id + - injectedCount + - phase + - recoveredCount + - selectorKey type: object - gid: - format: int32 - type: integer - ino: - format: int64 - type: integer - kind: - description: FileType represents type of a file + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: networkchaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: NetworkChaos + listKind: NetworkChaosList + plural: networkchaos + singular: networkchaos + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: NetworkChaos is the Schema for the networkchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a pod chaos experiment + properties: + action: + description: 'Action defines the specific network chaos action. Supported + action: partition, netem, delay, loss, duplicate, corrupt Default + action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth control + action + properties: + buffer: + description: Buffer is the maximum amount of bytes that tokens + can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be queued waiting + for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate bucket. + For perfect accuracy, should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness is acceptable, this + size can be raised. A 3000 byte minburst allows around 3mbit/s + of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of the bucket. + The peakrate does not need to be set, it is only necessary if + perfect millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, gbit, + tbit, bps, kbps, mbps, gbps, tbps unit. bps means bytes per + second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies on netem + and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, gbit, + tbit, bps, kbps, mbps, gbps, tbps unit. bps means bytes per + second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: type: string - mtime: - description: Timespec represents a time + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array required: - - nsec - - sec + - key + - operator type: object - nlink: - format: int32 - type: integer - perm: - type: integer - rdev: - format: int32 - type: integer - size: - format: int64 - type: integer - uid: - format: int32 - type: integer - type: object - containerName: - description: ContainerName indicates the target container to inject - iochaos in - type: string - delay: - description: Delay defines the value of I/O chaos action delay. - A delay string is a possibly signed sequence of decimal numbers, - each with optional fraction and a unit suffix, such as "300ms". - Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - type: string - duration: - description: Duration represents the duration of the chaos action. - It is required when the action is `PodFailureAction`. 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". - type: string - errno: - description: 'Errno defines the error code that returned by I/O - action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' - format: int32 - type: integer - methods: - description: 'Methods defines the I/O methods for injecting I/O - chaos action. default: all I/O methods.' - items: - type: string - type: array - mistake: - description: Mistake defines what types of incorrectness are injected - to IO operations - properties: - filling: - description: Filling determines what is filled in the miskate - data. - enum: - - zero - - random - type: string - maxLength: - description: Max length of each wrong data segment in bytes - format: int64 - minimum: 1 - type: integer - maxOccurrences: - description: There will be [1, MaxOccurrences] segments of wrong - data. - format: int64 - minimum: 1 - type: integer - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - path: - description: Path defines the path of files for injecting I/O chaos - action. - type: string - percent: - description: 'Percent defines the percentage of injection errors - and provides a number from 0-100. default: 100.' - type: integer - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + type: array + fieldSelectors: + additionalProperties: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: items: type: string type: array - pods: - additionalProperties: + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this applies on netem + and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - volumePath: - description: VolumePath represents the mount path of injected volume - type: string - required: - - action - - mode - - selector - - volumePath - type: object - jvm_chaos: - description: JVMChaosSpec defines the desired state of JVMChaos - properties: - action: - description: 'Action defines the specific jvm chaos action. Supported - action: delay;return;script;cfl;oom;ccf;tce;cpf;tde;tpf' - enum: - - delay - - return - - script - - cfl - - oom - - ccf - - tce - - cpf - - tde - - tpf - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - flags: - additionalProperties: - type: string - description: Flags represents the flags of action - type: object - matchers: - additionalProperties: - type: string - description: Matchers represents the matching rules for the target - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - target: - description: 'Target defines the specific jvm chaos target. Supported - target: servlet;psql;jvm;jedis;http;dubbo;rocketmq;tars;mysql;druid;redisson;rabbitmq;mongodb' - enum: - - servlet - - psql - - jvm - - jedis - - http - - dubbo - - rocketmq - - tars - - mysql - - druid - - redisson - - rabbitmq - - mongodb - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the % of pods to do chaos action - type: string - required: - - action - - mode - - selector - - target - type: object - kernel_chaos: - description: KernelChaosSpec defines the desired state of KernelChaos - properties: - duration: - description: Duration represents the duration of the chaos action - type: string - failKernRequest: - description: FailKernRequest defines the request of kernel injection - properties: - callchain: - description: 'Callchain indicate a special call chain, such - as: ext4_mount -> mount_subtree -> ... -> - should_failslab With an optional set of predicates and an - optional set of parameters, which used with predicates. You - can read call chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples - to learn more. If no special call chain, just keep Callchain - empty, which means it will fail at any call chain with slab - alloc (eg: kmalloc).' - items: - description: Frame defines the function signature and predicate - in function's body - properties: - funcname: - description: Funcname can be find from kernel source or - `/proc/kallsyms`, such as `ext4_mount` - type: string - parameters: - description: Parameters is used with predicate, for example, - if you want to inject slab error in `d_alloc_parallel(struct - dentry *parent, const struct qstr *name)` with a special - name `bananas`, you need to set it to `struct dentry - *parent, const struct qstr *name` otherwise omit it. - type: string - predicate: - description: Predicate will access the arguments of this - Frame, example with Parameters's, you can set it to - `STRNCMP(name->name, "bananas", 8)` to make inject only - with it, or omit it to inject for all d_alloc_parallel - call chain. - type: string - type: object - type: array - failtype: - description: 'FailType indicates what to fail, can be set to - ''0'' / ''1'' / ''2'' If `0`, indicates slab to fail (should_failslab) - If `1`, indicates alloc_page to fail (should_fail_alloc_page) - If `2`, indicates bio to fail (should_fail_bio) You can read: 1. - https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html 2. - http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt - to learn more' - format: int32 - maximum: 2 - minimum: 0 - type: integer - headers: - description: 'Headers indicates the appropriate kernel headers - you need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so on' - items: - type: string - type: array - probability: - description: Probability indicates the fails with probability. - If you want 1%, please set this field with 1. - format: int32 - maximum: 100 - minimum: 0 - type: integer - times: - description: Times indicates the max times of fails. - format: int32 - minimum: 0 - type: integer - required: - - failtype - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' items: type: string type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - failKernRequest - - mode - - selector - type: object - network_chaos: - description: NetworkChaosSpec defines the desired state of NetworkChaos - properties: - action: - description: 'Action defines the specific network chaos action. - Supported action: partition, netem, delay, loss, duplicate, corrupt - Default action: delay' - enum: - - netem - - delay - - loss - - duplicate - - corrupt - - partition - - bandwidth - type: string - bandwidth: - description: Bandwidth represents the detail about bandwidth control - action - properties: - buffer: - description: Buffer is the maximum amount of bytes that tokens - can be available for instantaneously. - format: int32 - minimum: 1 - type: integer - limit: - description: Limit is the number of bytes that can be queued - waiting for tokens to become available. - format: int32 - minimum: 1 - type: integer - minburst: - description: Minburst specifies the size of the peakrate bucket. - For perfect accuracy, should be set to the MTU of the interface. If - a peakrate is needed, but some burstiness is acceptable, this - size can be raised. A 3000 byte minburst allows around 3mbit/s - of peakrate, given 1000 byte packets. - format: int32 - minimum: 0 - type: integer - peakrate: - description: Peakrate is the maximum depletion rate of the bucket. - The peakrate does not need to be set, it is only necessary - if perfect millisecond timescale shaping is required. - format: int64 - minimum: 0 - type: integer - rate: - description: Rate is the speed knob. Allows bps, kbps, mbps, - gbps, tbps unit. bps means bytes per second. - type: string - required: - - buffer - - limit - - rate - type: object - corrupt: - description: Corrupt represents the detail about corrupt action - properties: - correlation: - type: string - corrupt: - type: string - required: - - correlation - - corrupt - type: object - delay: - description: Delay represents the detail about delay action - properties: - correlation: - type: string - jitter: - type: string - latency: - type: string - reorder: - description: ReorderSpec defines details of packet reorder. - properties: - correlation: - type: string - gap: - type: integer - reorder: - type: string - required: - - correlation - - gap - - reorder - type: object - required: - - latency - type: object - direction: - description: Direction represents the direction, this applies on - netem and network partition action - enum: - - to - - from - - both - - "" - type: string - duplicate: - description: DuplicateSpec represents the detail about loss action - properties: - correlation: - type: string - duplicate: - type: string - required: - - correlation - - duplicate - type: object - duration: - description: Duration represents the duration of the chaos action - type: string - externalTargets: - description: ExternalTargets represents network targets outside - k8s - items: - type: string - type: array - loss: - description: Loss represents the detail about loss action + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device to be affected + in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + status: + description: Most recently observed status of the chaos experiment about + pods + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: properties: - correlation: + reason: type: string - loss: + status: type: string - required: - - correlation - - loss - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" + type: type: string required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object + - status + - type type: object - target: - description: Target represents network target, this applies on netem - and network partition action - properties: - mode: - description: TargetMode defines the target selector mode - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - - "" - type: string - selector: - description: TargetSelector defines the target selector + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. + events: + description: Events are the essential details about the + injections and recoveries items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. This - array is replaced during a strategic merge patch. - items: - type: string - type: array + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string required: - - key - - operator + - operation + - timestamp + - type type: object type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of - a pod at the current time. supported value: Pending / - Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey type: object - value: - description: TargetValue is required when the mode is set to - `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - If `FixedPodMode`, provide an integer of pods to do chaos - action. If `FixedPercentPodMod`, provide a number from 0-100 - to specify the percent of pods the server can do chaos action. - If `RandomMaxPercentPodMod`, provide a number from 0-100 - to specify the max percent of pods to do chaos action - type: string - required: - - mode - - selector - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - action - - mode - - selector - type: object - pod_chaos: - description: PodChaosSpec defines the attributes that a user creates - on a chaos experiment about pods. - properties: - action: - description: 'Action defines the specific pod chaos action. Supported - action: pod-kill / pod-failure / container-kill Default action: - pod-kill' - enum: - - pod-kill - - pod-failure - - container-kill - type: string - containerName: - description: ContainerName indicates the name of the container. - Needed in container-kill. - type: string - duration: - description: Duration represents the duration of the chaos action. - It is required when the action is `PodFailureAction`. 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". - type: string - gracePeriod: - description: GracePeriod is used in pod-kill action. It represents - the duration in seconds before the pod should be deleted. Value - must be non-negative integer. The default value is zero that indicates - delete immediately. + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + instances: + additionalProperties: format: int64 - minimum: 0 type: integer - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent + description: Instances always specifies podnetworkchaos generation + or empty + type: object + required: + - experiment + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: physicalmachinechaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: PhysicalMachineChaos + listKind: PhysicalMachineChaosList + plural: physicalmachinechaos + singular: physicalmachinechaos + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.action + name: action + type: string + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: PhysicalMachineChaos is the Schema for the physical machine chaos + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a physical machine chaos experiment + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one of Address + and Selector could be specified.' + items: type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - action - - mode - - selector - type: object - start_time: - format: date-time - type: string - stress_chaos: - description: StressChaosSpec defines the desired state of StressChaos - properties: - containerName: - description: ContainerName indicates the target container to inject - stress in - type: string - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - stressngStressors: - description: StressngStressors defines plenty of stressors just - like `Stressors` except that it's an experimental feature and - more powerful. You can define stressors in `stress-ng` (see also - `man stress-ng`) dialect, however not all of the supported stressors - are well tested. It maybe retired in later releases. You should - always use `Stressors` to define the stressors and use this only - when you want more stressors unsupported by `Stressors`. When - both `StressngStressors` and `Stressors` are defined, `StressngStressors` - wins. - type: string - stressors: - description: Stressors defines plenty of stressors supported to - stress system components out. You can use one or more of them - to make up various kinds of stresses. At least one of the stressors - should be specified. - properties: - cpu: - description: CPUStressor stresses CPU out - properties: - load: - description: Load specifies P percent loading per CPU worker. - 0 is effectively a sleep (no load) and 100 is full loading. - type: integer - options: - description: extend stress-ng options - items: - type: string - type: array - workers: - description: Workers specifies N workers to apply the stressor. - type: integer - required: - - workers - type: object - memory: - description: MemoryStressor stresses virtual memory out - properties: - options: - description: extend stress-ng options - items: - type: string - type: array - size: - description: Size specifies N bytes consumed per vm worker, - default is the total available memory. One can specify - the size as % of total available memory or in units of - B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. - type: string - workers: - description: Workers specifies N workers to apply the stressor. - type: integer - required: - - workers - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide a number - from 0-100 to specify the % of pods to do chaos action - type: string - required: - - mode - - selector - type: object - tasks: - items: + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock on which to + act. More clock description in linux kernel can be found in + man page of clock_getres, clock_gettime, clock_settime. Muti + clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. if path not + provided, payload will read/write from/into a temp file, temp + file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will write into + the file path. support unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. if path not + provided, payload will read/write from/into a temp file, temp + file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write into + the file path. support unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. if path not + provided, payload will read/write from/into a temp file, temp + file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write into + the file path. support unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos action type: string - type: array - template_name: - type: string - time_chaos: - description: TimeChaosSpec defines the desired state of TimeChaos - properties: - clockIds: - description: ClockIds defines all affected clock id All available - options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", - "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", - "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] - items: - type: string - type: array - containerNames: - description: ContainerName indicates the name of affected container. - If not set, all containers will be injected - items: - type: string - type: array - duration: - description: Duration represents the duration of the chaos action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control the - running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule examples: - \"0 30 * * * *\" means to \"Every hour on the half hour\" - \"@hourly\" means to \"Every hour\" \"@every 1h30m\" - means to \"Every hour thirty\" \n More rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used to inject - chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that can - be used to select objects. A list of selectors based on set-based - label expressions. - items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which objects - belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be used - to select nodes. Selector which must match a node's labels, - and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must belong - to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition of a pod - at the current time. supported value: Pending / Running / - Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values that - used to select pods. The key defines the namespace which pods - belong, and the each values is a set of pod names. - type: object - type: object - timeOffset: - description: TimeOffset defines the delta time of injected program. - It's a possibly signed sequence of decimal numbers, such as "300ms", - "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), - "ms", "s", "m", "h". - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods the - server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to do chaos - action - type: string - required: - - mode - - selector - - timeOffset - type: object - type: - type: string - workflow_name: - type: string - required: - - start_time - - template_name - - type - - workflow_name - type: object - status: - description: Most recently observed status of the workflow node - properties: - active_children: - description: ActiveChildren means the created children node - items: - description: LocalObjectReference contains enough information to let - you locate the referenced object inside the same namespace. + file-append: properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - type: object - type: array - chaos_resource: - description: ChaosResource refs to the real chaos CR object. - properties: - apiGroup: - description: APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the - core API group. For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - required: - - kind - - name - type: object - conditions: - description: Represents the latest available observations of a worklfow - node's current state. - items: + count: + description: Count is the number of times to append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. + type: string + type: object + file-create: properties: - reason: + dir-name: + description: DirName is the directory name to create or delete. type: string - status: + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. type: string - type: + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the file. + type: string + file-name: + description: FileName is the name of the file to be created, modified, + deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http status code + in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' type: string required: - - reason - - status - - type + - proxy_ports + - target type: object - type: array - expected_children_num: - description: ExpectedChildrenNum means the expected children to execute - type: integer - finished_children: - description: Children is necessary for representing the order when replicated - child template references by parent template. - items: - description: LocalObjectReference contains enough information to let - you locate the referenced object inside the same namespace. + http-config: properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' + file_path: + description: The config file path type: string type: object - type: array - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 - served: true - storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.2.5 - creationTimestamp: null - name: workflows.chaos-mesh.org -spec: - group: chaos-mesh.org - names: - kind: Workflow - listKind: WorkflowList - plural: workflows - shortNames: - - wf - singular: workflow - preserveUnknownFields: false - scope: Namespaced - validation: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the behavior of a workflow - properties: - entry: - type: string - templates: - items: + http-delay: properties: - aws_chaos: - description: AwsChaosSpec is the content of the specification - for an AwsChaos - properties: - action: - description: 'Action defines the specific aws chaos action. - Supported action: ec2-stop / ec2-restart / detach-volume - Default action: ec2-stop' - enum: - - ec2-stop - - ec2-restart - - detach-volume - type: string - awsRegion: - description: AwsRegion defines the region of aws. - type: string - deviceName: - description: DeviceName indicates the name of the device. - Needed in detach-volume. - type: string - duration: - description: Duration represents the duration of the chaos - action. - type: string - ec2Instance: - description: Ec2Instance indicates the ID of the ec2 instance. - type: string - endpoint: - description: Endpoint indicates the endpoint of the aws server. - Just used it in test now. - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. - type: string - volumeID: - description: EbsVolume indicates the ID of the EBS volume. - Needed in detach-volume. - type: string - required: - - action - - awsRegion - - ec2Instance + code: + description: Code is a rule to select target by http status code + in response + type: string + delay: + description: Delay represents the delay of the target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", means match + all database + type: string + exception: + description: The exception which needs to throw for action `exception` + or the exception message needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' or the + latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", means match + all SQL type. The value can be 'select', 'insert', 'update', + 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, will + use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set it when + action is stress + type: integer + mem-type: + description: the memory type need to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: + tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can be accepted, + others will be dropped. only set when the IPProtocol is tcp, + used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: + tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), ms, s, + m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf with this + value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or µs), ms, s, + m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: + tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP address + type: string + rate: + description: The speed of network traffic, allows bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: + tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source ports, + use a ',' to separate or to indicate the range, such as 80, + 8001:8010. it can only be used in conjunction with -p tcp or + -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can be accepted, + others will be dropped. only set when the IPProtocol is tcp, + used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values can be + 'from', 'to'. 'from' means packets coming from the 'IPAddress' + or 'Hostname' and going to your server, 'to' means packets originating + from your server and going to the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of the original + value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. type: object - dns_chaos: - description: DNSChaosSpec defines the desired state of DNSChaos - properties: - action: - description: 'Action defines the specific DNS chaos action. - Supported action: error, random Default action: error' - enum: - - error - - random + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: type: string - duration: - description: Duration represents the duration of the chaos - action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent + type: array + description: PhysicalMachines is a map of string keys and a set + values that used to select physical machines. The key defines + the namespace which physical machine belong, and each value + is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. 0 is + effectively a sleep (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, default + is the total available memory. One can specify the size as % + of total available memory or in units of B, KB/KiB, MB/MiB, + GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of physical machines to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of physical machines + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do chaos + action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + status: + description: Most recently observed status of the chaos experiment + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: physicalmachines.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: PhysicalMachine + listKind: PhysicalMachineList + plural: physicalmachines + singular: physicalmachine + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PhysicalMachine is the Schema for the physical machine API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a physical machine + properties: + address: + description: Address represents the address of the physical machine + type: string + required: + - address + type: object + required: + - spec + type: object + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: podchaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: PodChaos + listKind: PodChaosList + plural: podchaos + singular: podchaos + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PodChaos is the control script`s spec. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a pod chaos experiment + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: pod-kill / pod-failure / container-kill Default action: + pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It represents + the duration in seconds before the pod should be deleted. Value + must be non-negative integer. The default value is zero that indicates + delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - patterns: - description: "Choose which domain names to take effect, support - the placeholder ? and wildcard *, or the Specified domain - name. Note: 1. The wildcard * must be at the end of - the string. For example, chaos-*.org is invalid. 2. - if the patterns is empty, will take effect on all the domain - names. For example: \t\tThe value is [\"google.com\", \"github.*\", - \"chaos-mes?.org\"], \t\twill take effect on \"google.com\", - \"github.com\" and \"chaos-mesh.org\"" - items: + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + status: + description: Most recently observed status of the chaos experiment about + pods + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: podhttpchaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: PodHttpChaos + listKind: PodHttpChaosList + plural: podhttpchaos + singular: podhttpchaos + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PodHttpChaos is the Schema for the podhttpchaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PodHttpChaosSpec defines the desired state of PodHttpChaos. + properties: + rules: + description: Rules are a list of injection rule for http request. + items: + description: PodHttpChaosRule defines the injection rule for http. + properties: + actions: + description: Actions contains rules to inject target. + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, + such as "300ms", "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of + target. + properties: + type: + description: Type represents the patch type, only + support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], + ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", "bar"], + ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http message + body in target. + format: byte + type: string + code: + description: Code is a rule to replace http status code + in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header name + and header value pairs. + type: object + method: + description: Method is a rule to replace http method + in request. + type: string + path: + description: Path is rule to to replace uri path in + http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": + "unknown" }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + type: object + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + selector: + description: Selector contains the rules to select target. + properties: + code: + description: Code is a rule to select target by http status + code in response. + format: int32 + type: integer + method: + description: Method is a rule to select target by http method + in request. + type: string + path: + description: Path is a rule to select target by uri path + in http request. + type: string + port: + description: Port is a rule to select server listening on + specific port. + format: int32 + type: integer + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target by + http headers in request. The key-value pairs represent + header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target + by http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + type: object + source: + description: Source represents the source of current rules + type: string + target: + description: Target is the object to be selected and injected, + . + type: string + required: + - actions + - port + - selector + - target + type: object + type: array + tls: + description: TLS is the tls config, will be override if there are + multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file in secret, + `ca.crt` for example + type: string + certName: + description: CertName represents the data name of cert file in + secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of key file in secret, + `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required secret + resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace of required + secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + type: object + status: + description: PodHttpChaosStatus defines the actual state of PodHttpChaos. + properties: + failedMessage: + type: string + observedGeneration: + format: int64 + type: integer + pid: + description: Pid represents a running tproxy process id. + format: int64 + type: integer + startTime: + description: StartTime represents the start time of a tproxy process. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: podiochaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: PodIOChaos + listKind: PodIOChaosList + plural: podiochaos + singular: podiochaos + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PodIOChaos is the Schema for the podiochaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PodIOChaosSpec defines the desired state of IOChaos + properties: + actions: + description: Actions are a list of IOChaos actions + items: + description: IOChaosAction defines a possible action of IOChaos + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + faults: + description: Faults represents the fault to inject + items: + description: IoFault represents the fault to inject and their + weight + properties: + errno: + format: int32 + type: integer + weight: + format: int32 + type: integer + required: + - errno + - weight + type: object + type: array + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + latency: + description: Latency represents the latency to inject + type: string + methods: + description: Methods represents the method that the action will + inject in + items: + type: string + type: array + mistake: + description: MistakeSpec represents the mistake to inject + properties: + filling: + description: Filling determines what is filled in the mistake + data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + path: + description: Path represents a glob of injecting path + type: string + percent: + description: Percent represents the percent probability of injecting + this action + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + source: + description: Source represents the source of current rules + type: string + type: + description: IOChaosType represents the type of IOChaos Action + type: string + uid: + format: int32 + type: integer + required: + - path + - percent + - type + type: object + type: array + container: + description: 'TODO: support multiple different container to inject + in one pod' + type: string + volumeMountPath: + description: 'VolumeMountPath represents the target mount path It + must be a root of mount path now. TODO: search the mount parent + of any path automatically. TODO: support multiple different volume + mount path in one pod' + type: string + required: + - volumeMountPath + type: object + status: + properties: + failedMessage: + type: string + observedGeneration: + format: int64 + type: integer + pid: + description: Pid represents a running toda process id + format: int64 + type: integer + startTime: + description: StartTime represents the start time of a toda process + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: podnetworkchaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: PodNetworkChaos + listKind: PodNetworkChaosList + plural: podnetworkchaos + singular: podnetworkchaos + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PodNetworkChaos is the Schema for the PodNetworkChaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a pod chaos experiment + properties: + ipsets: + description: The ipset on the pod + items: + description: RawIPSet represents an ipset on specific pod + properties: + cidrAndPorts: + description: The contents of ipset. Only available when IPSetType + is NetPortIPSet. + items: + description: CidrAndPort represents CIDR and port pair + properties: + cidr: + type: string + port: + maximum: 65535 + minimum: 1 + type: integer + required: + - cidr + - port + type: object + type: array + cidrs: + description: The contents of ipset. Only available when IPSetType + is NetIPSet. + items: + type: string + type: array + ipsetType: + description: IPSetType represents the type of IP set + type: string + name: + description: The name of ipset + type: string + setNames: + description: The contents of ipset. Only available when IPSetType + is SetIPSet. + items: + type: string + type: array + source: + type: string + required: + - ipsetType + - name + - source + type: object + type: array + iptables: + description: The iptables rules on the pod + items: + description: RawIptables represents the iptables rules on specific + pod + properties: + device: + description: Device represents the network device to be affected. + type: string + direction: + description: The block direction of this iptables rule + type: string + ipsets: + description: The name of related ipset + items: + type: string + nullable: true + type: array + name: + description: The name of iptables chain + type: string + source: + type: string + required: + - direction + - name + - source + type: object + type: array + tcs: + description: The tc rules on the pod + items: + description: RawTrafficControl represents the traffic control chaos + on specific pod + properties: + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes that + tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be queued + waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate + bucket. For perfect accuracy, should be set to the MTU + of the interface. If a peakrate is needed, but some burstiness + is acceptable, this size can be raised. A 3000 byte minburst + allows around 3mbit/s of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of the + bucket. The peakrate does not need to be set, it is only + necessary if perfect millisecond timescale shaping is + required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + duplicate: + description: DuplicateSpec represents the detail about loss + action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + ipset: + description: The name of target ipset + type: string + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + rate: + description: Rate represents the detail about rate control action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - rate + type: object + source: + description: The name and namespace of the source network chaos + type: string + type: + description: The type of traffic control + type: string + required: + - source + - type + type: object + type: array + type: object + status: + description: Most recently observed status of the chaos experiment about + pods + properties: + failedMessage: + type: string + observedGeneration: + format: int64 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: remoteclusters.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: RemoteCluster + listKind: RemoteClusterList + plural: remoteclusters + singular: remotecluster + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: RemoteCluster defines a remote cluster + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: RemoteClusterSpec defines the specification of a remote cluster + properties: + configOverride: + type: object + x-kubernetes-preserve-unknown-fields: true + kubeConfig: + description: RemoteClusterKubeConfig refers to a secret by which we'll + use to connect remote cluster + properties: + secretRef: + description: RemoteClusterSecretRef refers to a secret in any + namespaces + properties: + key: + type: string + name: + type: string + namespace: + type: string + required: + - key + - name + - namespace + type: object + required: + - secretRef + type: object + namespace: + type: string + version: + type: string + required: + - kubeConfig + - namespace + - version + type: object + status: + properties: + conditions: + description: Conditions represents the current condition of the remote + cluster + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + currentVersion: + type: string + observedGeneration: + format: int64 + type: integer + required: + - currentVersion + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: schedules.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: Schedule + listKind: ScheduleList + plural: schedules + singular: schedule + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Schedule is the cronly schedule object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ScheduleSpec is the specification of a schedule object + properties: + awsChaos: + description: AWSChaosSpec is the content of the specification for + an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. Supported + action: ec2-stop / ec2-restart / detach-volume Default action: + ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. Needed + in detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws server. + Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. Needed + in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification for + an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. + Supported action: vm-stop / vm-restart / disk-detach Default + action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. Needed in + disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the data + disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification for + a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. + Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every io request. + type: string + type: object + duration: + description: Duration represents the duration of the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + default: Forbid + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos action. Supported + action: error, random Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, support + the placeholder ? and wildcard *, or the Specified domain name. + Note: 1. The wildcard * must be at the end of the string. For + example, chaos-*.org is invalid. 2. if the patterns is empty, + will take effect on all the domain names. For example: The value + is ["google.com", "github.*", "chaos-mes?.org"], will take effect + on "google.com", "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification for + a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. Supported + action: node-stop / node-reset / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status code + in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, such + as "300ms", "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + method: + description: Method is a rule to select target by http method + in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of target. + properties: + type: + description: Type represents the patch type, only support + `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers of + target. For example: `[["Set-Cookie", ""], ["Set-Cookie", + ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries of target(Request + only). For example: `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri path in http + request. + type: string + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents in target. + properties: + body: + description: Body is a rule to replace http message body in + target. + format: byte + type: string + code: + description: Code is a rule to replace http status code in + response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers of + target. The key-value pairs represent header name and header + value pairs. + type: object + method: + description: Method is a rule to replace http method in request. + type: string + path: + description: Path is rule to to replace uri path in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries in + http request. For example, with value `{ "foo": "unknown" + }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target by http + headers in request. The key-value pairs represent header name + and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target by http + headers in response. The key-value pairs represent header name + and header value pairs. + type: object + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file in + secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name of cert file + in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of key file + in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required secret + resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace of required + secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action delay. + A delay string is a possibly signed sequence of decimal numbers, + each with optional fraction and a unit suffix, such as "300ms". + Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that returned by I/O + action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting I/O + chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness are injected + to IO operations + properties: + filling: + description: Filling determines what is filled in the mistake + data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments of + wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting I/O + chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection errors + and provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected + volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. Supported + action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only set it when + action is stress + type: integer + database: + description: the match database default value is "", means match + all database + type: string + duration: + description: Duration represents the duration of the chaos action + type: string + exception: + description: the exception which needs to throw for action `exception` + or the exception message needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', unit ms + or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will generate + one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", means match + all SQL type. The value can be 'select', 'insert', 'update', + 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call chain, such + as: ext4_mount -> mount_subtree -> ... -> should_failslab + With an optional set of predicates and an optional set of + parameters, which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep Callchain + empty, which means it will fail at any call chain with slab + alloc (eg: kmalloc).' + items: + description: Frame defines the function signature and predicate + in function's body + properties: + funcname: + description: Funcname can be find from kernel source + or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, for + example, if you want to inject slab error in `d_alloc_parallel(struct + dentry *parent, const struct qstr *name)` with a special + name `bananas`, you need to set it to `struct dentry + *parent, const struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments of + this Frame, example with Parameters's, you can set + it to `STRNCMP(name->name, "bananas", 8)` to make + inject only with it, or omit it to inject for all + d_alloc_parallel call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be set + to ''0'' / ''1'' / ''2'' If `0`, indicates slab to fail + (should_failslab) If `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) You can + read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel headers + you need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so + on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos action. + Supported action: partition, netem, delay, loss, duplicate, + corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth control + action + properties: + buffer: + description: Buffer is the maximum amount of bytes that tokens + can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be queued + waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate bucket. + For perfect accuracy, should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness is acceptable, + this size can be raised. A 3000 byte minburst allows around + 3mbit/s of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of the + bucket. The peakrate does not need to be set, it is only + necessary if perfect millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies + on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets outside + k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this applies on + netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device to be + affected in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired state of + PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one of Address + and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock on which + to act. More clock description in linux kernel can be found + in man page of clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the file. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + delay: + description: Delay represents the delay of the target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for action + `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', unit + ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", means + match all database + type: string + exception: + description: The exception which needs to throw for action + `exception` or the exception message needs to throw in action + `mysql` + type: string + latency: + description: The latency duration for action 'latency' or + the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, will + use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set it + when action is stress + type: integer + mem-type: + description: the memory type need to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can + be accepted, others will be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf with + this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads to + run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP address + type: string + rate: + description: The speed of network traffic, allows bps, kbps, + mbps, gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can + be accepted, others will be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values can + be 'from', 'to'. 'from' means packets coming from the 'IPAddress' + or 'Hostname' and going to your server, 'to' means packets + originating from your server and going to the 'IPAddress' + or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of the original + value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string keys and + a set values that used to select physical machines. The + key defines the namespace which physical machine belong, + and each value is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. 0 + is effectively a sleep (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, default + is the total available memory. One can specify the size + as % of total available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify + the percent of physical machines the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify + the max percent of pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a user creates + on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: pod-kill / pod-failure / container-kill Default action: + pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It represents + the duration in seconds before the pod should be deleted. Value + must be non-negative integer. The default value is zero that + indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + exclusiveMinimum: true + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors just + like `Stressors` except that it's an experimental feature and + more powerful. You can define stressors in `stress-ng` (see + also `man stress-ng`) dialect, however not all of the supported + stressors are well tested. It maybe retired in later releases. + You should always use `Stressors` to define the stressors and + use this only when you want more stressors unsupported by `Stressors`. + When both `StressngStressors` and `Stressors` are defined, `StressngStressors` + wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported to + stress system components out. You can use one or more of them + to make up various kinds of stresses. At least one of the stressors + should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading per CPU + worker. 0 is effectively a sleep (no load) and 100 is + full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to apply the + stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj of the + stress process. See `man 5 proc` to know more about + this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per vm worker, + default is the total available memory. One can specify + the size as % of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to apply the + stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id All available + options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected program. + It's a possibly signed sequence of decimal numbers, such as + "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + workflow: + properties: + entry: + type: string + templates: + items: + properties: + abortWithStatusCheck: + description: AbortWithStatusCheck describe whether to abort + the workflow when the failure threshold of StatusCheck + is exceeded. Only used when Type is TypeStatusCheck. + type: boolean + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos + action. Supported action: ec2-stop / ec2-restart / + detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. + Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 + instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the + aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. + Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos + action. Supported action: vm-stop / vm-restart / disk-detach + Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. + Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of + the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure + subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos + action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every + io request. + type: string + type: object + duration: + description: Duration represents the duration of the + chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + children: + description: Children describes the children steps of serial + or parallel node. Only used when Type is TypeSerial or + TypeParallel. + items: + type: string + type: array + conditionalBranches: + description: ConditionalBranches describes the conditional + branches of custom tasks. Only used when Type is TypeTask. + items: + properties: + expression: + description: Expression is the expression for this + conditional branch, expected type of result is boolean. + If expression is empty, this branch will always + be selected/the template will be spawned. + type: string + target: + description: Target is the name of other template, + if expression is evaluated as true, this template + will be spawned. + type: string + required: + - target + type: object + type: array + deadline: + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos + action. Supported action: error, random Default action: + error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, + support the placeholder ? and wildcard *, or the Specified + domain name. Note: 1. The wildcard * must be at the + end of the string. For example, chaos-*.org is invalid. + 2. if the patterns is empty, will take effect on all + the domain names. For example: The value is ["google.com", + "github.*", "chaos-mes?.org"], will take effect on + "google.com", "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos + action. Supported action: node-stop / node-reset / + disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed + in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http + status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target + request/response. A duration string is a possibly + unsigned sequence of decimal numbers, each with optional + fraction and a unit suffix, such as "300ms", "2h45m". + Valid time units are "ns", "us" (or "µs"), "ms", "s", + "m", "h". + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + method: + description: Method is a rule to select target by http + method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. + properties: + body: + description: Body is a rule to patch message body + of target. + properties: + type: + description: Type represents the patch type, + only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", + "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri + path in http request. + type: string + port: + description: Port represents the target port to be proxy + of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http message + body in target. + format: byte + type: string + code: + description: Code is a rule to replace http status + code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header + name and header value pairs. + type: object + method: + description: Method is a rule to replace http method + in request. + type: string + path: + description: Path is rule to to replace uri path + in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": + "unknown" }`, the `/?foo=bar` will be altered + to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target + by http headers in request. The key-value pairs represent + header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target + by http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and + injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of + ca file in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name of + cert file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of + key file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required + secret resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace + of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: latency / fault / attrOverride + / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action + delay. A delay string is a possibly signed sequence + of decimal numbers, each with optional fraction and + a unit suffix, such as "300ms". Valid time units are + "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the + chaos action. It is required when the action is `PodFailureAction`. + 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". + type: string + errno: + description: 'Errno defines the error code that returned + by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting + I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled in + the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment + in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting + I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection + errors and provides a number from 0-100. default: + 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path of + injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos + action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only + set it when action is stress + type: integer + database: + description: the match database default value is "", + means match all database + type: string + duration: + description: Duration represents the duration of the + chaos action + type: string + exception: + description: the exception which needs to throw for + action `exception` or the exception message needs + to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set + it when action is stress, the value can be 'stack' + or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only + support 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and + will generate one if not set + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", + means match all SQL type. The value can be 'select', + 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of + KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of + kernel injection + properties: + callchain: + description: 'Callchain indicate a special call + chain, such as: ext4_mount -> mount_subtree -> + ... -> should_failslab With an optional set of + predicates and an optional set of parameters, + which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just + keep Callchain empty, which means it will fail + at any call chain with slab alloc (eg: kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from kernel + source or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab + error in `d_alloc_parallel(struct dentry + *parent, const struct qstr *name)` with + a special name `bananas`, you need to set + it to `struct dentry *parent, const struct + qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments + of this Frame, example with Parameters's, + you can set it to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, or omit + it to inject for all d_alloc_parallel call + chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can + be set to ''0'' / ''1'' / ''2'' If `0`, indicates + slab to fail (should_failslab) If `1`, indicates + alloc_page to fail (should_fail_alloc_page) If + `2`, indicates bio to fail (should_fail_bio) You + can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with + probability. If you want 1%, please set this field + with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + name: + type: string + networkChaos: + description: NetworkChaosSpec defines the desired state + of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos + action. Supported action: partition, netem, delay, + loss, duplicate, corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes + that tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can + be queued waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the + peakrate bucket. For perfect accuracy, should + be set to the MTU of the interface. If a peakrate + is needed, but some burstiness is acceptable, + this size can be raised. A 3000 byte minburst + allows around 3mbit/s of peakrate, given 1000 + byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate + of the bucket. The peakrate does not need to be + set, it is only necessary if perfect millisecond + timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, + kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, + tbps unit. bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt + action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay + action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet + reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to + be affected. + type: string + direction: + default: to + description: Direction represents the direction, this + applies on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about + loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the + chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets + outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control + action + properties: + rate: + description: Rate is the speed knob. Allows bit, + kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, + tbps unit. bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this + applies on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device + to be affected in target scope. + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired + state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only + one of Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock + on which to act. More clock description in linux + kernel can be found in man page of clock_getres, + clock_gettime, clock_settime. Muti clock ids should + be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + payload-process-num: + description: specifies the number of process work + on writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + payload-process-num: + description: specifies the number of process work + on writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the + chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to append + the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to + be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of + the file. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file + to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the + file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by + http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP + connection, we will only attack HTTP connection + with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by + http status code in response + type: string + delay: + description: Delay represents the delay of the target + request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP + connection, we will only attack HTTP connection + with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support + GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw + for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', + unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is + "", means match all database + type: string + exception: + description: The exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' + or the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set to + "8") now + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is + "", means match all SQL type. The value can be + 'select', 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", + means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's + data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only + set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, only + set it when action is stress, the value can be + 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp + flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used for + partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or + µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf + test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client + threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the + IP address + type: string + rate: + description: The speed of network traffic, allows + bps, kbps, mbps, gbps, tbps unit. bps means bytes + per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is + 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp + flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used for + partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means packets + coming from the 'IPAddress' or 'Hostname' and + going to your server, 'to' means packets originating + from your server and going to the 'IPAddress' + or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these + IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering + experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string + keys and a set values that used to select physical + machines. The key defines the namespace which + physical machine belong, and each value is a set + of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU + worker. 0 is effectively a sleep (no load) and + 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, + default is the total available memory. One can + specify the size as % of total available memory + or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of physical machines + to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of physical + machines the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a + user creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: pod-kill / pod-failure / + container-kill Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action. It is required when the action is `PodFailureAction`. + 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. + It represents the duration in seconds before the pod + should be deleted. Value must be non-negative integer. + The default value is zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + description: Schedule describe the Schedule(describing scheduled + chaos) to be injected with chaos nodes. Only used when + Type is TypeSchedule. + properties: + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos + action. Supported action: ec2-stop / ec2-restart + / detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the + device. Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the + ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of + the aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS + volume. Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure + chaos action. Supported action: vm-stop / vm-restart + / disk-detach Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the + disk. Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number + of the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name + of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure + subscription. + type: string + vmName: + description: VMName defines the name of Virtual + Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block + chaos action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of + every io request. + type: string + type: object + duration: + description: Duration represents the duration of + the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state + of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos + action. Supported action: error, random Default + action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take + effect, support the placeholder ? and wildcard + *, or the Specified domain name. Note: 1. The + wildcard * must be at the end of the string. For + example, chaos-*.org is invalid. 2. if the patterns + is empty, will take effect on all the domain names. + For example: The value is ["google.com", "github.*", + "chaos-mes?.org"], will take effect on "google.com", + "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos + action. Supported action: node-stop / node-reset + / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. + Needed in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by + http status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target + request/response. A duration string is a possibly + unsigned sequence of decimal numbers, each with + optional fraction and a unit suffix, such as "300ms", + "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + method: + description: Method is a rule to select target by + http method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. + properties: + body: + description: Body is a rule to patch message + body of target. + properties: + type: + description: Type represents the patch type, + only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http + headers of target. For example: `[["Set-Cookie", + ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri + queries of target(Request only). For example: + `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by + uri path in http request. + type: string + port: + description: Port represents the target port to + be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http + message body in target. + format: byte + type: string + code: + description: Code is a rule to replace http + status code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http + headers of target. The key-value pairs represent + header name and header value pairs. + type: object + method: + description: Method is a rule to replace http + method in request. + type: string + path: + description: Path is rule to to replace uri + path in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri + queries in http request. For example, with + value `{ "foo": "unknown" }`, the `/?foo=bar` + will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select + target by http headers in request. The key-value + pairs represent header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select + target by http headers in response. The key-value + pairs represent header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected + and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override + PodHttpChaos if there are multiple HTTPChaos experiments + are applied + properties: + caName: + description: CAName represents the data name + of ca file in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name + of cert file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name + of key file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name + of required secret resource + type: string + secretNamespace: + description: SecretNamespace represents the + namespace of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of + IOChaos + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: latency / fault / attrOverride + / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos + action delay. A delay string is a possibly signed + sequence of decimal numbers, each with optional + fraction and a unit suffix, such as "300ms". Valid + time units are "ns", "us" (or "µs"), "ms", "s", + "m", "h". + type: string + duration: + description: Duration represents the duration of + the chaos action. It is required when the action + is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that + returned by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for + injecting I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled + in the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment + in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] + segments of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for + injecting I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of + injection errors and provides a number from 0-100. + default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path + of injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state + of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos + action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only + set it when action is stress + type: integer + database: + description: the match database default value is + "", means match all database + type: string + duration: + description: Duration represents the duration of + the chaos action + type: string + exception: + description: the exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only + set it when action is stress, the value can be + 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set to + "8") now + type: string + name: + description: byteman rule name, should be unique, + and will generate one if not set + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action + 'ruleData' + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is + "", means match all SQL type. The value can be + 'select', 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", + means match all table + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state + of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request + of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call + chain, such as: ext4_mount -> mount_subtree + -> ... -> should_failslab With an optional + set of predicates and an optional set of parameters, + which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just + keep Callchain empty, which means it will + fail at any call chain with slab alloc (eg: + kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from + kernel source or `/proc/kallsyms`, such + as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab + error in `d_alloc_parallel(struct dentry + *parent, const struct qstr *name)` with + a special name `bananas`, you need to + set it to `struct dentry *parent, const + struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the + arguments of this Frame, example with + Parameters's, you can set it to `STRNCMP(name->name, + "bananas", 8)` to make inject only with + it, or omit it to inject for all d_alloc_parallel + call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, + can be set to ''0'' / ''1'' / ''2'' If `0`, + indicates slab to fail (should_failslab) If + `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) + You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails + with probability. If you want 1%, please set + this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of + fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state + of NetworkChaos + properties: + action: + description: 'Action defines the specific network + chaos action. Supported action: partition, netem, + delay, loss, duplicate, corrupt Default action: + delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about + bandwidth control action + properties: + buffer: + description: Buffer is the maximum amount of + bytes that tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that + can be queued waiting for tokens to become + available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of + the peakrate bucket. For perfect accuracy, + should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness + is acceptable, this size can be raised. A + 3000 byte minburst allows around 3mbit/s of + peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion + rate of the bucket. The peakrate does not + need to be set, it is only necessary if perfect + millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about + corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay + action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of + packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device + to be affected. + type: string + direction: + default: to + description: Direction represents the direction, + this applies on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail + about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of + the chaos action + type: string + externalTargets: + description: ExternalTargets represents network + targets outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss + action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate + control action + properties: + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this + applies on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network + device to be affected in target scope. + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired + state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. + Only one of Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular + clock on which to act. More clock description + in linux kernel can be found in man page of + clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 is + valid value + type: integer + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 is + valid value + type: integer + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of + the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to + append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to + create or delete. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to + create or delete. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + privilege: + description: Privilege is the file privilege + to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to + be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string + of the file. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + line: + description: Line is the line number of the + file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string + of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of + HTTP connection, we will only attack HTTP + connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + delay: + description: Delay represents the delay of the + target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of + HTTP connection, we will only attack HTTP + connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support + GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw + for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action + 'latency', unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value + is "", means match all database + type: string + exception: + description: The exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action + 'latency' or the latency duration in action + `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set + to "8") now + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value + is "", means match all SQL type. The value + can be 'select', 'insert', 'update', 'delete', + 'replace'. + type: string + table: + description: the match table default value is + "", means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule + file's data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, + only set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, + only set it when action is stress, the value + can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the + tcp flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used + for partition. + type: string + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: + ns, us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the + iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client + threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on + the IP address + type: string + rate: + description: The speed of network traffic, allows + bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the + tcp flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used + for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means packets + coming from the 'IPAddress' or 'Hostname' + and going to your server, 'to' means packets + originating from your server and going to + the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these + IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process + ID + type: string + recoverCmd: + description: the command to be run when recovering + experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical + machines that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string + keys and a set values that used to select + physical machines. The key defines the namespace + which physical machine belong, and each value + is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per + CPU worker. 0 is effectively a sleep (no load) + and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the + stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per + vm worker, default is the total available + memory. One can specify the size as % of total + available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when + attack + type: string + recoverCmd: + description: The command to be executed when + recover + type: string + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of physical + machines to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent + of physical machines the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do + chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that + a user creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: pod-kill / pod-failure + / container-kill Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action. It is required when the action + is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. + It represents the duration in seconds before the + pod should be deleted. Value must be non-negative + integer. The default value is zero that indicates + delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired state + of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of + stressors just like `Stressors` except that it's + an experimental feature and more powerful. You + can define stressors in `stress-ng` (see also + `man stress-ng`) dialect, however not all of the + supported stressors are well tested. It maybe + retired in later releases. You should always use + `Stressors` to define the stressors and use this + only when you want more stressors unsupported + by `Stressors`. When both `StressngStressors` + and `Stressors` are defined, `StressngStressors` + wins. + type: string + stressors: + description: Stressors defines plenty of stressors + supported to stress system components out. You + can use one or more of them to make up various + kinds of stresses. At least one of the stressors + should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading + per CPU worker. 0 is effectively a sleep + (no load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 workers + can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual + memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` + to know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % + of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 workers + can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state + of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock + id All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of + injected program. It's a possibly signed sequence + of decimal numbers, such as "300ms", "-1.5h" or + "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + required: + - schedule + - type + type: object + statusCheck: + description: StatusCheck describe the behavior of StatusCheck. + Only used when Type is TypeStatusCheck. + properties: + duration: + description: Duration defines the duration of the whole + status check if the number of failed execution does + not exceed the failure threshold. Duration is available + to both `Synchronous` and `Continuous` mode. 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum consecutive + failure for the status check to be considered failed. + minimum: 1 + type: integer + http: + properties: + body: + type: string + criteria: + description: Criteria defines how to determine the + result of the status check. + properties: + statusCode: + description: StatusCode defines the expected + http status code for the request. A statusCode + string could be a single code (e.g. 200), + or an inclusive range (e.g. 200-400, both + `200` and `400` are included). + type: string + required: + - statusCode + type: object + headers: + additionalProperties: + items: + type: string + type: array + description: "A Header represents the key-value + pairs in an HTTP header. \n The keys should be + in canonical form, as returned by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in seconds) + to perform an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of the + status check. Support type: Synchronous / Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number + of record to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum consecutive + successes for the status check to be considered successful. + SuccessThreshold only works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of seconds + after which an execution of status check times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check + type. Support type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + stressChaos: + description: StressChaosSpec defines the desired state of + StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors + just like `Stressors` except that it's an experimental + feature and more powerful. You can define stressors + in `stress-ng` (see also `man stress-ng`) dialect, + however not all of the supported stressors are well + tested. It maybe retired in later releases. You should + always use `Stressors` to define the stressors and + use this only when you want more stressors unsupported + by `Stressors`. When both `StressngStressors` and + `Stressors` are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported + to stress system components out. You can use one or + more of them to make up various kinds of stresses. + At least one of the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading + per CPU worker. 0 is effectively a sleep (no + load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to + apply the stressor. Maximum 8192 workers can + run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory + out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` to + know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % of total + available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to + apply the stressor. Maximum 8192 workers can + run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + type: object + task: + description: Task describes the behavior of the custom task. + Only used when Type is TypeTask. + properties: + container: + description: Container is the main container image to + run in the pod + properties: + args: + description: 'Arguments to the entrypoint. The container + image''s CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using + the container''s environment. If a variable cannot + be resolved, the reference in the input string + will be unchanged. Double $$ are reduced to a + single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will + never be expanded, regardless of whether the variable + exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The container image''s ENTRYPOINT is + used if this is not provided. Variable references + $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, + the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot + be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set + in the container. Cannot be updated. + items: + description: EnvVar represents an environment + variable present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined + environment variables in the container and + any service environment variables. If a + variable cannot be resolved, the reference + in the input string will be unchanged. Double + $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal + "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable + exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: + supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the + container: only resources limits and + requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret + in the pod's namespace + properties: + key: + description: The key of the secret + to select from. Must be a valid + secret key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined within + a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container + is starting. When a key exists in multiple sources, + the value associated with the last source will + take precedence. Values defined by an Env with + a duplicate key will take precedence. Cannot be + updated. + items: + description: EnvFromSource represents the source + of a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be a + C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config + management to default or override container images + in workload controllers like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, + Never, IfNotPresent. Defaults to Always if :latest + tag is specified, or IfNotPresent otherwise. Cannot + be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system + should take in response to container lifecycle + events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately + after a container is created. If the handler + fails, the container is terminated and restarted + according to its restart policy. Other management + of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT + supported as a LifecycleHandler and kept + for the backward compatibility. There + are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler + is specified. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately + before a container is terminated due to an + API request or management event such as liveness/startup + probe failure, preemption, resource contention, + etc. The handler is not called if the container + crashes or exits. The Pod''s termination grace + period countdown begins before the PreStop + hook is executed. Regardless of the outcome + of the handler, the container will eventually + terminate within the Pod''s termination grace + period (unless delayed by finalizers). Other + management of the container blocks until the + hook completes or until the termination grace + period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT + supported as a LifecycleHandler and kept + for the backward compatibility. There + are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler + is specified. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as + a DNS_LABEL. Each container in a pod must have + a unique name (DNS_LABEL). Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. + Not specifying a port here DOES NOT prevent that + port from being exposed. Any port which is listening + on the default "0.0.0.0" address inside a container + will be accessible from the network. Modifying + this array with strategic merge patch may corrupt + the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network + port in a single container. + properties: + containerPort: + description: Number of port to expose on the + pod's IP address. This must be a valid port + number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on the + host. If specified, this must be a valid + port number, 0 < x < 65536. If HostNetwork + is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an + IANA_SVC_NAME and unique within the pod. + Each named port in a pod must have a unique + name. Name for the port that can be referred + to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, + TCP, or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service + readiness. Container will be removed from service + endpoints if the probe fails. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents + resource resize policy for the container. + properties: + resourceName: + description: 'Name of the resource to which + this resource resize policy applies. Supported + values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when + specified resource is resized. If not specified, + it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this + container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, + defined in spec.resourceClaims, that are used + by this container. \n This is an alpha field + and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. + It can only be set for containers." + items: + description: ResourceClaim references one + entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available inside + a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. If Requests + is omitted for a container, it defaults to + Limits if that is explicitly specified, otherwise + to an implementation-defined value. Requests + cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + restartPolicy: + description: 'RestartPolicy defines the restart + behavior of individual containers in a pod. This + field may only be set for init containers, and + the only allowed value is "Always". For non-init + containers or when this field is not specified, + the restart behavior is defined by the Pod''s + restart policy and the container type. Setting + the RestartPolicy as "Always" for the init container + will have the following effect: this init container + will be continually restarted on exit until all + regular containers have terminated. Once all regular + containers have completed, all init containers + with restartPolicy "Always" will be shut down. + This lifecycle differs from normal init containers + and is often referred to as a "sidecar" container. + Although this init container still starts in the + init container sequence, it does not wait for + the container to complete before proceeding to + the next init container. Instead, the next init + container starts immediately after this init container + is started, or after any startupProbe has successfully + completed.' + type: string + securityContext: + description: 'SecurityContext defines the security + options the container should be run with. If set, + the fields of SecurityContext override the equivalent + fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges + than its parent process. This bool directly + controls if the no_new_privs flag will be + set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run + as Privileged 2) has CAP_SYS_ADMIN Note that + this field cannot be set when spec.os.name + is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when + running containers. Defaults to the default + set of capabilities granted by the container + runtime. Note that this field cannot be set + when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. + Processes in privileged containers are essentially + equivalent to root on the host. Defaults to + false. Note that this field cannot be set + when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc + mount to use for the containers. The default + is DefaultProcMount which uses the container + runtime defaults for readonly paths and masked + paths. This requires the ProcMountType feature + flag to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only + root filesystem. Default is false. Note that + this field cannot be set when spec.os.name + is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of + the container process. Uses runtime default + if unset. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must + run as a non-root user. If true, the Kubelet + will validate the image at runtime to ensure + that it does not run as UID 0 (root) and fail + to start the container if it does. If unset + or false, no such validation will be performed. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of + the container process. Defaults to user specified + in image metadata if unspecified. May also + be set in PodSecurityContext. If set in both + SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied + to the container. If unspecified, the container + runtime will allocate a random SELinux context + for each container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label + that applies to the container. + type: string + role: + description: Role is a SELinux role label + that applies to the container. + type: string + type: + description: Type is a SELinux type label + that applies to the container. + type: string + user: + description: User is a SELinux user label + that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this + container. If seccomp options are provided + at both the pod & container level, the container + options override the pod options. Note that + this field cannot be set when spec.os.name + is windows. + properties: + localhostProfile: + description: localhostProfile indicates + a profile defined in a file on the node + should be used. The profile must be preconfigured + on the node to work. Must be a descending + path, relative to the kubelet's configured + seccomp profile location. Must be set + if type is "Localhost". Must NOT be set + for any other type. + type: string + type: + description: "type indicates which kind + of seccomp profile will be applied. Valid + options are: \n Localhost - a profile + defined in a file on the node should be + used. RuntimeDefault - the container runtime + default profile should be used. Unconfined + - no profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options + from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where + the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName + field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the + name of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a + container should be run as a 'Host Process' + container. All of a Pod's containers must + have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess + containers and non-HostProcess containers). + In addition, if HostProcess is true then + HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to + run the entrypoint of the container process. + Defaults to the user specified in image + metadata if unspecified. May also be set + in PodSecurityContext. If set in both + SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the Pod + has successfully initialized. If specified, no + other probes are executed until this completes + successfully. If this probe fails, the Pod will + be restarted, just as if the livenessProbe failed. + This can be used to provide different probe parameters + at the beginning of a Pod''s lifecycle, when it + might take a long time to load data or warm a + cache, than during steady-state operation. This + cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. If + this is not set, reads from stdin in the container + will always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should + close the stdin channel after it has been opened + by a single attach. When stdin is true the stdin + stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is + opened on container start, is empty until the + first client attaches to stdin, and then remains + open and accepts data until the client disconnects, + at which time stdin is closed and remains closed + until the container is restarted. If this flag + is false, a container processes that reads from + stdin will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to + which the container''s termination message will + be written is mounted into the container''s filesystem. + Message written is intended to be brief final + status, such as an assertion failure message. + Will be truncated by the node if greater than + 4096 bytes. The total message length across all + containers will be limited to 12kb. Defaults to + /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message + should be populated. File will use the contents + of terminationMessagePath to populate the container + status message on both success and failure. FallbackToLogsOnError + will use the last chunk of container log output + if the termination message file is empty and the + container exited with an error. The log output + is limited to 2048 bytes or 80 lines, whichever + is smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be + true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block + devices to be used by the container. + items: + description: volumeDevice describes a mapping + of a raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside + of the container that the device will be + mapped to. + type: string + name: + description: name must match the name of a + persistentVolumeClaim in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting + of a Volume within a container. + properties: + mountPath: + description: Path within the container at + which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how + mounts are propagated from the host to container + and the other way around. When not set, + MountPropagationNone is used. This field + is beta in 1.10. + type: string + name: + description: This must match the Name of a + Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write + otherwise (false or unspecified). Defaults + to false. + type: boolean + subPath: + description: Path within the volume from which + the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume + from which the container's volume should + be mounted. Behaves similarly to SubPath + but environment variable references $(VAR_NAME) + are expanded using the container's environment. + Defaults to "" (volume's root). SubPathExpr + and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not + specified, the container runtime's default will + be used, which might be configured in the container + image. Cannot be updated. + type: string + required: + - name + type: object + volumes: + description: Volumes is a list of volumes that can be + mounted by containers in a template. + items: + description: Volume represents a named volume in a + pod that may be accessed by any container in the + pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents + an AWS Disk resource that is attached to a kubelet''s + host machine and then exposed to the pod. More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in + the volume that you want to mount. If omitted, + the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify + the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can + leave the property empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force + the readOnly setting in VolumeMounts. More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the + persistent disk resource in AWS (Amazon + EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data + Disk mount on the host and bind mount to the + pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching + mode: None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data + disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk + in the blob storage + type: string + fsType: + description: fsType is Filesystem type to + mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: + multiple blob disks per storage account Dedicated: + single blob disk per storage account Managed: + azure managed data disk (only in managed + availability set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File + Service mount on the host and bind mount to + the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret + that contains Azure Storage Account Name + and Key + type: string + shareName: + description: shareName is the azure share + Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount + on the host that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors + is a collection of Ceph monitors More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the + mounted root, rather than the full Ceph + tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile + is the path to key ring for User, default + is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef + is reference to the authentication secret + for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the + rados user name, default is admin More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume + attached and mounted on kubelets host machine. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points + to a secret object containing parameters + used to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the + volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap + that should populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode + bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. + Directories within the path are not affected + by this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced + ConfigMap will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the ConfigMap, the volume setup will + error unless it is marked optional. Paths + must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether the + ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) + represents ephemeral storage that is handled + by certain external CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI + driver that handles this volume. Consult + with your admin for the correct name as + registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", + "xfs", "ntfs". If not provided, the empty + value is passed to the associated CSI driver + which will determine the default filesystem + to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference + to the secret object containing sensitive + information to pass to the CSI driver to + complete the CSI NodePublishVolume and NodeUnpublishVolume + calls. This field is optional, and may + be empty if no secret is required. If the + secret object contains more than one secret, + all secret references are passed. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only + configuration for the volume. Defaults to + false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. + Consult your driver's documentation for + supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API + about the pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on + created files by default. Must be a Optional: + mode bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. + Directories within the path are not affected + by this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + items: + description: Items is a list of downward API + volume file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used + to set permissions on this file, must + be an octal value between 0000 and + 0777 or a decimal value between 0 + and 511. YAML accepts both octal and + decimal values, JSON requires decimal + values for mode bits. If not specified, + the volume defaultMode will be used. + This might be in conflict with other + options that affect the file mode, + like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file to + be created. Must not be absolute or + contain the ''..'' path. Must be utf-8 + encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env + vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary + directory that shares a pod''s lifetime. More + info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type + of storage medium should back this directory. + The default is "" which means to use the + node''s default medium. Must be an empty + string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount + of local storage required for this EmptyDir + volume. The size limit is also applicable + for memory medium. The maximum usage on + memory medium EmptyDir would be the minimum + value between the SizeLimit specified here + and the sum of memory limits of all containers + in a pod. The default is nil which means + that the limit is undefined. More info: + https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume that + is handled by a cluster storage driver. The + volume's lifecycle is tied to the pod that defines + it - it will be created before the pod starts, + and deleted when the pod is removed. \n Use + this if: a) the volume is only needed while + the pod runs, b) features of normal volumes + like restoring from snapshot or capacity tracking + are needed, c) the storage driver is specified + through a storage class, and d) the storage + driver supports dynamic volume provisioning + through a PersistentVolumeClaim (see EphemeralVolumeSource + for more information on the connection between + this volume type and PersistentVolumeClaim). + \n Use PersistentVolumeClaim or one of the vendor-specific + APIs for volumes that persist for longer than + the lifecycle of an individual pod. \n Use CSI + for light-weight local ephemeral volumes if + the CSI driver is meant to be used that way + - see the documentation of the driver for more + information. \n A pod can use both types of + ephemeral volumes and persistent volumes at + the same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone + PVC to provision the volume. The pod in + which this EphemeralVolumeSource is embedded + will be the owner of the PVC, i.e. the PVC + will be deleted together with the pod. The + name of the PVC will be `-` where `` is the name + from the `PodSpec.Volumes` array entry. + Pod validation will reject the pod if the + concatenated name is not valid for a PVC + (for example, too long). \n An existing + PVC with that name that is not owned by + the pod will *not* be used for the pod to + avoid using an unrelated volume by mistake. + Starting the pod is then blocked until the + unrelated PVC is removed. If such a pre-created + PVC is meant to be used by the pod, the + PVC has to updated with an owner reference + to the pod once the pod exists. Normally + this should not be necessary, but it may + be useful when manually reconstructing a + broken cluster. \n This field is read-only + and no changes will be made by Kubernetes + to the PVC after it has been created. \n + Required, must not be nil." + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when + creating it. No other fields are allowed + and will be rejected during validation. + type: object + spec: + description: The specification for the + PersistentVolumeClaim. The entire content + is copied unchanged into the PVC that + gets created from this template. The + same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: 'accessModes contains + the desired access modes the volume + should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can + be used to specify either: * An + existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external + controller can support the specified + data source, it will create a new + volume based on the contents of + the specified data source. When + the AnyVolumeDataSource feature + gate is enabled, dataSource contents + will be copied to dataSourceRef, + and dataSourceRef contents will + be copied to dataSource when dataSourceRef.namespace + is not specified. If the namespace + is specified, then dataSourceRef + will not be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, + the specified Kind must be in + the core API group. For any + other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies + the object from which to populate + the volume with data, if a non-empty + volume is desired. This may be any + object from a non-empty API group + (non core object) or a PersistentVolumeClaim + object. When this field is specified, + volume binding will only succeed + if the type of the specified object + matches some installed volume populator + or dynamic provisioner. This field + will replace the functionality of + the dataSource field and as such + if both fields are non-empty, they + must have the same value. For backwards + compatibility, when namespace isn''t + specified in dataSourceRef, both + fields (dataSource and dataSourceRef) + will be set to the same value automatically + if one of them is empty and the + other is non-empty. When namespace + is specified in dataSourceRef, dataSource + isn''t set to the same value and + must be empty. There are three important + differences between dataSource and + dataSourceRef: * While dataSource + only allows two specific types of + objects, dataSourceRef allows any + non-core object, as well as PersistentVolumeClaim + objects. * While dataSource ignores + disallowed values (dropping them), + dataSourceRef preserves all values, + and generates an error if a disallowed + value is specified. * While dataSource + only allows local objects, dataSourceRef + allows objects in any namespaces. + (Beta) Using this field requires + the AnyVolumeDataSource feature + gate to be enabled. (Alpha) Using + the namespace field of dataSourceRef + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, + the specified Kind must be in + the core API group. For any + other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + namespace: + description: Namespace is the + namespace of resource being + referenced Note that when a + namespace is specified, a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent + namespace to allow that namespace's + owner to accept the reference. + See the ReferenceGrant documentation + for details. (Alpha) This field + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents + the minimum resources the volume + should have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed + to specify resource requirements + that are lower than previous value + but must still be higher than capacity + recorded in the status field of + the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the + names of resources, defined + in spec.resourceClaims, that + are used by this container. + \n This is an alpha field and + requires enabling the DynamicResourceAllocation + feature gate. \n This field + is immutable. It can only be + set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match + the name of one entry + in pod.spec.resourceClaims + of the Pod where this + field is used. It makes + that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes + the maximum amount of compute + resources allowed. More info: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes + the minimum amount of compute + resources required. If Requests + is omitted for a container, + it defaults to Limits if that + is explicitly specified, otherwise + to an implementation-defined + value. Requests cannot exceed + Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query + over volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a key, + and an operator that relates + the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid + operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In + or NotIn, the values array + must be non-empty. If + the operator is Exists + or DoesNotExist, the values + array must be empty. This + array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a + map of {key,value} pairs. A + single {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator + is "In", and the values array + contains only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName is + the name of the StorageClass required + by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what + type of volume is required by the + claim. Value of Filesystem is implied + when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding + reference to the PersistentVolume + backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource + that is attached to a kubelet's host machine + and then exposed to the pod. + properties: + fsType: + description: 'fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. TODO: how do we prevent + errors in the filesystem from compromising + the machine' + type: string + lun: + description: 'lun is Optional: FC target lun + number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target + worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume world + wide identifiers (wwids) Either wwids or + combination of targetWWNs and lun must be + set, but not both simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume + resource that is provisioned/attached using + an exec based plugin. + properties: + driver: + description: driver is the name of the driver + to use for this volume. + type: string + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". The default filesystem depends + on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field + holds extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef + is reference to the secret object containing + sensitive information to pass to the plugin + scripts. This may be empty if no secret + object is specified. If the secret object + contains more than one secret, all secrets + are passed to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume + attached to a kubelet's host machine. This depends + on the Flocker control service being running + properties: + datasetName: + description: datasetName is Name of the dataset + stored as metadata -> name on the dataset + for Flocker should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the + dataset. This is unique identifier of a + Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE + Disk resource that is attached to a kubelet''s + host machine and then exposed to the pod. More + info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of + the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in + the volume that you want to mount. If omitted, + the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify + the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can + leave the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the + PD resource in GCE. Used to identify the + disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the + ReadOnly setting in VolumeMounts. Defaults + to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository + at a particular revision. DEPRECATED: GitRepo + is deprecated. To provision a container with + a git repo, mount an EmptyDir into an InitContainer + that clones the repo using git, then mount the + EmptyDir into the Pod''s container.' + properties: + directory: + description: directory is the target directory + name. Must not contain or start with '..'. If + '.' is supplied, the volume directory will + be the git repository. Otherwise, if specified, + the volume will contain the git repository + in the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for + the specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name + that details Glusterfs topology. More info: + https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume + path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the + Glusterfs volume to be mounted with read-only + permissions. Defaults to false. More info: + https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing + file or directory on the host machine that is + directly exposed to the container. This is generally + used for system agents or other privileged things + that are allowed to see the host machine. Most + containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can + use host directory mounts and who can/can not + mount host directories as read/write.' + properties: + path: + description: 'path of the directory on the + host. If the path is a symlink, it will + follow the link to the real path. More info: + https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults + to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource + that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether + support iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether + support iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI + Initiator Name. If initiatorName is specified + with iscsiInterface simultaneously, new + iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified + Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface + Name that uses an iSCSI transport. Defaults + to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun + number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal + List. The portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the + ReadOnly setting in VolumeMounts. Defaults + to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret + for iSCSI target and initiator authentication + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target + Portal. The Portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL + and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the + host that shares a pod''s lifetime More info: + https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the + NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the + NFS export to be mounted with read-only + permissions. Defaults to false. More info: + https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP + address of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource + represents a reference to a PersistentVolumeClaim + in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this + volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a + PhotonController persistent disk attached and + mounted on kubelets host machine + properties: + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies + Photon Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx + volume attached and mounted on kubelets host + machine + properties: + fsType: + description: fSType represents the filesystem + type to mount Must be a filesystem type + supported by the host operating system. + Ex. "ext4", "xfs". Implicitly inferred to + be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies + a Portworx volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources + secrets, configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits + used to set permissions on created files + by default. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. Directories within the path are + not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume + projections + items: + description: Projection that may be projected + along with other supported volume types + properties: + configMap: + description: configMap information about + the configMap data to project + properties: + items: + description: items if unspecified, + each key-value pair in the Data + field of the referenced ConfigMap + will be projected into the volume + as a file whose name is the key + and content is the value. If specified, + the listed keys will be projected + into the specified paths, and + unlisted keys will not be present. + If a key is specified which is + not present in the ConfigMap, + the volume setup will error unless + it is marked optional. Paths must + be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key + to a path within a volume. + properties: + key: + description: key is the key + to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an + octal value between 0000 + and 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If + not specified, the volume + defaultMode will be used. + This might be in conflict + with other options that + affect the file mode, like + fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map + the key to. May not be an + absolute path. May not contain + the path element '..'. May + not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information + about the downwardAPI data to project + properties: + items: + description: Items is a list of + DownwardAPIVolume file + items: + description: DownwardAPIVolumeFile + represents information to create + the file containing the pod + field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only + annotations, labels, name + and namespace are supported.' + properties: + apiVersion: + description: Version of + the schema the FieldPath + is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the + field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode + bits used to set permissions + on this file, must be an + octal value between 0000 + and 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If + not specified, the volume + defaultMode will be used. + This might be in conflict + with other options that + affect the file mode, like + fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path + is the relative path name + of the file to be created. + Must not be absolute or + contain the ''..'' path. + Must be utf-8 encoded. The + first item of the relative + path must not start with + ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource + of the container: only resources + limits and requests (limits.cpu, + limits.memory, requests.cpu + and requests.memory) are + currently supported.' + properties: + containerName: + description: 'Container + name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies + the output format of + the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: + resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about + the secret data to project + properties: + items: + description: items if unspecified, + each key-value pair in the Data + field of the referenced Secret + will be projected into the volume + as a file whose name is the key + and content is the value. If specified, + the listed keys will be projected + into the specified paths, and + unlisted keys will not be present. + If a key is specified which is + not present in the Secret, the + volume setup will error unless + it is marked optional. Paths must + be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key + to a path within a volume. + properties: + key: + description: key is the key + to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an + octal value between 0000 + and 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If + not specified, the volume + defaultMode will be used. + This might be in conflict + with other options that + affect the file mode, like + fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map + the key to. May not be an + absolute path. May not contain + the path element '..'. May + not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: optional field specify + whether the Secret or its key + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is + information about the serviceAccountToken + data to project + properties: + audience: + description: audience is the intended + audience of the token. A recipient + of a token must identify itself + with an identifier specified in + the audience of the token, and + otherwise should reject the token. + The audience defaults to the identifier + of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is + the requested duration of validity + of the service account token. + As the token approaches expiration, + the kubelet volume plugin will + proactively rotate the service + account token. The kubelet will + start trying to rotate the token + if the token is older than 80 + percent of its time to live or + if the token is older than 24 + hours.Defaults to 1 hour and must + be at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative + to the mount point of the file + to project the token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount + on the host that shares a pod's lifetime + properties: + group: + description: group to map volume access to + Default is no group + type: string + readOnly: + description: readOnly here will force the + Quobyte volume to be mounted with read-only + permissions. Defaults to false. + type: boolean + registry: + description: registry represents a single + or multiple Quobyte Registry services specified + as a string as host:port pair (multiple + entries are separated with commas) which + acts as the central registry for volumes + type: string + tenant: + description: tenant owning the given Quobyte + volume in the Backend Used with dynamically + provisioned Quobyte volumes, value is set + by the plugin + type: string + user: + description: user to map volume access to + Defaults to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + image: + description: 'image is the rados image name. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring + for RBDUser. Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of + Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. + Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the + ReadOnly setting in VolumeMounts. Defaults + to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides + keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. + Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of + the ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name + of the ScaleIO Protection Domain for the + configured storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret + for ScaleIO user and other sensitive information. + If this is not provided, Login operation + will fail. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable + SSL communication with Gateway, default + false + type: boolean + storageMode: + description: storageMode indicates whether + the storage for a volume should be ThickProvisioned + or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage + Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage + system as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume + already created in the ScaleIO system that + is associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that + should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode + bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. + Directories within the path are not affected + by this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + items: + description: items If unspecified, each key-value + pair in the Data field of the referenced + Secret will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the Secret, the volume setup will error + unless it is marked optional. Paths must + be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether + the Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the + secret in the pod''s namespace to use. More + info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret + to use for obtaining the StorageOS API credentials. If + not specified, default values will be attempted. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable + name of the StorageOS volume. Volume names + are only unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the + scope of the volume within StorageOS. If + no namespace is specified then the Pod's + namespace will be used. This allows the + Kubernetes name scoping to be mirrored within + StorageOS for tighter integration. Set VolumeName + to any name to override the default behaviour. + Set to "default" if you are not using namespaces + within StorageOS. Namespaces that do not + pre-exist within StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere + volume attached and mounted on kubelets host + machine + properties: + fsType: + description: fsType is filesystem type to + mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage + Policy Based Management (SPBM) profile ID + associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage + Policy Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + templateType: + type: string + timeChaos: + description: TimeChaosSpec defines the desired state of + TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id + All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected + program. It's a possibly signed sequence of decimal + numbers, such as "300ms", "-1.5h" or "2h45m". Valid + time units are "ns", "us" (or "µs"), "ms", "s", "m", + "h". + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + required: + - name + - templateType + type: object + type: array + required: + - entry + - templates + type: object + required: + - schedule + - type + type: object + status: + description: ScheduleStatus is the status of a schedule object + properties: + active: + items: + description: "ObjectReference contains enough information to let + you inspect or modify the referred object. --- New uses of this + type are discouraged because of difficulty describing its usage + when embedded in APIs. 1. Ignored fields. It includes many fields + which are not generally honored. For instance, ResourceVersion + and FieldPath are both very rarely valid in actual usage. 2. Invalid + usage help. It is impossible to add specific help for individual + usage. In most embedded usages, there are particular restrictions + like, \"must refer only to types A and B\" or \"UID not honored\" + or \"name must be restricted\". Those cannot be well described + when embedded. 3. Inconsistent validation. Because the usages + are different, the validation rules are different by usage, which + makes it hard for users to predict what will happen. 4. The fields + are both imprecise and overly precise. Kind is not a precise + mapping to a URL. This can produce ambiguity during interpretation + and require a REST mapping. In most cases, the dependency is + on the group,resource tuple and the version of the actual struct + is irrelevant. 5. We cannot easily change it. Because this type + is embedded in many locations, updates to this type will affect + numerous schemas. Don't make new APIs embed an underspecified + API type they do not control. \n Instead of using this type, create + a locally provided and used type that is well-focused on your + reference. For example, ServiceReferences for admission registration: + https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + time: + format: date-time + nullable: true + type: string + type: object + required: + - spec + type: object + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: statuschecks.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: StatusCheck + listKind: StatusCheckList + plural: statuschecks + singular: statuscheck + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a status check + properties: + duration: + description: Duration defines the duration of the whole status check + if the number of failed execution does not exceed the failure threshold. + Duration is available to both `Synchronous` and `Continuous` mode. + 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum consecutive failure + for the status check to be considered failed. + minimum: 1 + type: integer + http: + properties: + body: + type: string + criteria: + description: Criteria defines how to determine the result of the + status check. + properties: + statusCode: + description: StatusCode defines the expected http status code + for the request. A statusCode string could be a single code + (e.g. 200), or an inclusive range (e.g. 200-400, both `200` + and `400` are included). + type: string + required: + - statusCode + type: object + headers: + additionalProperties: + items: + type: string + type: array + description: "A Header represents the key-value pairs in an HTTP + header. \n The keys should be in canonical form, as returned + by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in seconds) to perform + an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of the status check. + Support type: Synchronous / Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number of record to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum consecutive successes + for the status check to be considered successful. SuccessThreshold + only works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of seconds after which + an execution of status check times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check type. Support + type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + status: + description: Most recently observed status of status check + properties: + completionTime: + description: CompletionTime represents time when the status check + was completed. + format: date-time + type: string + conditions: + description: Conditions represents the latest available observations + of a StatusCheck's current state. + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - lastProbeTime + - lastTransitionTime + - reason + - status + - type + type: object + type: array + count: + description: Count represents the total number of the status check + executed. + format: int64 + type: integer + records: + description: Records contains the history of the execution of StatusCheck. + items: + properties: + outcome: + type: string + startTime: + format: date-time + type: string + required: + - outcome + - startTime + type: object + type: array + startTime: + description: StartTime represents time when the status check started + to execute. + format: date-time + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: stresschaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: StressChaos + listKind: StressChaosList + plural: stresschaos + singular: stresschaos + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: StressChaos is the Schema for the stresschaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a time chaos experiment + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors just like + `Stressors` except that it's an experimental feature and more powerful. + You can define stressors in `stress-ng` (see also `man stress-ng`) + dialect, however not all of the supported stressors are well tested. + It maybe retired in later releases. You should always use `Stressors` + to define the stressors and use this only when you want more stressors + unsupported by `Stressors`. When both `StressngStressors` and `Stressors` + are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported to stress + system components out. You can use one or more of them to make up + various kinds of stresses. At least one of the stressors should + be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading per CPU worker. + 0 is effectively a sleep (no load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to apply the stressor. + Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj of the stress + process. See `man 5 proc` to know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per vm worker, + default is the total available memory. One can specify the + size as % of total available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to apply the stressor. + Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - mode + - selector + type: object + status: + description: Most recently observed status of the time chaos experiment + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + instances: + additionalProperties: + description: StressInstance is an instance generates stresses + properties: + memoryStartTime: + description: MemoryStartTime specifies when the memStress starts + format: date-time + type: string + memoryUid: + description: MemoryUID is the memStress identifier + type: string + startTime: + description: StartTime specifies when the stress-ng starts + format: date-time + type: string + uid: + description: UID is the stress-ng identifier + type: string + type: object + description: Instances always specifies stressing instances + type: object + required: + - experiment + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: timechaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: TimeChaos + listKind: TimeChaosList + plural: timechaos + singular: timechaos + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.duration + name: duration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: TimeChaos is the Schema for the timechaos API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a time chaos experiment + properties: + clockIds: + description: ClockIds defines all affected clock id All available + options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to inject + chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can be + used to select objects. A list of selectors based on set-based + label expressions. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used to + select nodes. Selector which must match a node's labels, and + objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must belong + to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a pod + at the current time. supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values that + used to select pods. The key defines the namespace which pods + belong, and the each values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected program. + It's a possibly signed sequence of decimal numbers, such as "300ms", + "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", + "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide + an integer of pods to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + status: + description: Most recently observed status of the time chaos experiment + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: workflownodes.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: WorkflowNode + listKind: WorkflowNodeList + plural: workflownodes + shortNames: + - wfn + singular: workflownode + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a node of workflow + properties: + abortWithStatusCheck: + description: AbortWithStatusCheck describe whether to abort the workflow + when the failure threshold of StatusCheck is exceeded. Only used + when Type is TypeStatusCheck. + type: boolean + awsChaos: + description: AWSChaosSpec is the content of the specification for + an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. Supported + action: ec2-stop / ec2-restart / detach-volume Default action: + ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. Needed + in detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws server. + Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. Needed + in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification for + an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. + Supported action: vm-stop / vm-restart / disk-detach Default + action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. Needed in + disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the data + disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification for + a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. + Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every io request. + type: string + type: object + duration: + description: Duration represents the duration of the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + children: + items: + type: string + type: array + conditionalBranches: + items: + properties: + expression: + description: Expression is the expression for this conditional + branch, expected type of result is boolean. If expression + is empty, this branch will always be selected/the template + will be spawned. + type: string + target: + description: Target is the name of other template, if expression + is evaluated as true, this template will be spawned. + type: string + required: + - target + type: object + type: array + deadline: + format: date-time + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos action. Supported + action: error, random Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, support + the placeholder ? and wildcard *, or the Specified domain name. + Note: 1. The wildcard * must be at the end of the string. For + example, chaos-*.org is invalid. 2. if the patterns is empty, + will take effect on all the domain names. For example: The value + is ["google.com", "github.*", "chaos-mes?.org"], will take effect + on "google.com", "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification for + a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. Supported + action: node-stop / node-reset / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status code + in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, such + as "300ms", "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + type: string + method: + description: Method is a rule to select target by http method + in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of target. + properties: + type: + description: Type represents the patch type, only support + `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers of + target. For example: `[["Set-Cookie", ""], ["Set-Cookie", + ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries of target(Request + only). For example: `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri path in http + request. + type: string + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents in target. + properties: + body: + description: Body is a rule to replace http message body in + target. + format: byte + type: string + code: + description: Code is a rule to replace http status code in + response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers of + target. The key-value pairs represent header name and header + value pairs. + type: object + method: + description: Method is a rule to replace http method in request. + type: string + path: + description: Path is rule to to replace uri path in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries in + http request. For example, with value `{ "foo": "unknown" + }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target by http + headers in request. The key-value pairs represent header name + and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target by http + headers in response. The key-value pairs represent header name + and header value pairs. + type: object + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file in + secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name of cert file + in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of key file + in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required secret + resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace of required + secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action delay. + A delay string is a possibly signed sequence of decimal numbers, + each with optional fraction and a unit suffix, such as "300ms". + Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that returned by I/O + action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting I/O + chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness are injected + to IO operations + properties: + filling: + description: Filling determines what is filled in the mistake + data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments of + wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting I/O + chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection errors + and provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected + volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. Supported + action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only set it when + action is stress + type: integer + database: + description: the match database default value is "", means match + all database + type: string + duration: + description: Duration represents the duration of the chaos action + type: string + exception: + description: the exception which needs to throw for action `exception` + or the exception message needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', unit ms + or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will generate + one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", means match + all SQL type. The value can be 'select', 'insert', 'update', + 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call chain, such + as: ext4_mount -> mount_subtree -> ... -> should_failslab + With an optional set of predicates and an optional set of + parameters, which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep Callchain + empty, which means it will fail at any call chain with slab + alloc (eg: kmalloc).' + items: + description: Frame defines the function signature and predicate + in function's body + properties: + funcname: + description: Funcname can be find from kernel source + or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, for + example, if you want to inject slab error in `d_alloc_parallel(struct + dentry *parent, const struct qstr *name)` with a special + name `bananas`, you need to set it to `struct dentry + *parent, const struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments of + this Frame, example with Parameters's, you can set + it to `STRNCMP(name->name, "bananas", 8)` to make + inject only with it, or omit it to inject for all + d_alloc_parallel call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be set + to ''0'' / ''1'' / ''2'' If `0`, indicates slab to fail + (should_failslab) If `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) You can + read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel headers + you need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so + on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos action. + Supported action: partition, netem, delay, loss, duplicate, + corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth control + action + properties: + buffer: + description: Buffer is the maximum amount of bytes that tokens + can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be queued + waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate bucket. + For perfect accuracy, should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness is acceptable, + this size can be raised. A 3000 byte minburst allows around + 3mbit/s of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of the + bucket. The peakrate does not need to be set, it is only + necessary if perfect millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies + on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets outside + k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, + gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this applies on + netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device to be + affected in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired state of + PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one of Address + and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock on which + to act. More clock description in linux kernel can be found + in man page of clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. if path + not provided, payload will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the file. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + delay: + description: Delay represents the delay of the target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for action + `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', unit + ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", means + match all database + type: string + exception: + description: The exception which needs to throw for action + `exception` or the exception message needs to throw in action + `mysql` + type: string + latency: + description: The latency duration for action 'latency' or + the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, will + use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set it + when action is stress + type: integer + mem-type: + description: the memory type need to locate, only set it when + action is stress, the value can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can + be accepted, others will be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf with + this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or µs), ms, + s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads to + run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP address + type: string + rate: + description: The speed of network traffic, allows bps, kbps, + mbps, gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, such + as 80, 8001:8010. it can only be used in conjunction with + -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag can + be accepted, others will be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values can + be 'from', 'to'. 'from' means packets coming from the 'IPAddress' + or 'Hostname' and going to your server, 'to' means packets + originating from your server and going to the 'IPAddress' + or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of the original + value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string keys and + a set values that used to select physical machines. The + key defines the namespace which physical machine belong, + and each value is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. 0 + is effectively a sleep (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, default + is the total available memory. One can specify the size + as % of total available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify + the percent of physical machines the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify + the max percent of pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a user creates + on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos action. Supported + action: pod-kill / pod-failure / container-kill Default action: + pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It represents + the duration in seconds before the pod should be deleted. Value + must be non-negative integer. The default value is zero that + indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + description: ScheduleSpec is the specification of a schedule object + properties: + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. + Supported action: ec2-stop / ec2-restart / detach-volume + Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. + Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws server. + Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. + Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. + Supported action: vm-stop / vm-restart / disk-detach Default + action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. Needed + in disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the + data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. + Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every io request. + type: string + type: object + duration: + description: Duration represents the duration of the chaos + action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + default: Forbid + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos action. + Supported action: error, random Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, support + the placeholder ? and wildcard *, or the Specified domain + name. Note: 1. The wildcard * must be at the end of the + string. For example, chaos-*.org is invalid. 2. if the patterns + is empty, will take effect on all the domain names. For + example: The value is ["google.com", "github.*", "chaos-mes?.org"], + will take effect on "google.com", "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. + Supported action: node-stop / node-reset / disk-loss Default + action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed in + disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status + code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, + such as "300ms", "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + method: + description: Method is a rule to select target by http method + in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of target. + properties: + type: + description: Type represents the patch type, only + support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], + ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", "bar"], + ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri path in + http request. + type: string + port: + description: Port represents the target port to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents in + target. + properties: + body: + description: Body is a rule to replace http message body + in target. + format: byte + type: string + code: + description: Code is a rule to replace http status code + in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header name + and header value pairs. + type: object + method: + description: Method is a rule to replace http method in + request. + type: string + path: + description: Path is rule to to replace uri path in http + request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": "unknown" + }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target by + http headers in request. The key-value pairs represent header + name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target by + http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file + in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name of cert + file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of key file + in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required + secret resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace + of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. + Supported action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action delay. + A delay string is a possibly signed sequence of decimal + numbers, each with optional fraction and a unit suffix, + such as "300ms". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos + action. It is required when the action is `PodFailureAction`. + 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". + type: string + errno: + description: 'Errno defines the error code that returned by + I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting + I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness are + injected to IO operations + properties: + filling: + description: Filling determines what is filled in the + mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment in + bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting + I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection + errors and provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected + volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. + Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only set it + when action is stress + type: integer + database: + description: the match database default value is "", means + match all database + type: string + duration: + description: Duration represents the duration of the chaos + action + type: string + exception: + description: the exception which needs to throw for action + `exception` or the exception message needs to throw in action + `mysql` + type: string + latency: + description: the latency duration for action 'latency', unit + ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it + when action is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will + generate one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means match + all table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel + injection + properties: + callchain: + description: 'Callchain indicate a special call chain, + such as: ext4_mount -> mount_subtree -> ... -> should_failslab + With an optional set of predicates and an optional set + of parameters, which used with predicates. You can read + call chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep Callchain + empty, which means it will fail at any call chain with + slab alloc (eg: kmalloc).' + items: + description: Frame defines the function signature and + predicate in function's body + properties: + funcname: + description: Funcname can be find from kernel source + or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab error + in `d_alloc_parallel(struct dentry *parent, const + struct qstr *name)` with a special name `bananas`, + you need to set it to `struct dentry *parent, + const struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments + of this Frame, example with Parameters's, you + can set it to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, or omit it to + inject for all d_alloc_parallel call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be + set to ''0'' / ''1'' / ''2'' If `0`, indicates slab + to fail (should_failslab) If `1`, indicates alloc_page + to fail (should_fail_alloc_page) If `2`, indicates bio + to fail (should_fail_bio) You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel + headers you need. Eg: "linux/mmzone.h", "linux/blkdev.h" + and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos action. + Supported action: partition, netem, delay, loss, duplicate, + corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes that + tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be + queued waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate + bucket. For perfect accuracy, should be set to the MTU + of the interface. If a peakrate is needed, but some + burstiness is acceptable, this size can be raised. A + 3000 byte minburst allows around 3mbit/s of peakrate, + given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate of + the bucket. The peakrate does not need to be set, it + is only necessary if perfect millisecond timescale shaping + is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, + mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies + on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss + action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos + action + type: string + externalTargets: + description: ExternalTargets represents network targets outside + k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control + action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, + mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + target: + description: Target represents network target, this applies + on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / + random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values + array must be non-empty. If the operator is + Exists or DoesNotExist, the values array must + be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines + the namespace which pods belong, and the each values + is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to + `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device to + be affected in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired state + of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one of + Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock on + which to act. More clock description in linux kernel + can be found in man page of clock_getres, clock_gettime, + clock_settime. Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. if + path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. if + path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. if + path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, + default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will write + into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos + action + type: string + file-append: + properties: + count: + description: Count is the number of times to append the + data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create or + delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create or + delete. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the + file. + type: string + file-name: + description: FileName is the name of the file to be created, + modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to be + replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside + proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by http status + code in response + type: string + delay: + description: Delay represents the delay of the target + request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside + proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for action + `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', + unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", means + match all database + type: string + exception: + description: The exception which needs to throw for action + `exception` or the exception message needs to throw + in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' + or the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only + support 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, + will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set + it when action is stress + type: integer + mem-type: + description: the memory type need to locate, only set + it when action is stress, the value can be 'stack' or + 'heap' + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag + can be accepted, others will be dropped. only set when + the IPProtocol is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us (or + µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 is + 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads + to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP address + type: string + rate: + description: The speed of network traffic, allows bps, + kbps, mbps, gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag + can be accepted, others will be dropped. only set when + the IPProtocol is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values + can be 'from', 'to'. 'from' means packets coming from + the 'IPAddress' or 'Hostname' and going to your server, + 'to' means packets originating from your server and + going to the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of the + original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush + config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string keys + and a set values that used to select physical machines. + The key defines the namespace which physical machine + belong, and each value is a set of physical machine + names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. + 0 is effectively a sleep (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, + default is the total available memory. One can specify + the size as % of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify + the percent of physical machines the server can do chaos + action. IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a user creates + on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos action. + Supported action: pod-kill / pod-failure / container-kill + Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action. It is required when the action is `PodFailureAction`. + 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It represents + the duration in seconds before the pod should be deleted. + Value must be non-negative integer. The default value is + zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + exclusiveMinimum: true + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors + just like `Stressors` except that it's an experimental feature + and more powerful. You can define stressors in `stress-ng` + (see also `man stress-ng`) dialect, however not all of the + supported stressors are well tested. It maybe retired in + later releases. You should always use `Stressors` to define + the stressors and use this only when you want more stressors + unsupported by `Stressors`. When both `StressngStressors` + and `Stressors` are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported + to stress system components out. You can use one or more + of them to make up various kinds of stresses. At least one + of the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading per + CPU worker. 0 is effectively a sleep (no load) and + 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to apply + the stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj of + the stress process. See `man 5 proc` to know more + about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per vm + worker, default is the total available memory. One + can specify the size as % of total available memory + or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to apply + the stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id All available + options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be + used to select nodes. Selector which must match a node's + labels, and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod + names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected + program. It's a possibly signed sequence of decimal numbers, + such as "300ms", "-1.5h" or "2h45m". Valid time units are + "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods + the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to + do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + workflow: + properties: + entry: + type: string + templates: + items: + properties: + abortWithStatusCheck: + description: AbortWithStatusCheck describe whether to + abort the workflow when the failure threshold of StatusCheck + is exceeded. Only used when Type is TypeStatusCheck. + type: boolean + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos + action. Supported action: ec2-stop / ec2-restart + / detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the + device. Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the + ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of + the aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS + volume. Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure + chaos action. Supported action: vm-stop / vm-restart + / disk-detach Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the + disk. Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number + of the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name + of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure + subscription. + type: string + vmName: + description: VMName defines the name of Virtual + Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block + chaos action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of + every io request. + type: string + type: object + duration: + description: Duration represents the duration of + the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + children: + description: Children describes the children steps of + serial or parallel node. Only used when Type is TypeSerial + or TypeParallel. + items: + type: string + type: array + conditionalBranches: + description: ConditionalBranches describes the conditional + branches of custom tasks. Only used when Type is TypeTask. + items: + properties: + expression: + description: Expression is the expression for + this conditional branch, expected type of result + is boolean. If expression is empty, this branch + will always be selected/the template will be + spawned. + type: string + target: + description: Target is the name of other template, + if expression is evaluated as true, this template + will be spawned. + type: string + required: + - target + type: object + type: array + deadline: + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state + of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos + action. Supported action: error, random Default + action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take + effect, support the placeholder ? and wildcard + *, or the Specified domain name. Note: 1. The + wildcard * must be at the end of the string. For + example, chaos-*.org is invalid. 2. if the patterns + is empty, will take effect on all the domain names. + For example: The value is ["google.com", "github.*", + "chaos-mes?.org"], will take effect on "google.com", + "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos + action. Supported action: node-stop / node-reset + / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. + Needed in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by + http status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target + request/response. A duration string is a possibly + unsigned sequence of decimal numbers, each with + optional fraction and a unit suffix, such as "300ms", + "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of + the chaos action. + type: string + method: + description: Method is a rule to select target by + http method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. + properties: + body: + description: Body is a rule to patch message + body of target. + properties: + type: + description: Type represents the patch type, + only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http + headers of target. For example: `[["Set-Cookie", + ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri + queries of target(Request only). For example: + `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by + uri path in http request. + type: string + port: + description: Port represents the target port to + be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http + message body in target. + format: byte + type: string + code: + description: Code is a rule to replace http + status code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http + headers of target. The key-value pairs represent + header name and header value pairs. + type: object + method: + description: Method is a rule to replace http + method in request. + type: string + path: + description: Path is rule to to replace uri + path in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri + queries in http request. For example, with + value `{ "foo": "unknown" }`, the `/?foo=bar` + will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select + target by http headers in request. The key-value + pairs represent header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select + target by http headers in response. The key-value + pairs represent header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected + and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override + PodHttpChaos if there are multiple HTTPChaos experiments + are applied + properties: + caName: + description: CAName represents the data name + of ca file in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name + of cert file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name + of key file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name + of required secret resource + type: string + secretNamespace: + description: SecretNamespace represents the + namespace of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of + IOChaos + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: latency / fault / attrOverride + / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos + action delay. A delay string is a possibly signed + sequence of decimal numbers, each with optional + fraction and a unit suffix, such as "300ms". Valid + time units are "ns", "us" (or "µs"), "ms", "s", + "m", "h". + type: string + duration: + description: Duration represents the duration of + the chaos action. It is required when the action + is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that + returned by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for + injecting I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled + in the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment + in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] + segments of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for + injecting I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of + injection errors and provides a number from 0-100. + default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path + of injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state + of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos + action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only + set it when action is stress + type: integer + database: + description: the match database default value is + "", means match all database + type: string + duration: + description: Duration represents the duration of + the chaos action + type: string + exception: + description: the exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only + set it when action is stress, the value can be + 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set to + "8") now + type: string + name: + description: byteman rule name, should be unique, + and will generate one if not set + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action + 'ruleData' + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is + "", means match all SQL type. The value can be + 'select', 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", + means match all table + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state + of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request + of kernel injection + properties: + callchain: + description: 'Callchain indicate a special call + chain, such as: ext4_mount -> mount_subtree + -> ... -> should_failslab With an optional + set of predicates and an optional set of parameters, + which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just + keep Callchain empty, which means it will + fail at any call chain with slab alloc (eg: + kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from + kernel source or `/proc/kallsyms`, such + as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab + error in `d_alloc_parallel(struct dentry + *parent, const struct qstr *name)` with + a special name `bananas`, you need to + set it to `struct dentry *parent, const + struct qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the + arguments of this Frame, example with + Parameters's, you can set it to `STRNCMP(name->name, + "bananas", 8)` to make inject only with + it, or omit it to inject for all d_alloc_parallel + call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, + can be set to ''0'' / ''1'' / ''2'' If `0`, + indicates slab to fail (should_failslab) If + `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) + You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails + with probability. If you want 1%, please set + this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of + fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + name: + type: string + networkChaos: + description: NetworkChaosSpec defines the desired state + of NetworkChaos + properties: + action: + description: 'Action defines the specific network + chaos action. Supported action: partition, netem, + delay, loss, duplicate, corrupt Default action: + delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about + bandwidth control action + properties: + buffer: + description: Buffer is the maximum amount of + bytes that tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that + can be queued waiting for tokens to become + available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of + the peakrate bucket. For perfect accuracy, + should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness + is acceptable, this size can be raised. A + 3000 byte minburst allows around 3mbit/s of + peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion + rate of the bucket. The peakrate does not + need to be set, it is only necessary if perfect + millisecond timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about + corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay + action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of + packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device + to be affected. + type: string + direction: + default: to + description: Direction represents the direction, + this applies on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail + about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of + the chaos action + type: string + externalTargets: + description: ExternalTargets represents network + targets outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss + action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate + control action + properties: + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, + gbps, tbps unit. bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this + applies on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network + device to be affected in target scope. + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired + state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. + Only one of Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular + clock on which to act. More clock description + in linux kernel can be found in man page of + clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 is + valid value + type: integer + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload will + read/write from/into a temp file, temp file + will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 is + valid value + type: integer + size: + description: 'specifies how many units of data + will write into the file path. support unit: + c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, + M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 + BYTES. example : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of + the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times to + append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to + create or delete. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to + create or delete. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + privilege: + description: Privilege is the file privilege + to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to + be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string + of the file. + type: string + file-name: + description: FileName is the name of the file + to be created, modified, deleted, renamed, + or appended. + type: string + line: + description: Line is the line number of the + file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string + of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of + HTTP connection, we will only attack HTTP + connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + delay: + description: Delay represents the delay of the + target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of + HTTP connection, we will only attack HTTP + connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support + GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw + for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action + 'latency', unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value + is "", means match all database + type: string + exception: + description: The exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action + 'latency' or the latency duration in action + `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set + to "8") now + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value + is "", means match all SQL type. The value + can be 'select', 'insert', 'update', 'delete', + 'replace'. + type: string + table: + description: the match table default value is + "", means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule + file's data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, + only set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, + only set it when action is stress, the value + can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the + tcp flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used + for partition. + type: string + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: + ns, us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the + iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client + threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on + the IP address + type: string + rate: + description: The speed of network traffic, allows + bps, kbps, mbps, gbps, tbps unit. bps means + bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is + 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or + to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this + IP protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from + these source ports, use a ',' to separate + or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p + tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the + tcp flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used + for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means packets + coming from the 'IPAddress' or 'Hostname' + and going to your server, 'to' means packets + originating from your server and going to + the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these + IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process + ID + type: string + recoverCmd: + description: the command to be run when recovering + experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical + machines that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string + keys and a set values that used to select + physical machines. The key defines the namespace + which physical machine belong, and each value + is a set of physical machine names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per + CPU worker. 0 is effectively a sleep (no load) + and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the + stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per + vm worker, default is the total available + memory. One can specify the size as % of total + available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when + attack + type: string + recoverCmd: + description: The command to be executed when + recover + type: string + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of physical + machines to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent + of physical machines the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from + 0-100 to specify the max percent of pods to do + chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that + a user creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: pod-kill / pod-failure + / container-kill Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action. It is required when the action + is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. + It represents the duration in seconds before the + pod should be deleted. Value must be non-negative + integer. The default value is zero that indicates + delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + description: Schedule describe the Schedule(describing + scheduled chaos) to be injected with chaos nodes. + Only used when Type is TypeSchedule. + properties: + awsChaos: + description: AWSChaosSpec is the content of the + specification for an AWSChaos + properties: + action: + description: 'Action defines the specific aws + chaos action. Supported action: ec2-stop / + ec2-restart / detach-volume Default action: + ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of + aws. + type: string + deviceName: + description: DeviceName indicates the name of + the device. Needed in detach-volume. + type: string + duration: + description: Duration represents the duration + of the chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of + the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint + of the aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of + kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the + EBS volume. Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the + specification for an AzureChaos + properties: + action: + description: 'Action defines the specific azure + chaos action. Supported action: vm-stop / + vm-restart / disk-detach Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of + the disk. Needed in disk-detach. + type: string + duration: + description: Duration represents the duration + of the chaos action. + type: string + lun: + description: LUN indicates the Logical Unit + Number of the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name + of ResourceGroup + type: string + secretName: + description: SecretName defines the name of + kubernetes secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of + Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual + Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the + specification for a BlockChaos + properties: + action: + description: 'Action defines the specific block + chaos action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency + of every io request. + type: string + type: object + duration: + description: Duration represents the duration + of the chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state + of DNSChaos + properties: + action: + description: 'Action defines the specific DNS + chaos action. Supported action: error, random + Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take + effect, support the placeholder ? and wildcard + *, or the Specified domain name. Note: 1. + The wildcard * must be at the end of the string. + For example, chaos-*.org is invalid. 2. if + the patterns is empty, will take effect on + all the domain names. For example: The value + is ["google.com", "github.*", "chaos-mes?.org"], + will take effect on "google.com", "github.com" + and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the + specification for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp + chaos action. Supported action: node-stop + / node-reset / disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. + Needed in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action. + type: string + instance: + description: Instance defines the name of the + instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of + kubernetes secret. It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http + session. + type: boolean + code: + description: Code is a rule to select target + by http status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the + target request/response. A duration string + is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a + unit suffix, such as "300ms", "2h45m". Valid + time units are "ns", "us" (or "µs"), "ms", + "s", "m", "h". + type: string + duration: + description: Duration represents the duration + of the chaos action. + type: string + method: + description: Method is a rule to select target + by http method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. + properties: + body: + description: Body is a rule to patch message + body of target. + properties: + type: + description: Type represents the patch + type, only support `JSON` as [merge + patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append + http headers of target. For example: `[["Set-Cookie", + ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append + uri queries of target(Request only). For + example: `[["foo", "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target + by uri path in http request. + type: string + port: + description: Port represents the target port + to be proxy of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some + contents in target. + properties: + body: + description: Body is a rule to replace http + message body in target. + format: byte + type: string + code: + description: Code is a rule to replace http + status code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace + http headers of target. The key-value + pairs represent header name and header + value pairs. + type: object + method: + description: Method is a rule to replace + http method in request. + type: string + path: + description: Path is rule to to replace + uri path in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace + uri queries in http request. For example, + with value `{ "foo": "unknown" }`, the + `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select + target by http headers in request. The key-value + pairs represent header name and header value + pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select + target by http headers in response. The key-value + pairs represent header name and header value + pairs. + type: object + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + target: + description: Target is the object to be selected + and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override + PodHttpChaos if there are multiple HTTPChaos + experiments are applied + properties: + caName: + description: CAName represents the data + name of ca file in secret, `ca.crt` for + example + type: string + certName: + description: CertName represents the data + name of cert file in secret, `tls.crt` + for example + type: string + keyName: + description: KeyName represents the data + name of key file in secret, `tls.key` + for example + type: string + secretName: + description: SecretName represents the name + of required secret resource + type: string + secretNamespace: + description: SecretNamespace represents + the namespace of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state + of IOChaos + properties: + action: + description: 'Action defines the specific pod + chaos action. Supported action: latency / + fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of + file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O + chaos action delay. A delay string is a possibly + signed sequence of decimal numbers, each with + optional fraction and a unit suffix, such + as "300ms". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration + of the chaos action. It is required when the + action is `PodFailureAction`. 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". + type: string + errno: + description: 'Errno defines the error code that + returned by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods + for injecting I/O chaos action. default: all + I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is + filled in the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data + segment in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] + segments of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files + for injecting I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage + of injection errors and provides a number + from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + volumePath: + description: VolumePath represents the mount + path of injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state + of JVMChaos + properties: + action: + description: 'Action defines the specific jvm + chaos action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, + only set it when action is stress + type: integer + database: + description: the match database default value + is "", means match all database + type: string + duration: + description: Duration represents the duration + of the chaos action + type: string + exception: + description: the exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: the latency duration for action + 'latency', unit ms or the latency duration + in action `mysql` + type: integer + memType: + description: the memory type needs to locate, + only set it when action is stress, the value + can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set + to "8") now + type: string + name: + description: byteman rule name, should be unique, + and will generate one if not set + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action + 'ruleData' + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + sqlType: + description: the match sql type default value + is "", means match all SQL type. The value + can be 'select', 'insert', 'update', 'delete', + 'replace'. + type: string + table: + description: the match table default value is + "", means match all table + type: string + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired + state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request + of kernel injection + properties: + callchain: + description: 'Callchain indicate a special + call chain, such as: ext4_mount -> mount_subtree + -> ... -> should_failslab With an optional + set of predicates and an optional set + of parameters, which used with predicates. + You can read call chan and predicate examples + from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, + just keep Callchain empty, which means + it will fail at any call chain with slab + alloc (eg: kmalloc).' + items: + description: Frame defines the function + signature and predicate in function's + body + properties: + funcname: + description: Funcname can be find + from kernel source or `/proc/kallsyms`, + such as `ext4_mount` + type: string + parameters: + description: Parameters is used with + predicate, for example, if you want + to inject slab error in `d_alloc_parallel(struct + dentry *parent, const struct qstr + *name)` with a special name `bananas`, + you need to set it to `struct dentry + *parent, const struct qstr *name` + otherwise omit it. + type: string + predicate: + description: Predicate will access + the arguments of this Frame, example + with Parameters's, you can set it + to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, + or omit it to inject for all d_alloc_parallel + call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to + fail, can be set to ''0'' / ''1'' / ''2'' + If `0`, indicates slab to fail (should_failslab) + If `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) + You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails + with probability. If you want 1%, please + set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times + of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired + state of NetworkChaos + properties: + action: + description: 'Action defines the specific network + chaos action. Supported action: partition, + netem, delay, loss, duplicate, corrupt Default + action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail + about bandwidth control action + properties: + buffer: + description: Buffer is the maximum amount + of bytes that tokens can be available + for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes + that can be queued waiting for tokens + to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size + of the peakrate bucket. For perfect accuracy, + should be set to the MTU of the interface. If + a peakrate is needed, but some burstiness + is acceptable, this size can be raised. + A 3000 byte minburst allows around 3mbit/s + of peakrate, given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion + rate of the bucket. The peakrate does + not need to be set, it is only necessary + if perfect millisecond timescale shaping + is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, + mbps, gbps, tbps unit. bps means bytes + per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about + corrupt action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about + delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details + of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device + to be affected. + type: string + direction: + default: to + description: Direction represents the direction, + this applies on netem and network partition + action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail + about loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration + of the chaos action + type: string + externalTargets: + description: ExternalTargets represents network + targets outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about + loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about + rate control action + properties: + rate: + description: Rate is the speed knob. Allows + bit, kbit, mbit, gbit, tbit, bps, kbps, + mbps, gbps, tbps unit. bps means bytes + per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + target: + description: Target represents network target, + this applies on netem and network partition + action + properties: + mode: + description: 'Mode defines the mode to run + chaos action. Supported mode: one / all + / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select + pods that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and + values that can be used to select + objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector + expressions that can be used to select + objects. A list of selectors based + on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and + values that can be used to select + objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and + values that can be used to select + objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of + namespace to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and + values that can be used to select + nodes. Selector which must match a + node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node + name and objects must belong to these + nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a + set of condition of a pod at the current + time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string + keys and a set values that used to + select pods. The key defines the namespace + which pods belong, and the each values + is a set of pod names. + type: object + type: object + value: + description: Value is required when the + mode is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent + of pods the server can do chaos action. + IF `RandomMaxPercentMode`, provide a + number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network + device to be affected in target scope. + type: string + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the + desired state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. + Only one of Address and Selector could be + specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular + clock on which to act. More clock description + in linux kernel can be found in man page + of clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time + offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill + data in. if path not provided, payload + will read/write from/into a temp file, + temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of + data will write into the file path. support + unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | + 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload + will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 + is valid value + type: integer + size: + description: 'specifies how many units of + data will write into the file path. support + unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | + 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill + data in. if path not provided, payload + will read/write from/into a temp file, + temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process + work on writing, default 1, only 1-255 + is valid value + type: integer + size: + description: 'specifies how many units of + data will write into the file path. support + unit: c=1, w=2, b=512, kB=1000, K=1024, + MB=1000*1000, M=1024*1024, GB=1000*1000*1000, + G=1024*1024*1024 BYTES. example : 1M | + 512kB' + type: string + type: object + duration: + description: Duration represents the duration + of the chaos action + type: string + file-append: + properties: + count: + description: Count is the number of times + to append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name + to create or delete. + type: string + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name + to create or delete. + type: string + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege + to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be + renamed. + type: string + source-file: + description: SourceFile is the name need + to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination + string of the file. + type: string + file-name: + description: FileName is the name of the + file to be created, modified, deleted, + renamed, or appended. + type: string + line: + description: Line is the line number of + the file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string + of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target + service listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port + of HTTP connection, we will only attack + HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target + by http status code in response + type: string + delay: + description: Delay represents the delay + of the target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard + matches + type: string + port: + description: The TCP port that the target + service listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port + of HTTP connection, we will only attack + HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only + support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to + throw for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action + 'latency', unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default + value is "", means match all database + type: string + exception: + description: The exception which needs to + throw for action `exception` or the exception + message needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action + 'latency' or the latency duration in action + `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set + to "8") now + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default + value is "", means match all SQL type. + The value can be 'select', 'insert', 'update', + 'delete', 'replace'. + type: string + table: + description: the match table default value + is "", means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + value: + description: the return value for action + 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule + file's data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to + use, only set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, + only set it when action is stress, the + value can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which + needs to attach + type: integer + port: + description: the port of agent server, default + 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka + config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 + is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic + to these destination ports, use a ',' + to separate or to indicate the range, + such as 80, 8001:8010. it can only be + used in conjunction with -p tcp or -p + udp + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using + this IP protocol, supported: tcp, udp, + icmp, all' + type: string + percent: + description: percentage of packets to corrupt + (10 is 10%) + type: string + source-port: + description: only impact egress traffic + from these source ports, use a ',' to + separate or to indicate the range, such + as 80, 8001:8010. it can only be used + in conjunction with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match + the tcp flag can be accepted, others will + be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 + is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic + to these destination ports, use a ',' + to separate or to indicate the range, + such as 80, 8001:8010. it can only be + used in conjunction with -p tcp or -p + udp + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using + this IP protocol, supported: tcp, udp, + icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: + ns, us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic + from these source ports, use a ',' to + separate or to indicate the range, such + as 80, 8001:8010. it can only be used + in conjunction with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified + IP + type: string + dns-ip: + description: map specified host to this + IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: + ns, us (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 + is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic + to these destination ports, use a ',' + to separate or to indicate the range, + such as 80, 8001:8010. it can only be + used in conjunction with -p tcp or -p + udp + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using + this IP protocol, supported: tcp, udp, + icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic + from these source ports, use a ',' to + separate or to indicate the range, such + as 80, 8001:8010. it can only be used + in conjunction with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run + the iperf test + type: string + ip-address: + description: Generate traffic to this IP + address + type: string + parallel: + description: The number of iperf parallel + client threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port + on the IP address + type: string + rate: + description: The speed of network traffic, + allows bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 + is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic + to these destination ports, use a ',' + to separate or to indicate the range, + such as 80, 8001:8010. it can only be + used in conjunction with -p tcp or -p + udp + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using + this IP protocol, supported: tcp, udp, + icmp, all' + type: string + percent: + description: percentage of packets to loss + (10 is 10%) + type: string + source-port: + description: only impact egress traffic + from these source ports, use a ',' to + separate or to indicate the range, such + as 80, 8001:8010. it can only be used + in conjunction with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match + the tcp flag can be accepted, others will + be dropped. only set when the IPProtocol + is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means + packets coming from the 'IPAddress' or + 'Hostname' and going to your server, 'to' + means packets originating from your server + and going to the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these + hostnames + type: string + ip-address: + description: only impact egress traffic + to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic + to these IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process + ID + type: string + recoverCmd: + description: the command to be run when + recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be + sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines + whether to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` + command-line tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines + whether to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` + command-line tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical + machines that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of + string keys and a set values that used + to select physical machines. The key defines + the namespace which physical machine belong, + and each value is a set of physical machine + names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading + per CPU worker. 0 is effectively a sleep + (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply + the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % + of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed + when attack + type: string + recoverCmd: + description: The command to be executed + when recover + type: string + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent + of physical machines the server can do chaos + action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes + that a user creates on a chaos experiment about + pods. + properties: + action: + description: 'Action defines the specific pod + chaos action. Supported action: pod-kill / + pod-failure / container-kill Default action: + pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action. It is required when the + action is `PodFailureAction`. 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill + action. It represents the duration in seconds + before the pod should be deleted. Value must + be non-negative integer. The default value + is zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired + state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty + of stressors just like `Stressors` except + that it's an experimental feature and more + powerful. You can define stressors in `stress-ng` + (see also `man stress-ng`) dialect, however + not all of the supported stressors are well + tested. It maybe retired in later releases. + You should always use `Stressors` to define + the stressors and use this only when you want + more stressors unsupported by `Stressors`. + When both `StressngStressors` and `Stressors` + are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors + supported to stress system components out. + You can use one or more of them to make up + various kinds of stresses. At least one of + the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent + loading per CPU worker. 0 is effectively + a sleep (no load) and 100 is full + loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 + workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual + memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 + proc` to know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes + consumed per vm worker, default is + the total available memory. One can + specify the size as % of total available + memory or in units of B, KB/KiB, MB/MiB, + GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 + workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state + of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock + id All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of + the name of affected container. If not set, + the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration + of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed + / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A + list of selectors based on set-based label + expressions. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select objects. A + selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values + that can be used to select nodes. Selector + which must match a node's labels, and + objects must belong to these selected + nodes. + type: object + nodes: + description: Nodes is a set of node name + and objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set + of condition of a pod at the current time. + supported value: Pending / Running / Succeeded + / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys + and a set values that used to select pods. + The key defines the namespace which pods + belong, and the each values is a set of + pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time + of injected program. It's a possibly signed + sequence of decimal numbers, such as "300ms", + "-1.5h" or "2h45m". Valid time units are "ns", + "us" (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode + is set to `FixedMode` / `FixedPercentMode` + / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server + can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + required: + - schedule + - type + type: object + statusCheck: + description: StatusCheck describe the behavior of StatusCheck. + Only used when Type is TypeStatusCheck. + properties: + duration: + description: Duration defines the duration of the + whole status check if the number of failed execution + does not exceed the failure threshold. Duration + is available to both `Synchronous` and `Continuous` + mode. 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum + consecutive failure for the status check to be + considered failed. + minimum: 1 + type: integer + http: + properties: + body: + type: string + criteria: + description: Criteria defines how to determine + the result of the status check. + properties: + statusCode: + description: StatusCode defines the expected + http status code for the request. A statusCode + string could be a single code (e.g. 200), + or an inclusive range (e.g. 200-400, both + `200` and `400` are included). + type: string + required: + - statusCode + type: object + headers: + additionalProperties: + items: + type: string + type: array + description: "A Header represents the key-value + pairs in an HTTP header. \n The keys should + be in canonical form, as returned by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in + seconds) to perform an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of + the status check. Support type: Synchronous / + Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number + of record to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum + consecutive successes for the status check to + be considered successful. SuccessThreshold only + works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of + seconds after which an execution of status check + times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check + type. Support type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + stressChaos: + description: StressChaosSpec defines the desired state + of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of + stressors just like `Stressors` except that it's + an experimental feature and more powerful. You + can define stressors in `stress-ng` (see also + `man stress-ng`) dialect, however not all of the + supported stressors are well tested. It maybe + retired in later releases. You should always use + `Stressors` to define the stressors and use this + only when you want more stressors unsupported + by `Stressors`. When both `StressngStressors` + and `Stressors` are defined, `StressngStressors` + wins. + type: string + stressors: + description: Stressors defines plenty of stressors + supported to stress system components out. You + can use one or more of them to make up various + kinds of stresses. At least one of the stressors + should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading + per CPU worker. 0 is effectively a sleep + (no load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 workers + can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual + memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` + to know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % + of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers + to apply the stressor. Maximum 8192 workers + can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + type: object + task: + description: Task describes the behavior of the custom + task. Only used when Type is TypeTask. + properties: + container: + description: Container is the main container image + to run in the pod + properties: + args: + description: 'Arguments to the entrypoint. The + container image''s CMD is used if this is + not provided. Variable references $(VAR_NAME) + are expanded using the container''s environment. + If a variable cannot be resolved, the reference + in the input string will be unchanged. Double + $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal + "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable + exists or not. Cannot be updated. More info: + https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed + within a shell. The container image''s ENTRYPOINT + is used if this is not provided. Variable + references $(VAR_NAME) are expanded using + the container''s environment. If a variable + cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, + regardless of whether the variable exists + or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to + set in the container. Cannot be updated. + items: + description: EnvVar represents an environment + variable present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined + environment variables in the container + and any service environment variables. + If a variable cannot be resolved, the + reference in the input string will be + unchanged. Double $$ are reduced to + a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, + regardless of whether the variable exists + or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment + variable's value. Cannot be used if + value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the + ConfigMap or its key must be + defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the + pod: supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in + terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field + to select in the specified API + version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: + required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret + in the pod's namespace + properties: + key: + description: The key of the secret + to select from. Must be a valid + secret key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the + Secret or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined + within a source must be a C_IDENTIFIER. All + invalid keys will be reported as an event + when the container is starting. When a key + exists in multiple sources, the value associated + with the last source will take precedence. + Values defined by an Env with a duplicate + key will take precedence. Cannot be updated. + items: + description: EnvFromSource represents the + source of a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to + prepend to each key in the ConfigMap. + Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: + https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level + config management to default or override container + images in workload controllers like Deployments + and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, + Never, IfNotPresent. Defaults to Always if + :latest tag is specified, or IfNotPresent + otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system + should take in response to container lifecycle + events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately + after a container is created. If the handler + fails, the container is terminated and + restarted according to its restart policy. + Other management of the container blocks + until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action + to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the + command is root ('/') in the + container's filesystem. The command + is simply exec'd, it is not run + inside a shell, so traditional + shell instructions ('|', etc) + won't work. To use a shell, you + need to explicitly call out to + that shell. Exit status of 0 is + treated as live/healthy and non-zero + is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood + as the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is + NOT supported as a LifecycleHandler + and kept for the backward compatibility. + There are no validation of this field + and lifecycle hooks will fail in runtime + when tcp handler is specified. + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the + pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately + before a container is terminated due to + an API request or management event such + as liveness/startup probe failure, preemption, + resource contention, etc. The handler + is not called if the container crashes + or exits. The Pod''s termination grace + period countdown begins before the PreStop + hook is executed. Regardless of the outcome + of the handler, the container will eventually + terminate within the Pod''s termination + grace period (unless delayed by finalizers). + Other management of the container blocks + until the hook completes or until the + termination grace period is reached. More + info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action + to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the + command is root ('/') in the + container's filesystem. The command + is simply exec'd, it is not run + inside a shell, so traditional + shell instructions ('|', etc) + won't work. To use a shell, you + need to explicitly call out to + that shell. Exit status of 0 is + treated as live/healthy and non-zero + is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood + as the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is + NOT supported as a LifecycleHandler + and kept for the backward compatibility. + There are no validation of this field + and lifecycle hooks will fail in runtime + when tcp handler is specified. + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the + pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed + after having succeeded. Defaults to 3. + Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC + service. Number must be in the range + 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of + the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness + probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum + value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully + upon probe failure. The grace period is + the duration in seconds after the processes + running in the pod are sent a termination + signal and the time when the processes + are forcibly halted with a kill signal. + Set this value longer than the expected + cleanup time for your process. If this + value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value + zero indicates stop immediately via the + kill signal (no opportunity to shut down). + This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified + as a DNS_LABEL. Each container in a pod must + have a unique name (DNS_LABEL). Cannot be + updated. + type: string + ports: + description: List of ports to expose from the + container. Not specifying a port here DOES + NOT prevent that port from being exposed. + Any port which is listening on the default + "0.0.0.0" address inside a container will + be accessible from the network. Modifying + this array with strategic merge patch may + corrupt the data. For more information See + https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network + port in a single container. + properties: + containerPort: + description: Number of port to expose + on the pod's IP address. This must be + a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the + external port to. + type: string + hostPort: + description: Number of port to expose + on the host. If specified, this must + be a valid port number, 0 < x < 65536. + If HostNetwork is specified, this must + match ContainerPort. Most containers + do not need this. + format: int32 + type: integer + name: + description: If specified, this must be + an IANA_SVC_NAME and unique within the + pod. Each named port in a pod must have + a unique name. Name for the port that + can be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be + UDP, TCP, or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service + readiness. Container will be removed from + service endpoints if the probe fails. Cannot + be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed + after having succeeded. Defaults to 3. + Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC + service. Number must be in the range + 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of + the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness + probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum + value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully + upon probe failure. The grace period is + the duration in seconds after the processes + running in the pod are sent a termination + signal and the time when the processes + are forcibly halted with a kill signal. + Set this value longer than the expected + cleanup time for your process. If this + value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value + zero indicates stop immediately via the + kill signal (no opportunity to shut down). + This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the + container. + items: + description: ContainerResizePolicy represents + resource resize policy for the container. + properties: + resourceName: + description: 'Name of the resource to + which this resource resize policy applies. + Supported values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when + specified resource is resized. If not + specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by + this container. Cannot be updated. More info: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of + resources, defined in spec.resourceClaims, + that are used by this container. \n This + is an alpha field and requires enabling + the DynamicResourceAllocation feature + gate. \n This field is immutable. It can + only be set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum + amount of compute resources allowed. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. + If Requests is omitted for a container, + it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined + value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + restartPolicy: + description: 'RestartPolicy defines the restart + behavior of individual containers in a pod. + This field may only be set for init containers, + and the only allowed value is "Always". For + non-init containers or when this field is + not specified, the restart behavior is defined + by the Pod''s restart policy and the container + type. Setting the RestartPolicy as "Always" + for the init container will have the following + effect: this init container will be continually + restarted on exit until all regular containers + have terminated. Once all regular containers + have completed, all init containers with restartPolicy + "Always" will be shut down. This lifecycle + differs from normal init containers and is + often referred to as a "sidecar" container. + Although this init container still starts + in the init container sequence, it does not + wait for the container to complete before + proceeding to the next init container. Instead, + the next init container starts immediately + after this init container is started, or after + any startupProbe has successfully completed.' + type: string + securityContext: + description: 'SecurityContext defines the security + options the container should be run with. + If set, the fields of SecurityContext override + the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges + than its parent process. This bool directly + controls if the no_new_privs flag will + be set on the container process. AllowPrivilegeEscalation + is true always when the container is: + 1) run as Privileged 2) has CAP_SYS_ADMIN + Note that this field cannot be set when + spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop + when running containers. Defaults to the + default set of capabilities granted by + the container runtime. Note that this + field cannot be set when spec.os.name + is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent + POSIX capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent + POSIX capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged + mode. Processes in privileged containers + are essentially equivalent to root on + the host. Defaults to false. Note that + this field cannot be set when spec.os.name + is windows. + type: boolean + procMount: + description: procMount denotes the type + of proc mount to use for the containers. + The default is DefaultProcMount which + uses the container runtime defaults for + readonly paths and masked paths. This + requires the ProcMountType feature flag + to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has + a read-only root filesystem. Default is + false. Note that this field cannot be + set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint + of the container process. Uses runtime + default if unset. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. Note that this field + cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container + must run as a non-root user. If true, + the Kubelet will validate the image at + runtime to ensure that it does not run + as UID 0 (root) and fail to start the + container if it does. If unset or false, + no such validation will be performed. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint + of the container process. Defaults to + user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. Note that this field + cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied + to the container. If unspecified, the + container runtime will allocate a random + SELinux context for each container. May + also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. Note that this field + cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level + label that applies to the container. + type: string + role: + description: Role is a SELinux role + label that applies to the container. + type: string + type: + description: Type is a SELinux type + label that applies to the container. + type: string + user: + description: User is a SELinux user + label that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use + by this container. If seccomp options + are provided at both the pod & container + level, the container options override + the pod options. Note that this field + cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: localhostProfile indicates + a profile defined in a file on the + node should be used. The profile must + be preconfigured on the node to work. + Must be a descending path, relative + to the kubelet's configured seccomp + profile location. Must be set if type + is "Localhost". Must NOT be set for + any other type. + type: string + type: + description: "type indicates which kind + of seccomp profile will be applied. + Valid options are: \n Localhost - + a profile defined in a file on the + node should be used. RuntimeDefault + - the container runtime default profile + should be used. Unconfined - no profile + should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings + applied to all containers. If unspecified, + the options from the PodSecurityContext + will be used. If set in both SecurityContext + and PodSecurityContext, the value specified + in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name + is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where + the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName + field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName + is the name of the GMSA credential + spec to use. + type: string + hostProcess: + description: HostProcess determines + if a container should be run as a + 'Host Process' container. All of a + Pod's containers must have the same + effective HostProcess value (it is + not allowed to have a mix of HostProcess + containers and non-HostProcess containers). + In addition, if HostProcess is true + then HostNetwork must also be set + to true. + type: boolean + runAsUserName: + description: The UserName in Windows + to run the entrypoint of the container + process. Defaults to the user specified + in image metadata if unspecified. + May also be set in PodSecurityContext. + If set in both SecurityContext and + PodSecurityContext, the value specified + in SecurityContext takes precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the + Pod has successfully initialized. If specified, + no other probes are executed until this completes + successfully. If this probe fails, the Pod + will be restarted, just as if the livenessProbe + failed. This can be used to provide different + probe parameters at the beginning of a Pod''s + lifecycle, when it might take a long time + to load data or warm a cache, than during + steady-state operation. This cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed + after having succeeded. Defaults to 3. + Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC + service. Number must be in the range + 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of + the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness + probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum + value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully + upon probe failure. The grace period is + the duration in seconds after the processes + running in the pod are sent a termination + signal and the time when the processes + are forcibly halted with a kill signal. + Set this value longer than the expected + cleanup time for your process. If this + value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value + zero indicates stop immediately via the + kill signal (no opportunity to shut down). + This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. + If this is not set, reads from stdin in the + container will always result in EOF. Default + is false. + type: boolean + stdinOnce: + description: Whether the container runtime should + close the stdin channel after it has been + opened by a single attach. When stdin is true + the stdin stream will remain open across multiple + attach sessions. If stdinOnce is set to true, + stdin is opened on container start, is empty + until the first client attaches to stdin, + and then remains open and accepts data until + the client disconnects, at which time stdin + is closed and remains closed until the container + is restarted. If this flag is false, a container + processes that reads from stdin will never + receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file + to which the container''s termination message + will be written is mounted into the container''s + filesystem. Message written is intended to + be brief final status, such as an assertion + failure message. Will be truncated by the + node if greater than 4096 bytes. The total + message length across all containers will + be limited to 12kb. Defaults to /dev/termination-log. + Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message + should be populated. File will use the contents + of terminationMessagePath to populate the + container status message on both success and + failure. FallbackToLogsOnError will use the + last chunk of container log output if the + termination message file is empty and the + container exited with an error. The log output + is limited to 2048 bytes or 80 lines, whichever + is smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to + be true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block + devices to be used by the container. + items: + description: volumeDevice describes a mapping + of a raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside + of the container that the device will + be mapped to. + type: string + name: + description: name must match the name + of a persistentVolumeClaim in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting + of a Volume within a container. + properties: + mountPath: + description: Path within the container + at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines + how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is + used. This field is beta in 1.10. + type: string + name: + description: This must match the Name + of a Volume. + type: string + readOnly: + description: Mounted read-only if true, + read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + subPath: + description: Path within the volume from + which the container's volume should + be mounted. Defaults to "" (volume's + root). + type: string + subPathExpr: + description: Expanded path within the + volume from which the container's volume + should be mounted. Behaves similarly + to SubPath but environment variable + references $(VAR_NAME) are expanded + using the container's environment. Defaults + to "" (volume's root). SubPathExpr and + SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. + If not specified, the container runtime's + default will be used, which might be configured + in the container image. Cannot be updated. + type: string + required: + - name + type: object + volumes: + description: Volumes is a list of volumes that can + be mounted by containers in a template. + items: + description: Volume represents a named volume + in a pod that may be accessed by any container + in the pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents + an AWS Disk resource that is attached to + a kubelet''s host machine and then exposed + to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem + type of the volume that you want to + mount. Tip: Ensure that the filesystem + type is supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + partition: + description: 'partition is the partition + in the volume that you want to mount. + If omitted, the default is to mount + by volume name. Examples: For volume + /dev/sda1, you specify the partition + as "1". Similarly, the volume partition + for /dev/sda is "0" (or you can leave + the property empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will + force the readOnly setting in VolumeMounts. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of + the persistent disk resource in AWS + (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure + Data Disk mount on the host and bind mount + to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host + Caching mode: None, Read Only, Read + Write.' + type: string + diskName: + description: diskName is the Name of the + data disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data + disk in the blob storage + type: string + fsType: + description: fsType is Filesystem type + to mount. Must be a filesystem type + supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are + Shared: multiple blob disks per storage + account Dedicated: single blob disk + per storage account Managed: azure + managed data disk (only in managed availability + set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure + File Service mount on the host and bind + mount to the pod. + properties: + readOnly: + description: readOnly defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of + secret that contains Azure Storage Account + Name and Key + type: string + shareName: + description: shareName is the azure share + Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount + on the host that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors + is a collection of Ceph monitors More + info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as + the mounted root, rather than the full + Ceph tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here + will force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: + SecretFile is the path to key ring for + User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef + is reference to the authentication secret + for User, default is empty. More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is + the rados user name, default is admin + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume + attached and mounted on kubelets host machine. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if + unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points + to a secret object containing parameters + used to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify + the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap + that should populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: + mode bits used to set permissions on + created files by default. Must be an + octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML + accepts both octal and decimal values, + JSON requires decimal values for mode + bits. Defaults to 0644. Directories + within the path are not affected by + this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + items: + description: items if unspecified, each + key-value pair in the Data field of + the referenced ConfigMap will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will be + projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not present + in the ConfigMap, the volume setup will + error unless it is marked optional. + Paths must be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key to a + path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 or + a decimal value between 0 and + 511. YAML accepts both octal and + decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume defaultMode + will be used. This might be in + conflict with other options that + affect the file mode, like fsGroup, + and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the key + to. May not be an absolute path. + May not contain the path element + '..'. May not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) + represents ephemeral storage that is handled + by certain external CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the + CSI driver that handles this volume. + Consult with your admin for the correct + name as registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", + "xfs", "ntfs". If not provided, the + empty value is passed to the associated + CSI driver which will determine the + default filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a + reference to the secret object containing + sensitive information to pass to the + CSI driver to complete the CSI NodePublishVolume + and NodeUnpublishVolume calls. This + field is optional, and may be empty + if no secret is required. If the secret + object contains more than one secret, + all secret references are passed. + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only + configuration for the volume. Defaults + to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI + driver. Consult your driver's documentation + for supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward + API about the pod that should populate this + volume + properties: + defaultMode: + description: 'Optional: mode bits to use + on created files by default. Must be + a Optional: mode bits used to set permissions + on created files by default. Must be + an octal value between 0000 and 0777 + or a decimal value between 0 and 511. + YAML accepts both octal and decimal + values, JSON requires decimal values + for mode bits. Defaults to 0644. Directories + within the path are not affected by + this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + items: + description: Items is a list of downward + API volume file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only annotations, + labels, name and namespace are + supported.' + properties: + apiVersion: + description: Version of the + schema the FieldPath is written + in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field + to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits + used to set permissions on this + file, must be an octal value between + 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts + both octal and decimal values, + JSON requires decimal values for + mode bits. If not specified, the + volume defaultMode will be used. + This might be in conflict with + other options that affect the + file mode, like fsGroup, and the + result can be other mode bits + set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file + to be created. Must not be absolute + or contain the ''..'' path. Must + be utf-8 encoded. The first item + of the relative path must not + start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource + of the container: only resources + limits and requests (limits.cpu, + limits.memory, requests.cpu and + requests.memory) are currently + supported.' + properties: + containerName: + description: 'Container name: + required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary + directory that shares a pod''s lifetime. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type + of storage medium should back this directory. + The default is "" which means to use + the node''s default medium. Must be + an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount + of local storage required for this EmptyDir + volume. The size limit is also applicable + for memory medium. The maximum usage + on memory medium EmptyDir would be the + minimum value between the SizeLimit + specified here and the sum of memory + limits of all containers in a pod. The + default is nil which means that the + limit is undefined. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume + that is handled by a cluster storage driver. + The volume's lifecycle is tied to the pod + that defines it - it will be created before + the pod starts, and deleted when the pod + is removed. \n Use this if: a) the volume + is only needed while the pod runs, b) features + of normal volumes like restoring from snapshot + or capacity tracking are needed, c) the + storage driver is specified through a storage + class, and d) the storage driver supports + dynamic volume provisioning through a PersistentVolumeClaim + (see EphemeralVolumeSource for more information + on the connection between this volume type + and PersistentVolumeClaim). \n Use PersistentVolumeClaim + or one of the vendor-specific APIs for volumes + that persist for longer than the lifecycle + of an individual pod. \n Use CSI for light-weight + local ephemeral volumes if the CSI driver + is meant to be used that way - see the documentation + of the driver for more information. \n A + pod can use both types of ephemeral volumes + and persistent volumes at the same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a + stand-alone PVC to provision the volume. + The pod in which this EphemeralVolumeSource + is embedded will be the owner of the + PVC, i.e. the PVC will be deleted together + with the pod. The name of the PVC will + be `-` where + `` is the name from the + `PodSpec.Volumes` array entry. Pod validation + will reject the pod if the concatenated + name is not valid for a PVC (for example, + too long). \n An existing PVC with that + name that is not owned by the pod will + *not* be used for the pod to avoid using + an unrelated volume by mistake. Starting + the pod is then blocked until the unrelated + PVC is removed. If such a pre-created + PVC is meant to be used by the pod, + the PVC has to updated with an owner + reference to the pod once the pod exists. + Normally this should not be necessary, + but it may be useful when manually reconstructing + a broken cluster. \n This field is read-only + and no changes will be made by Kubernetes + to the PVC after it has been created. + \n Required, must not be nil." + properties: + metadata: + description: May contain labels and + annotations that will be copied + into the PVC when creating it. No + other fields are allowed and will + be rejected during validation. + type: object + spec: + description: The specification for + the PersistentVolumeClaim. The entire + content is copied unchanged into + the PVC that gets created from this + template. The same fields as in + a PersistentVolumeClaim are also + valid here. + properties: + accessModes: + description: 'accessModes contains + the desired access modes the + volume should have. More info: + https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field + can be used to specify either: + * An existing VolumeSnapshot + object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external + controller can support the specified + data source, it will create + a new volume based on the contents + of the specified data source. + When the AnyVolumeDataSource + feature gate is enabled, dataSource + contents will be copied to dataSourceRef, + and dataSourceRef contents will + be copied to dataSource when + dataSourceRef.namespace is not + specified. If the namespace + is specified, then dataSourceRef + will not be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the + group for the resource being + referenced. If APIGroup + is not specified, the specified + Kind must be in the core + API group. For any other + third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies + the object from which to populate + the volume with data, if a non-empty + volume is desired. This may + be any object from a non-empty + API group (non core object) + or a PersistentVolumeClaim object. + When this field is specified, + volume binding will only succeed + if the type of the specified + object matches some installed + volume populator or dynamic + provisioner. This field will + replace the functionality of + the dataSource field and as + such if both fields are non-empty, + they must have the same value. + For backwards compatibility, + when namespace isn''t specified + in dataSourceRef, both fields + (dataSource and dataSourceRef) + will be set to the same value + automatically if one of them + is empty and the other is non-empty. + When namespace is specified + in dataSourceRef, dataSource + isn''t set to the same value + and must be empty. There are + three important differences + between dataSource and dataSourceRef: + * While dataSource only allows + two specific types of objects, + dataSourceRef allows any non-core + object, as well as PersistentVolumeClaim + objects. * While dataSource + ignores disallowed values (dropping + them), dataSourceRef preserves + all values, and generates an + error if a disallowed value + is specified. * While dataSource + only allows local objects, dataSourceRef + allows objects in any namespaces. + (Beta) Using this field requires + the AnyVolumeDataSource feature + gate to be enabled. (Alpha) + Using the namespace field of + dataSourceRef requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the + group for the resource being + referenced. If APIGroup + is not specified, the specified + Kind must be in the core + API group. For any other + third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + namespace: + description: Namespace is + the namespace of resource + being referenced Note that + when a namespace is specified, + a gateway.networking.k8s.io/ReferenceGrant + object is required in the + referent namespace to allow + that namespace's owner to + accept the reference. See + the ReferenceGrant documentation + for details. (Alpha) This + field requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents + the minimum resources the volume + should have. If RecoverVolumeExpansionFailure + feature is enabled users are + allowed to specify resource + requirements that are lower + than previous value but must + still be higher than capacity + recorded in the status field + of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists + the names of resources, + defined in spec.resourceClaims, + that are used by this container. + \n This is an alpha field + and requires enabling the + DynamicResourceAllocation + feature gate. \n This field + is immutable. It can only + be set for containers." + items: + description: ResourceClaim + references one entry in + PodSpec.ResourceClaims. + properties: + name: + description: Name must + match the name of + one entry in pod.spec.resourceClaims + of the Pod where this + field is used. It + makes that resource + available inside a + container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes + the maximum amount of compute + resources allowed. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes + the minimum amount of compute + resources required. If Requests + is omitted for a container, + it defaults to Limits if + that is explicitly specified, + otherwise to an implementation-defined + value. Requests cannot exceed + Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label + query over volumes to consider + for binding. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, + a key, and an operator + that relates the key and + values. + properties: + key: + description: key is + the label key that + the selector applies + to. + type: string + operator: + description: operator + represents a key's + relationship to a + set of values. Valid + operators are In, + NotIn, Exists and + DoesNotExist. + type: string + values: + description: values + is an array of string + values. If the operator + is In or NotIn, the + values array must + be non-empty. If the + operator is Exists + or DoesNotExist, the + values array must + be empty. This array + is replaced during + a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is + a map of {key,value} pairs. + A single {key,value} in + the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", + the operator is "In", and + the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName + is the name of the StorageClass + required by the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines + what type of volume is required + by the claim. Value of Filesystem + is implied when not included + in claim spec. + type: string + volumeName: + description: volumeName is the + binding reference to the PersistentVolume + backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel + resource that is attached to a kubelet's + host machine and then exposed to the pod. + properties: + fsType: + description: 'fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target + lun number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here + will force the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: + FC target worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume + world wide identifiers (wwids) Either + wwids or combination of targetWWNs and + lun must be set, but not both simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic + volume resource that is provisioned/attached + using an exec based plugin. + properties: + driver: + description: driver is the name of the + driver to use for this volume. + type: string + fsType: + description: fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". The + default filesystem depends on FlexVolume + script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this + field holds extra command options if + any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults + to false (read/write). ReadOnly here + will force the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef + is reference to the secret object containing + sensitive information to pass to the + plugin scripts. This may be empty if + no secret object is specified. If the + secret object contains more than one + secret, all secrets are passed to the + plugin scripts.' + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker + volume attached to a kubelet's host machine. + This depends on the Flocker control service + being running + properties: + datasetName: + description: datasetName is Name of the + dataset stored as metadata -> name on + the dataset for Flocker should be considered + as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of + the dataset. This is unique identifier + of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents + a GCE Disk resource that is attached to + a kubelet''s host machine and then exposed + to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type + of the volume that you want to mount. + Tip: Ensure that the filesystem type + is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + partition: + description: 'partition is the partition + in the volume that you want to mount. + If omitted, the default is to mount + by volume name. Examples: For volume + /dev/sda1, you specify the partition + as "1". Similarly, the volume partition + for /dev/sda is "0" (or you can leave + the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of + the PD resource in GCE. Used to identify + the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force + the ReadOnly setting in VolumeMounts. + Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository + at a particular revision. DEPRECATED: GitRepo + is deprecated. To provision a container + with a git repo, mount an EmptyDir into + an InitContainer that clones the repo using + git, then mount the EmptyDir into the Pod''s + container.' + properties: + directory: + description: directory is the target directory + name. Must not contain or start with + '..'. If '.' is supplied, the volume + directory will be the git repository. Otherwise, + if specified, the volume will contain + the git repository in the subdirectory + with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash + for the specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint + name that details Glusterfs topology. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume + path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force + the Glusterfs volume to be mounted with + read-only permissions. Defaults to false. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing + file or directory on the host machine that + is directly exposed to the container. This + is generally used for system agents or other + privileged things that are allowed to see + the host machine. Most containers will NOT + need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who + can use host directory mounts and who can/can + not mount host directories as read/write.' + properties: + path: + description: 'path of the directory on + the host. If the path is a symlink, + it will follow the link to the real + path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume + Defaults to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk + resource that is attached to a kubelet''s + host machine and then exposed to the pod. + More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines + whether support iSCSI Discovery CHAP + authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether + support iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem + type of the volume that you want to + mount. Tip: Ensure that the filesystem + type is supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom + iSCSI Initiator Name. If initiatorName + is specified with iscsiInterface simultaneously, + new iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified + Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface + Name that uses an iSCSI transport. Defaults + to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target + Lun number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target + Portal List. The portal is either an + IP or ip_addr:port if the port is other + than default (typically TCP ports 860 + and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force + the ReadOnly setting in VolumeMounts. + Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret + for iSCSI target and initiator authentication + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target + Portal. The Portal is either an IP or + ip_addr:port if the port is other than + default (typically TCP ports 860 and + 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be + a DNS_LABEL and unique within the pod. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount + on the host that shares a pod''s lifetime + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by + the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force + the NFS export to be mounted with read-only + permissions. Defaults to false. More + info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or + IP address of the NFS server. More info: + https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource + represents a reference to a PersistentVolumeClaim + in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of + a PersistentVolumeClaim in the same + namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents + a PhotonController persistent disk attached + and mounted on kubelets host machine + properties: + fsType: + description: fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies + Photon Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx + volume attached and mounted on kubelets + host machine + properties: + fsType: + description: fSType represents the filesystem + type to mount Must be a filesystem type + supported by the host operating system. + Ex. "ext4", "xfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies + a Portworx volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one + resources secrets, configmaps, and downward + API + properties: + defaultMode: + description: defaultMode are the mode + bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both + octal and decimal values, JSON requires + decimal values for mode bits. Directories + within the path are not affected by + this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume + projections + items: + description: Projection that may be + projected along with other supported + volume types + properties: + configMap: + description: configMap information + about the configMap data to project + properties: + items: + description: items if unspecified, + each key-value pair in the + Data field of the referenced + ConfigMap will be projected + into the volume as a file + whose name is the key and + content is the value. If specified, + the listed keys will be projected + into the specified paths, + and unlisted keys will not + be present. If a key is specified + which is not present in the + ConfigMap, the volume setup + will error unless it is marked + optional. Paths must be relative + and may not contain the '..' + path or start with '..'. + items: + description: Maps a string + key to a path within a volume. + properties: + key: + description: key is the + key to project. + type: string + mode: + description: 'mode is + Optional: mode bits + used to set permissions + on this file. Must be + an octal value between + 0000 and 0777 or a decimal + value between 0 and + 511. YAML accepts both + octal and decimal values, + JSON requires decimal + values for mode bits. + If not specified, the + volume defaultMode will + be used. This might + be in conflict with + other options that affect + the file mode, like + fsGroup, and the result + can be other mode bits + set.' + format: int32 + type: integer + path: + description: path is the + relative path of the + file to map the key + to. May not be an absolute + path. May not contain + the path element '..'. + May not start with the + string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: optional specify + whether the ConfigMap or its + keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information + about the downwardAPI data to + project + properties: + items: + description: Items is a list + of DownwardAPIVolume file + items: + description: DownwardAPIVolumeFile + represents information to + create the file containing + the pod field + properties: + fieldRef: + description: 'Required: + Selects a field of the + pod: only annotations, + labels, name and namespace + are supported.' + properties: + apiVersion: + description: Version + of the schema the + FieldPath is written + in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path + of the field to + select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: + mode bits used to set + permissions on this + file, must be an octal + value between 0000 and + 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and + decimal values, JSON + requires decimal values + for mode bits. If not + specified, the volume + defaultMode will be + used. This might be + in conflict with other + options that affect + the file mode, like + fsGroup, and the result + can be other mode bits + set.' + format: int32 + type: integer + path: + description: 'Required: + Path is the relative + path name of the file + to be created. Must + not be absolute or contain + the ''..'' path. Must + be utf-8 encoded. The + first item of the relative + path must not start + with ''..''' + type: string + resourceFieldRef: + description: 'Selects + a resource of the container: + only resources limits + and requests (limits.cpu, + limits.memory, requests.cpu + and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container + name: required for + volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies + the output format + of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: + resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information + about the secret data to project + properties: + items: + description: items if unspecified, + each key-value pair in the + Data field of the referenced + Secret will be projected into + the volume as a file whose + name is the key and content + is the value. If specified, + the listed keys will be projected + into the specified paths, + and unlisted keys will not + be present. If a key is specified + which is not present in the + Secret, the volume setup will + error unless it is marked + optional. Paths must be relative + and may not contain the '..' + path or start with '..'. + items: + description: Maps a string + key to a path within a volume. + properties: + key: + description: key is the + key to project. + type: string + mode: + description: 'mode is + Optional: mode bits + used to set permissions + on this file. Must be + an octal value between + 0000 and 0777 or a decimal + value between 0 and + 511. YAML accepts both + octal and decimal values, + JSON requires decimal + values for mode bits. + If not specified, the + volume defaultMode will + be used. This might + be in conflict with + other options that affect + the file mode, like + fsGroup, and the result + can be other mode bits + set.' + format: int32 + type: integer + path: + description: path is the + relative path of the + file to map the key + to. May not be an absolute + path. May not contain + the path element '..'. + May not start with the + string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: optional field + specify whether the Secret + or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken + is information about the serviceAccountToken + data to project + properties: + audience: + description: audience is the + intended audience of the token. + A recipient of a token must + identify itself with an identifier + specified in the audience + of the token, and otherwise + should reject the token. The + audience defaults to the identifier + of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds + is the requested duration + of validity of the service + account token. As the token + approaches expiration, the + kubelet volume plugin will + proactively rotate the service + account token. The kubelet + will start trying to rotate + the token if the token is + older than 80 percent of its + time to live or if the token + is older than 24 hours.Defaults + to 1 hour and must be at least + 10 minutes. + format: int64 + type: integer + path: + description: path is the path + relative to the mount point + of the file to project the + token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte + mount on the host that shares a pod's lifetime + properties: + group: + description: group to map volume access + to Default is no group + type: string + readOnly: + description: readOnly here will force + the Quobyte volume to be mounted with + read-only permissions. Defaults to false. + type: boolean + registry: + description: registry represents a single + or multiple Quobyte Registry services + specified as a string as host:port pair + (multiple entries are separated with + commas) which acts as the central registry + for volumes + type: string + tenant: + description: tenant owning the given Quobyte + volume in the Backend Used with dynamically + provisioned Quobyte volumes, value is + set by the plugin + type: string + user: + description: user to map volume access + to Defaults to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by + name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block + Device mount on the host that shares a pod''s + lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem + type of the volume that you want to + mount. Tip: Ensure that the filesystem + type is supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + image: + description: 'image is the rados image + name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key + ring for RBDUser. Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection + of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. + Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force + the ReadOnly setting in VolumeMounts. + Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the + authentication secret for RBDUser. If + provided overrides keyring. Default + is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. + Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO + persistent volume attached and mounted on + Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Default + is "xfs". + type: string + gateway: + description: gateway is the host address + of the ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name + of the ScaleIO Protection Domain for + the configured storage. + type: string + readOnly: + description: readOnly Defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the + secret for ScaleIO user and other sensitive + information. If this is not provided, + Login operation will fail. + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable + SSL communication with Gateway, default + false + type: boolean + storageMode: + description: storageMode indicates whether + the storage for a volume should be ThickProvisioned + or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO + Storage Pool associated with the protection + domain. + type: string + system: + description: system is the name of the + storage system as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of + a volume already created in the ScaleIO + system that is associated with this + volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that + should populate this volume. More info: + https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: + mode bits used to set permissions on + created files by default. Must be an + octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML + accepts both octal and decimal values, + JSON requires decimal values for mode + bits. Defaults to 0644. Directories + within the path are not affected by + this setting. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + items: + description: items If unspecified, each + key-value pair in the Data field of + the referenced Secret will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will be + projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not present + in the Secret, the volume setup will + error unless it is marked optional. + Paths must be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key to a + path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 or + a decimal value between 0 and + 511. YAML accepts both octal and + decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume defaultMode + will be used. This might be in + conflict with other options that + affect the file mode, like fsGroup, + and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the key + to. May not be an absolute path. + May not contain the path element + '..'. May not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether + the Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of + the secret in the pod''s namespace to + use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS + volume attached and mounted on Kubernetes + nodes. + properties: + fsType: + description: fsType is the filesystem + type to mount. Must be a filesystem + type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false + (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret + to use for obtaining the StorageOS API + credentials. If not specified, default + values will be attempted. + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable + name of the StorageOS volume. Volume + names are only unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies + the scope of the volume within StorageOS. If + no namespace is specified then the Pod's + namespace will be used. This allows + the Kubernetes name scoping to be mirrored + within StorageOS for tighter integration. + Set VolumeName to any name to override + the default behaviour. Set to "default" + if you are not using namespaces within + StorageOS. Namespaces that do not pre-exist + within StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere + volume attached and mounted on kubelets + host machine + properties: + fsType: + description: fsType is filesystem type + to mount. Must be a filesystem type + supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage + Policy Based Management (SPBM) profile + ID associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the + storage Policy Based Management (SPBM) + profile name. + type: string + volumePath: + description: volumePath is the path that + identifies vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + templateType: + type: string + timeChaos: + description: TimeChaosSpec defines the desired state + of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock + id All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the + name of affected container. If not set, the first + container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of + the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of + injected program. It's a possibly signed sequence + of decimal numbers, such as "300ms", "-1.5h" or + "2h45m". Valid time units are "ns", "us" (or "µs"), + "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + required: + - name + - templateType + type: object + type: array + required: + - entry + - templates + type: object + required: + - schedule + - type + type: object + startTime: + format: date-time + type: string + statusCheck: + description: StatusCheck describe the behavior of StatusCheck. Only + used when Type is TypeStatusCheck. + properties: + duration: + description: Duration defines the duration of the whole status + check if the number of failed execution does not exceed the + failure threshold. Duration is available to both `Synchronous` + and `Continuous` mode. 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum consecutive + failure for the status check to be considered failed. + minimum: 1 + type: integer + http: + properties: + body: + type: string + criteria: + description: Criteria defines how to determine the result + of the status check. + properties: + statusCode: + description: StatusCode defines the expected http status + code for the request. A statusCode string could be a + single code (e.g. 200), or an inclusive range (e.g. + 200-400, both `200` and `400` are included). + type: string + required: + - statusCode + type: object + headers: + additionalProperties: + items: + type: string + type: array + description: "A Header represents the key-value pairs in an + HTTP header. \n The keys should be in canonical form, as + returned by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in seconds) to + perform an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of the status check. + Support type: Synchronous / Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number of record + to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum consecutive + successes for the status check to be considered successful. + SuccessThreshold only works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of seconds after + which an execution of status check times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check type. Support + type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + stressChaos: + description: StressChaosSpec defines the desired state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors just + like `Stressors` except that it's an experimental feature and + more powerful. You can define stressors in `stress-ng` (see + also `man stress-ng`) dialect, however not all of the supported + stressors are well tested. It maybe retired in later releases. + You should always use `Stressors` to define the stressors and + use this only when you want more stressors unsupported by `Stressors`. + When both `StressngStressors` and `Stressors` are defined, `StressngStressors` + wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported to + stress system components out. You can use one or more of them + to make up various kinds of stresses. At least one of the stressors + should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading per CPU + worker. 0 is effectively a sleep (no load) and 100 is + full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: Workers specifies N workers to apply the + stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + memory: + description: MemoryStressor stresses virtual memory out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj of the + stress process. See `man 5 proc` to know more about + this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per vm worker, + default is the total available memory. One can specify + the size as % of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to apply the + stressor. Maximum 8192 workers can run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + type: object + task: + properties: + container: + description: Container is the main container image to run in the + pod + properties: + args: + description: 'Arguments to the entrypoint. The container image''s + CMD is used if this is not provided. Variable references + $(VAR_NAME) are expanded using the container''s environment. + If a variable cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced to a single + $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of + whether the variable exists or not. Cannot be updated. More + info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within a shell. + The container image''s ENTRYPOINT is used if this is not + provided. Variable references $(VAR_NAME) are expanded using + the container''s environment. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double + $$ are reduced to a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references will + never be expanded, regardless of whether the variable exists + or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables + in the container and any service environment variables. + If a variable cannot be resolved, the reference in + the input string will be unchanged. Double $$ are + reduced to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment variables + in the container. The keys defined within a source must + be a C_IDENTIFIER. All invalid keys will be reported as + an event when the container is starting. When a key exists + in multiple sources, the value associated with the last + source will take precedence. Values defined by an Env with + a duplicate key will take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to each + key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management + to default or override container images in workload controllers + like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent + otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system should take + in response to container lifecycle events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately after a + container is created. If the handler fails, the container + is terminated and restarted according to its restart + policy. Other management of the container blocks until + the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory + for the command is root ('/') in the container's + filesystem. The command is simply exec'd, it + is not run inside a shell, so traditional shell + instructions ('|', etc) won't work. To use a + shell, you need to explicitly call out to that + shell. Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to + perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the + host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of this field + and lifecycle hooks will fail in runtime when tcp + handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately before a container + is terminated due to an API request or management event + such as liveness/startup probe failure, preemption, + resource contention, etc. The handler is not called + if the container crashes or exits. The Pod''s termination + grace period countdown begins before the PreStop hook + is executed. Regardless of the outcome of the handler, + the container will eventually terminate within the Pod''s + termination grace period (unless delayed by finalizers). + Other management of the container blocks until the hook + completes or until the termination grace period is reached. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory + for the command is root ('/') in the container's + filesystem. The command is simply exec'd, it + is not run inside a shell, so traditional shell + instructions ('|', etc) won't work. To use a + shell, you need to explicitly call out to that + shell. Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to + perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the + host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of this field + and lifecycle hooks will fail in runtime when tcp + handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. Container + will be restarted if the probe fails. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', + etc) won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC + port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a + TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and + the time when the processes are forcibly halted with + a kill signal. Set this value longer than the expected + cleanup time for your process. If this value is nil, + the pod's terminationGracePeriodSeconds will be used. + Otherwise, this value overrides the value provided by + the pod spec. Value must be non-negative integer. The + value zero indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta field + and requires enabling ProbeTerminationGracePeriod feature + gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe + times out. Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. Not + specifying a port here DOES NOT prevent that port from being + exposed. Any port which is listening on the default "0.0.0.0" + address inside a container will be accessible from the network. + Modifying this array with strategic merge patch may corrupt + the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port in + a single container. + properties: + containerPort: + description: Number of port to expose on the pod's IP + address. This must be a valid port number, 0 < x < + 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external port + to. + type: string + hostPort: + description: Number of port to expose on the host. If + specified, this must be a valid port number, 0 < x + < 65536. If HostNetwork is specified, this must match + ContainerPort. Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an IANA_SVC_NAME + and unique within the pod. Each named port in a pod + must have a unique name. Name for the port that can + be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, TCP, or + SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service readiness. + Container will be removed from service endpoints if the + probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', + etc) won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC + port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a + TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and + the time when the processes are forcibly halted with + a kill signal. Set this value longer than the expected + cleanup time for your process. If this value is nil, + the pod's terminationGracePeriodSeconds will be used. + Otherwise, this value overrides the value provided by + the pod spec. Value must be non-negative integer. The + value zero indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta field + and requires enabling ProbeTerminationGracePeriod feature + gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe + times out. Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource resize + policy for the container. + properties: + resourceName: + description: 'Name of the resource to which this resource + resize policy applies. Supported values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when specified + resource is resized. If not specified, it defaults + to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this container. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. \n This field + is immutable. It can only be set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry + in pod.spec.resourceClaims of the Pod where this + field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of + compute resources required. If Requests is omitted for + a container, it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined value. + Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + restartPolicy: + description: 'RestartPolicy defines the restart behavior of + individual containers in a pod. This field may only be set + for init containers, and the only allowed value is "Always". + For non-init containers or when this field is not specified, + the restart behavior is defined by the Pod''s restart policy + and the container type. Setting the RestartPolicy as "Always" + for the init container will have the following effect: this + init container will be continually restarted on exit until + all regular containers have terminated. Once all regular + containers have completed, all init containers with restartPolicy + "Always" will be shut down. This lifecycle differs from + normal init containers and is often referred to as a "sidecar" + container. Although this init container still starts in + the init container sequence, it does not wait for the container + to complete before proceeding to the next init container. + Instead, the next init container starts immediately after + this init container is started, or after any startupProbe + has successfully completed.' + type: string + securityContext: + description: 'SecurityContext defines the security options + the container should be run with. If set, the fields of + SecurityContext override the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether + a process can gain more privileges than its parent process. + This bool directly controls if the no_new_privs flag + will be set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run as Privileged + 2) has CAP_SYS_ADMIN Note that this field cannot be + set when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running + containers. Defaults to the default set of capabilities + granted by the container runtime. Note that this field + cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes + in privileged containers are essentially equivalent + to root on the host. Defaults to false. Note that this + field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc mount + to use for the containers. The default is DefaultProcMount + which uses the container runtime defaults for readonly + paths and masked paths. This requires the ProcMountType + feature flag to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root + filesystem. Default is false. Note that this field cannot + be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set + when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as + a non-root user. If true, the Kubelet will validate + the image at runtime to ensure that it does not run + as UID 0 (root) and fail to start the container if it + does. If unset or false, no such validation will be + performed. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container + process. Defaults to user specified in image metadata + if unspecified. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to the + container. If unspecified, the container runtime will + allocate a random SELinux context for each container. May + also be set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set + when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this container. + If seccomp options are provided at both the pod & container + level, the container options override the pod options. + Note that this field cannot be set when spec.os.name + is windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. The + profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's + configured seccomp profile location. Must be set + if type is "Localhost". Must NOT be set for any + other type. + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: \n Localhost + - a profile defined in a file on the node should + be used. RuntimeDefault - the container runtime + default profile should be used. Unconfined - no + profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied to + all containers. If unspecified, the options from the + PodSecurityContext will be used. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set + when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA + admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec + named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of + the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. All + of a Pod's containers must have the same effective + HostProcess value (it is not allowed to have a mix + of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork + must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set + in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the Pod has successfully + initialized. If specified, no other probes are executed + until this completes successfully. If this probe fails, + the Pod will be restarted, just as if the livenessProbe + failed. This can be used to provide different probe parameters + at the beginning of a Pod''s lifecycle, when it might take + a long time to load data or warm a cache, than during steady-state + operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', + etc) won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC + port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a + TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and + the time when the processes are forcibly halted with + a kill signal. Set this value longer than the expected + cleanup time for your process. If this value is nil, + the pod's terminationGracePeriodSeconds will be used. + Otherwise, this value overrides the value provided by + the pod spec. Value must be non-negative integer. The + value zero indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta field + and requires enabling ProbeTerminationGracePeriod feature + gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe + times out. Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate a buffer + for stdin in the container runtime. If this is not set, + reads from stdin in the container will always result in + EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close the + stdin channel after it has been opened by a single attach. + When stdin is true the stdin stream will remain open across + multiple attach sessions. If stdinOnce is set to true, stdin + is opened on container start, is empty until the first client + attaches to stdin, and then remains open and accepts data + until the client disconnects, at which time stdin is closed + and remains closed until the container is restarted. If + this flag is false, a container processes that reads from + stdin will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to which the + container''s termination message will be written is mounted + into the container''s filesystem. Message written is intended + to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. + The total message length across all containers will be limited + to 12kb. Defaults to /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message should be + populated. File will use the contents of terminationMessagePath + to populate the container status message on both success + and failure. FallbackToLogsOnError will use the last chunk + of container log output if the termination message file + is empty and the container exited with an error. The log + output is limited to 2048 bytes or 80 lines, whichever is + smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate a TTY + for itself, also requires 'stdin' to be true. Default is + false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to + be used by the container. + items: + description: volumeDevice describes a mapping of a raw block + device within a container. + properties: + devicePath: + description: devicePath is the path inside of the container + that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's filesystem. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a Volume + within a container. + properties: + mountPath: + description: Path within the container at which the + volume should be mounted. Must not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts + are propagated from the host to container and the + other way around. When not set, MountPropagationNone + is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write otherwise + (false or unspecified). Defaults to false. + type: boolean + subPath: + description: Path within the volume from which the container's + volume should be mounted. Defaults to "" (volume's + root). + type: string + subPathExpr: + description: Expanded path within the volume from which + the container's volume should be mounted. Behaves + similarly to SubPath but environment variable references + $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). SubPathExpr and SubPath + are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not specified, + the container runtime's default will be used, which might + be configured in the container image. Cannot be updated. + type: string + required: + - name + type: object + volumes: + description: Volumes is a list of volumes that can be mounted + by containers in a template. + items: + description: Volume represents a named volume in a pod that + may be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents an AWS Disk + resource that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume + that you want to mount. If omitted, the default is + to mount by volume name. Examples: For volume /dev/sda1, + you specify the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can leave the + property empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force the readOnly + setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the persistent + disk resource in AWS (Amazon EBS volume). More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data Disk mount + on the host and bind mount to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching mode: + None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data disk in + the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in the + blob storage + type: string + fsType: + description: fsType is Filesystem type to mount. Must + be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: multiple + blob disks per storage account Dedicated: single + blob disk per storage account Managed: azure managed + data disk (only in managed availability set). defaults + to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File Service + mount on the host and bind mount to the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret that + contains Azure Storage Account Name and Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount on the host + that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors is a collection + of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the mounted + root, rather than the full Ceph tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile is + the path to key ring for User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef is reference + to the authentication secret for User, default is + empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the rados user + name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume attached + and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points to a secret + object containing parameters used to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the volume in + cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that should + populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value pair + in the Data field of the referenced ConfigMap will + be projected into the volume as a file whose name + is the key and content is the value. If specified, + the listed keys will be projected into the specified + paths, and unlisted keys will not be present. If a + key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. + Paths must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within a + volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used + to set permissions on this file. Must be an + octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal values + for mode bits. If not specified, the volume + defaultMode will be used. This might be in conflict + with other options that affect the file mode, + like fsGroup, and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative path of the + file to map the key to. May not be an absolute + path. May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents + ephemeral storage that is handled by certain external + CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI driver that + handles this volume. Consult with your admin for the + correct name as registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the + associated CSI driver which will determine the default + filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference to + the secret object containing sensitive information + to pass to the CSI driver to complete the CSI NodePublishVolume + and NodeUnpublishVolume calls. This field is optional, + and may be empty if no secret is required. If the + secret object contains more than one secret, all secret + references are passed. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only configuration + for the volume. Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. Consult + your driver's documentation for supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API about the + pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on created + files by default. Must be a Optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + items: + description: Items is a list of downward API volume + file + items: + description: DownwardAPIVolumeFile represents information + to create the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects a field of the + pod: only annotations, labels, name and namespace + are supported.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used to set + permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for mode + bits. If not specified, the volume defaultMode + will be used. This might be in conflict with + other options that affect the file mode, like + fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must not + be absolute or contain the ''..'' path. Must + be utf-8 encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary directory + that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type of storage + medium should back this directory. The default is + "" which means to use the node''s default medium. + Must be an empty string (default) or Memory. More + info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount of local + storage required for this EmptyDir volume. The size + limit is also applicable for memory medium. The maximum + usage on memory medium EmptyDir would be the minimum + value between the SizeLimit specified here and the + sum of memory limits of all containers in a pod. The + default is nil which means that the limit is undefined. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume that is handled + by a cluster storage driver. The volume's lifecycle is + tied to the pod that defines it - it will be created before + the pod starts, and deleted when the pod is removed. \n + Use this if: a) the volume is only needed while the pod + runs, b) features of normal volumes like restoring from + snapshot or capacity tracking are needed, c) the storage + driver is specified through a storage class, and d) the + storage driver supports dynamic volume provisioning through + a PersistentVolumeClaim (see EphemeralVolumeSource for + more information on the connection between this volume + type and PersistentVolumeClaim). \n Use PersistentVolumeClaim + or one of the vendor-specific APIs for volumes that persist + for longer than the lifecycle of an individual pod. \n + Use CSI for light-weight local ephemeral volumes if the + CSI driver is meant to be used that way - see the documentation + of the driver for more information. \n A pod can use both + types of ephemeral volumes and persistent volumes at the + same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone PVC + to provision the volume. The pod in which this EphemeralVolumeSource + is embedded will be the owner of the PVC, i.e. the + PVC will be deleted together with the pod. The name + of the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` + array entry. Pod validation will reject the pod if + the concatenated name is not valid for a PVC (for + example, too long). \n An existing PVC with that name + that is not owned by the pod will *not* be used for + the pod to avoid using an unrelated volume by mistake. + Starting the pod is then blocked until the unrelated + PVC is removed. If such a pre-created PVC is meant + to be used by the pod, the PVC has to updated with + an owner reference to the pod once the pod exists. + Normally this should not be necessary, but it may + be useful when manually reconstructing a broken cluster. + \n This field is read-only and no changes will be + made by Kubernetes to the PVC after it has been created. + \n Required, must not be nil." + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when creating + it. No other fields are allowed and will be rejected + during validation. + type: object + spec: + description: The specification for the PersistentVolumeClaim. + The entire content is copied unchanged into the + PVC that gets created from this template. The + same fields as in a PersistentVolumeClaim are + also valid here. + properties: + accessModes: + description: 'accessModes contains the desired + access modes the volume should have. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can be used to + specify either: * An existing VolumeSnapshot + object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller + can support the specified data source, it + will create a new volume based on the contents + of the specified data source. When the AnyVolumeDataSource + feature gate is enabled, dataSource contents + will be copied to dataSourceRef, and dataSourceRef + contents will be copied to dataSource when + dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef + will not be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the group for the + resource being referenced. If APIGroup + is not specified, the specified Kind must + be in the core API group. For any other + third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies the object + from which to populate the volume with data, + if a non-empty volume is desired. This may + be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding + will only succeed if the type of the specified + object matches some installed volume populator + or dynamic provisioner. This field will replace + the functionality of the dataSource field + and as such if both fields are non-empty, + they must have the same value. For backwards + compatibility, when namespace isn''t specified + in dataSourceRef, both fields (dataSource + and dataSourceRef) will be set to the same + value automatically if one of them is empty + and the other is non-empty. When namespace + is specified in dataSourceRef, dataSource + isn''t set to the same value and must be empty. + There are three important differences between + dataSource and dataSourceRef: * While dataSource + only allows two specific types of objects, + dataSourceRef allows any non-core object, + as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values + (dropping them), dataSourceRef preserves all + values, and generates an error if a disallowed + value is specified. * While dataSource only + allows local objects, dataSourceRef allows + objects in any namespaces. (Beta) Using this + field requires the AnyVolumeDataSource feature + gate to be enabled. (Alpha) Using the namespace + field of dataSourceRef requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the group for the + resource being referenced. If APIGroup + is not specified, the specified Kind must + be in the core API group. For any other + third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: Namespace is the namespace + of resource being referenced Note that + when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent namespace + to allow that namespace's owner to accept + the reference. See the ReferenceGrant + documentation for details. (Alpha) This + field requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents the minimum + resources the volume should have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed to specify + resource requirements that are lower than + previous value but must still be higher than + capacity recorded in the status field of the + claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the names of + resources, defined in spec.resourceClaims, + that are used by this container. \n This + is an alpha field and requires enabling + the DynamicResourceAllocation feature + gate. \n This field is immutable. It can + only be set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum + amount of compute resources allowed. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. + If Requests is omitted for a container, + it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined + value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName is the name of + the StorageClass required by the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type of + volume is required by the claim. Value of + Filesystem is implied when not included in + claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource that + is attached to a kubelet's host machine and then exposed + to the pod. + properties: + fsType: + description: 'fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. TODO: how do we prevent + errors in the filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target worldwide + names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume world wide identifiers + (wwids) Either wwids or combination of targetWWNs + and lun must be set, but not both simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume resource + that is provisioned/attached using an exec based plugin. + properties: + driver: + description: driver is the name of the driver to use + for this volume. + type: string + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". The default filesystem + depends on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field holds + extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef is reference + to the secret object containing sensitive information + to pass to the plugin scripts. This may be empty if + no secret object is specified. If the secret object + contains more than one secret, all secrets are passed + to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume attached + to a kubelet's host machine. This depends on the Flocker + control service being running + properties: + datasetName: + description: datasetName is Name of the dataset stored + as metadata -> name on the dataset for Flocker should + be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. + This is unique identifier of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE Disk resource + that is attached to a kubelet''s host machine and then + exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume + that you want to mount. If omitted, the default is + to mount by volume name. Examples: For volume /dev/sda1, + you specify the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can leave the + property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the PD resource + in GCE. Used to identify the disk in GCE. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository at a particular + revision. DEPRECATED: GitRepo is deprecated. To provision + a container with a git repo, mount an EmptyDir into an + InitContainer that clones the repo using git, then mount + the EmptyDir into the Pod''s container.' + properties: + directory: + description: directory is the target directory name. + Must not contain or start with '..'. If '.' is supplied, + the volume directory will be the git repository. Otherwise, + if specified, the volume will contain the git repository + in the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the specified + revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs mount on + the host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name that details + Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume path. More + info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the Glusterfs + volume to be mounted with read-only permissions. Defaults + to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing file or + directory on the host machine that is directly exposed + to the container. This is generally used for system agents + or other privileged things that are allowed to see the + host machine. Most containers will NOT need this. More + info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can use host + directory mounts and who can/can not mount host directories + as read/write.' + properties: + path: + description: 'path of the directory on the host. If + the path is a symlink, it will follow the link to + the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults to "" + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource that + is attached to a kubelet''s host machine and then exposed + to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether support + iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support + iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI Initiator + Name. If initiatorName is specified with iscsiInterface + simultaneously, new iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface Name that + uses an iSCSI transport. Defaults to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal List. + The portal is either an IP or ip_addr:port if the + port is other than default (typically TCP ports 860 + and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the ReadOnly setting + in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for iSCSI + target and initiator authentication + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target Portal. The + Portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and + 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL and + unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the host that + shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the NFS export + to be mounted with read-only permissions. Defaults + to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP address of + the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource represents + a reference to a PersistentVolumeClaim in the same namespace. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly setting + in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets host + machine + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon Controller + persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx volume + attached and mounted on kubelets host machine + properties: + fsType: + description: fSType represents the filesystem type to + mount Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx + volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources secrets, + configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits used to set + permissions on created files by default. Must be an + octal value between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for mode bits. + Directories within the path are not affected by this + setting. This might be in conflict with other options + that affect the file mode, like fsGroup, and the result + can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume projections + items: + description: Projection that may be projected along + with other supported volume types + properties: + configMap: + description: configMap information about the configMap + data to project + properties: + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced + ConfigMap will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the ConfigMap, the volume setup will + error unless it is marked optional. Paths + must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether the + ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about the + downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used + to set permissions on this file, must + be an octal value between 0000 and + 0777 or a decimal value between 0 + and 511. YAML accepts both octal and + decimal values, JSON requires decimal + values for mode bits. If not specified, + the volume defaultMode will be used. + This might be in conflict with other + options that affect the file mode, + like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file to + be created. Must not be absolute or + contain the ''..'' path. Must be utf-8 + encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env + vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about the secret + data to project + properties: + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced + Secret will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the Secret, the volume setup will error + unless it is marked optional. Paths must + be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional field specify whether + the Secret or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to project + properties: + audience: + description: audience is the intended audience + of the token. A recipient of a token must + identify itself with an identifier specified + in the audience of the token, and otherwise + should reject the token. The audience defaults + to the identifier of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is the requested + duration of validity of the service account + token. As the token approaches expiration, + the kubelet volume plugin will proactively + rotate the service account token. The kubelet + will start trying to rotate the token if + the token is older than 80 percent of its + time to live or if the token is older than + 24 hours.Defaults to 1 hour and must be + at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative to + the mount point of the file to project the + token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount on the host + that shares a pod's lifetime + properties: + group: + description: group to map volume access to Default is + no group + type: string + readOnly: + description: readOnly here will force the Quobyte volume + to be mounted with read-only permissions. Defaults + to false. + type: boolean + registry: + description: registry represents a single or multiple + Quobyte Registry services specified as a string as + host:port pair (multiple entries are separated with + commas) which acts as the central registry for volumes + type: string + tenant: + description: tenant owning the given Quobyte volume + in the Backend Used with dynamically provisioned Quobyte + volumes, value is set by the plugin + type: string + user: + description: user to map volume access to Defaults to + serivceaccount user + type: string + volume: + description: volume is a string that references an already + created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device mount + on the host that shares a pod''s lifetime. More info: + https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + image: + description: 'image is the rados image name. More info: + https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring for RBDUser. + Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of Ceph monitors. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. Default is + rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. More info: + https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides keyring. + Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. Default is + admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent volume + attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of the ScaleIO + API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the ScaleIO + Protection Domain for the configured storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret for + ScaleIO user and other sensitive information. If this + is not provided, Login operation will fail. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL communication + with Gateway, default false + type: boolean + storageMode: + description: storageMode indicates whether the storage + for a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage Pool + associated with the protection domain. + type: string + system: + description: system is the name of the storage system + as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume already + created in the ScaleIO system that is associated with + this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that should populate + this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + items: + description: items If unspecified, each key-value pair + in the Data field of the referenced Secret will be + projected into the volume as a file whose name is + the key and content is the value. If specified, the + listed keys will be projected into the specified paths, + and unlisted keys will not be present. If a key is + specified which is not present in the Secret, the + volume setup will error unless it is marked optional. + Paths must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within a + volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used + to set permissions on this file. Must be an + octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal values + for mode bits. If not specified, the volume + defaultMode will be used. This might be in conflict + with other options that affect the file mode, + like fsGroup, and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative path of the + file to map the key to. May not be an absolute + path. May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether the Secret + or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the secret in + the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS volume attached + and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret to use for + obtaining the StorageOS API credentials. If not specified, + default values will be attempted. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable name of + the StorageOS volume. Volume names are only unique + within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the scope of + the volume within StorageOS. If no namespace is specified + then the Pod's namespace will be used. This allows + the Kubernetes name scoping to be mirrored within + StorageOS for tighter integration. Set VolumeName + to any name to override the default behaviour. Set + to "default" if you are not using namespaces within + StorageOS. Namespaces that do not pre-exist within + StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere volume attached + and mounted on kubelets host machine + properties: + fsType: + description: fsType is filesystem type to mount. Must + be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy Based + Management (SPBM) profile ID associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage Policy + Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + templateName: + type: string + timeChaos: + description: TimeChaosSpec defines the desired state of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id All available + options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name of affected + container. If not set, the first container will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. Supported + mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used to + inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that can + be used to select objects. A list of selectors based on + set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which objects + belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can be used + to select nodes. Selector which must match a node's labels, + and objects must belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects must + belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition of a + pod at the current time. supported value: Pending / Running + / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set values + that used to select pods. The key defines the namespace + which pods belong, and the each values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected program. + It's a possibly signed sequence of decimal numbers, such as + "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of pods the + server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods to do + chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + workflowName: + type: string + required: + - startTime + - templateName + - type + - workflowName + type: object + status: + description: Most recently observed status of the workflow node + properties: + activeChildren: + description: ActiveChildren means the created children node + items: + description: LocalObjectReference contains enough information to + let you locate the referenced object inside the same namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + chaosResource: + description: ChaosResource refs to the real chaos CR object. + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + conditionalBranchesStatus: + description: ConditionalBranchesStatus records the evaluation result + of each ConditionalBranch + properties: + branches: + items: + properties: + evaluationResult: + type: string + target: + type: string + required: + - evaluationResult + - target + type: object + type: array + context: + items: + type: string + type: array + type: object + conditions: + description: Represents the latest available observations of a workflow + node's current state. + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - reason + - status + - type + type: object + type: array + finishedChildren: + description: Children is necessary for representing the order when + replicated child template references by parent template. + items: + description: LocalObjectReference contains enough information to + let you locate the referenced object inside the same namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: workflows.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: Workflow + listKind: WorkflowList + plural: workflows + shortNames: + - wf + singular: workflow + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the behavior of a workflow + properties: + entry: + type: string + templates: + items: + properties: + abortWithStatusCheck: + description: AbortWithStatusCheck describe whether to abort + the workflow when the failure threshold of StatusCheck is + exceeded. Only used when Type is TypeStatusCheck. + type: boolean + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos action. + Supported action: ec2-stop / ec2-restart / detach-volume + Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. + Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the aws + server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. + Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos action. + Supported action: vm-stop / vm-restart / disk-detach Default + action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. Needed + in disk-detach. + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + lun: + description: LUN indicates the Logical Unit Number of the + data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos action. + Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. + properties: + correlation: + type: string + jitter: + type: string + latency: + description: Latency defines the latency of every io + request. + type: string + type: object + duration: + description: Duration represents the duration of the chaos + action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + volumeName: + type: string + required: + - action + - mode + - selector + - volumeName + type: object + children: + description: Children describes the children steps of serial + or parallel node. Only used when Type is TypeSerial or TypeParallel. + items: + type: string + type: array + conditionalBranches: + description: ConditionalBranches describes the conditional branches + of custom tasks. Only used when Type is TypeTask. + items: + properties: + expression: + description: Expression is the expression for this conditional + branch, expected type of result is boolean. If expression + is empty, this branch will always be selected/the template + will be spawned. + type: string + target: + description: Target is the name of other template, if + expression is evaluated as true, this template will + be spawned. + type: string + required: + - target + type: object + type: array + deadline: + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos action. + Supported action: error, random Default action: error' + enum: + - error + - random + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patterns: + description: 'Choose which domain names to take effect, + support the placeholder ? and wildcard *, or the Specified + domain name. Note: 1. The wildcard * must be at the end + of the string. For example, chaos-*.org is invalid. 2. + if the patterns is empty, will take effect on all the + domain names. For example: The value is ["google.com", + "github.*", "chaos-mes?.org"], will take effect on "google.com", + "github.com" and "chaos-mesh.org"' + items: + type: string + type: array + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos action. + Supported action: node-stop / node-reset / disk-loss Default + action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss + type: string + deviceNames: + description: The device name of disks to detach. Needed + in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action. + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes secret. + It is used for GCP credentials. + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + required: + - action + - instance + - project + - zone + type: object + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http status + code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of decimal + numbers, each with optional fraction and a unit suffix, + such as "300ms", "2h45m". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos + action. + type: string + method: + description: Method is a rule to select target by http method + in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents in target. + properties: + body: + description: Body is a rule to patch message body of + target. + properties: + type: + description: Type represents the patch type, only + support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], + ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", "bar"], + ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri path + in http request. + type: string + port: + description: Port represents the target port to be proxy + of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http message + body in target. + format: byte + type: string + code: + description: Code is a rule to replace http status code + in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header name + and header value pairs. + type: object + method: + description: Method is a rule to replace http method + in request. + type: string + path: + description: Path is rule to to replace uri path in + http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": + "unknown" }`, the `/?foo=bar` will be altered to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target by + http headers in request. The key-value pairs represent + header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target + by http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of ca file + in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name of cert + file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of key + file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required + secret resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace + of required secret resource + type: string + required: + - certName + - keyName + - secretName + - secretNamespace + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos action. + Supported action: latency / fault / attrOverride / mistake' + enum: + - latency + - fault + - attrOverride + - mistake + type: string + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action + delay. A delay string is a possibly signed sequence of + decimal numbers, each with optional fraction and a unit + suffix, such as "300ms". Valid time units are "ns", "us" + (or "µs"), "ms", "s", "m", "h". + type: string + duration: + description: Duration represents the duration of the chaos + action. It is required when the action is `PodFailureAction`. + 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". + type: string + errno: + description: 'Errno defines the error code that returned + by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting + I/O chaos action. default: all I/O methods.' + items: + type: string + type: array + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled in the + mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment in + bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting + I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection + errors and provides a number from 0-100. default: 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + volumePath: + description: VolumePath represents the mount path of injected + volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos action. + Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only set + it when action is stress + type: integer + database: + description: the match database default value is "", means + match all database + type: string + duration: + description: Duration represents the duration of the chaos + action + type: string + exception: + description: the exception which needs to throw for action + `exception` or the exception message needs to throw in + action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set it + when action is stress, the value can be 'stack' or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support + 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and will + generate one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", means + match all SQL type. The value can be 'select', 'insert', + 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + failKernRequest: + description: FailKernRequest defines the request of kernel + injection + properties: + callchain: + description: 'Callchain indicate a special call chain, + such as: ext4_mount -> mount_subtree -> ... -> should_failslab + With an optional set of predicates and an optional + set of parameters, which used with predicates. You + can read call chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just keep + Callchain empty, which means it will fail at any call + chain with slab alloc (eg: kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from kernel + source or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab error + in `d_alloc_parallel(struct dentry *parent, + const struct qstr *name)` with a special name + `bananas`, you need to set it to `struct dentry + *parent, const struct qstr *name` otherwise + omit it. + type: string + predicate: + description: Predicate will access the arguments + of this Frame, example with Parameters's, you + can set it to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, or omit it + to inject for all d_alloc_parallel call chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can be + set to ''0'' / ''1'' / ''2'' If `0`, indicates slab + to fail (should_failslab) If `1`, indicates alloc_page + to fail (should_fail_alloc_page) If `2`, indicates + bio to fail (should_fail_bio) You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate kernel + headers you need. Eg: "linux/mmzone.h", "linux/blkdev.h" + and so on' + items: + type: string + type: array + probability: + description: Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer + required: + - failtype + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - failKernRequest + - mode + - selector + type: object + name: + type: string + networkChaos: + description: NetworkChaosSpec defines the desired state of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos + action. Supported action: partition, netem, delay, loss, + duplicate, corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth + type: string + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes that + tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can be + queued waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the peakrate + bucket. For perfect accuracy, should be set to the + MTU of the interface. If a peakrate is needed, but + some burstiness is acceptable, this size can be raised. + A 3000 byte minburst allows around 3mbit/s of peakrate, + given 1000 byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate + of the bucket. The peakrate does not need to be set, + it is only necessary if perfect millisecond timescale + shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, + mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt + action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to be + affected. + type: string + direction: + default: to + description: Direction represents the direction, this applies + on netem and network partition action + enum: + - to + - from + - both + type: string + duplicate: + description: DuplicateSpec represents the detail about loss + action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the chaos + action + type: string + externalTargets: + description: ExternalTargets represents network targets + outside k8s + items: + type: string + type: array + loss: + description: Loss represents the detail about loss action + properties: + correlation: + type: string + loss: + type: string + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control + action + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, + mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. + bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + target: + description: Target represents network target, this applies + on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + type: object + targetDevice: + description: TargetDevice represents the network device + to be affected in target scope. + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired state + of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined + type: string + address: + description: 'DEPRECATED: Use Selector instead. Only one + of Address and Selector could be specified.' + items: + type: string + type: array + clock: + properties: + clock-ids-slice: + description: the identifier of the particular clock + on which to act. More clock description in linux kernel + can be found in man page of clock_getres, clock_gettime, + clock_settime. Muti clock ids should be split with + "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data in. + if path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-read-payload: + properties: + path: + description: specifies the location to fill data in. + if path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on + writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data in. + if path not provided, payload will read/write from/into + a temp file, temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on + writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the chaos + action + type: string + file-append: + properties: + count: + description: Count is the number of times to append + the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of the + file. + type: string + file-name: + description: FileName is the name of the file to be + created, modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file to + be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by http + status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside + proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: + properties: + file_path: + description: The config file path + type: string + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by http + status code in response + type: string + delay: + description: Delay represents the delay of the target + request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens + on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, + we will only attack HTTP connection with port inside + proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - delay + - proxy_ports + - target + type: object + http-request: + description: used for HTTP request, now only support GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw for + action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', + unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is "", + means match all database + type: string + exception: + description: The exception which needs to throw for + action `exception` or the exception message needs + to throw in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' + or the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only + support 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is "", + means match all SQL type. The value can be 'select', + 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's data, + will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only set + it when action is stress + type: integer + mem-type: + description: the memory type need to locate, only set + it when action is stress, the value can be 'stack' + or 'heap' + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is + 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag + can be accepted, others will be dropped. only set + when the IPProtocol is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), + ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or + µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf + test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads + to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the IP + address + type: string + rate: + description: The speed of network traffic, allows bps, + kbps, mbps, gbps, tbps unit. bps means bytes per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these destination + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, + supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these source + ports, use a ',' to separate or to indicate the range, + such as 80, 8001:8010. it can only be used in conjunction + with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp flag + can be accepted, others will be dropped. only set + when the IPProtocol is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, values + can be 'from', 'to'. 'from' means packets coming from + the 'IPAddress' or 'Hostname' and going to your server, + 'to' means packets originating from your server and + going to the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP + addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP + addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of + the original value + type: string + type: object + redis-expiration: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to + flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to + flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed type: string - type: array - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" + selector: + description: Selector is used to select physical machines + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string keys + and a set values that used to select physical machines. + The key defines the namespace which physical machine + belong, and each value is a set of physical machine + names. + type: object + type: object + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU worker. + 0 is effectively a sleep (no load) and 100 is full + loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, + default is the total available memory. One can specify + the size as % of total available memory or in units + of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID + type: string + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of physical machines to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to + specify the percent of physical machines the server can + do chaos action. IF `RandomMaxPercentMode`, provide a + number from 0-100 to specify the max percent of pods to + do chaos action + type: string + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a user + creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos action. + Supported action: pod-kill / pod-failure / container-kill + Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill + type: string + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: + type: array + duration: + description: Duration represents the duration of the chaos + action. It is required when the action is `PodFailureAction`. + 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". + type: string + gracePeriod: + description: GracePeriod is used in pod-kill action. It + represents the duration in seconds before the pod should + be deleted. Value must be non-negative integer. The default + value is zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - action + - mode + - selector + type: object + schedule: + description: Schedule describe the Schedule(describing scheduled + chaos) to be injected with chaos nodes. Only used when Type + is TypeSchedule. + properties: + awsChaos: + description: AWSChaosSpec is the content of the specification + for an AWSChaos + properties: + action: + description: 'Action defines the specific aws chaos + action. Supported action: ec2-stop / ec2-restart / + detach-volume Default action: ec2-stop' + enum: + - ec2-stop + - ec2-restart + - detach-volume type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: DeviceName indicates the name of the device. + Needed in detach-volume. + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 + instance. + type: string + endpoint: + description: Endpoint indicates the endpoint of the + aws server. Just used it in test now. + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. + type: string + volumeID: + description: EbsVolume indicates the ID of the EBS volume. + Needed in detach-volume. + type: string + required: + - action + - awsRegion + - ec2Instance + type: object + azureChaos: + description: AzureChaosSpec is the content of the specification + for an AzureChaos + properties: + action: + description: 'Action defines the specific azure chaos + action. Supported action: vm-stop / vm-restart / disk-detach + Default action: vm-stop' + enum: + - vm-stop + - vm-restart + - disk-detach + type: string + diskName: + description: DiskName indicates the name of the disk. + Needed in disk-detach. + type: string + duration: + description: Duration represents the duration of the + chaos action. + type: string + lun: + description: LUN indicates the Logical Unit Number of + the data disk. Needed in disk-detach. + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for Azure credentials. + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure + subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + required: + - action + - resourceGroupName + - subscriptionID + - vmName + type: object + blockChaos: + description: BlockChaosSpec is the content of the specification + for a BlockChaos + properties: + action: + description: 'Action defines the specific block chaos + action. Supported action: delay' + enum: + - delay + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + delay: + description: Delay defines the delay distribution. properties: - key: - description: key is the label key that the selector - applies to. + correlation: type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. + jitter: type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. + latency: + description: Latency defines the latency of every + io request. + type: string + type: object + duration: + description: Duration represents the duration of the + chaos action. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. items: type: string type: array - required: - - key - - operator + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: + volumeName: type: string - type: array - nodeSelectors: - additionalProperties: + required: + - action + - mode + - selector + - volumeName + type: object + concurrencyPolicy: + enum: + - Forbid + - Allow + type: string + dnsChaos: + description: DNSChaosSpec defines the desired state of DNSChaos + properties: + action: + description: 'Action defines the specific DNS chaos + action. Supported action: error, random Default action: + error' + enum: + - error + - random type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent type: string - type: array - pods: - additionalProperties: + patterns: + description: 'Choose which domain names to take effect, + support the placeholder ? and wildcard *, or the Specified + domain name. Note: 1. The wildcard * must be at the + end of the string. For example, chaos-*.org is invalid. + 2. if the patterns is empty, will take effect on all + the domain names. For example: The value is ["google.com", + "github.*", "chaos-mes?.org"], will take effect on + "google.com", "github.com" and "chaos-mesh.org"' items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, - provide a number from 0-100 to specify the max percent of - pods to do chaos action - type: string - required: - - action - - mode - - selector - type: object - duration: - type: string - gcp_chaos: - description: GcpChaosSpec is the content of the specification - for a GcpChaos - properties: - action: - description: 'Action defines the specific gcp chaos action. - Supported action: node-stop / node-reset / disk-loss Default - action: node-stop' - enum: - - node-stop - - node-reset - - disk-loss - type: string - deviceName: - description: The device name of the disk to detach. Needed - in disk-loss. - type: string - duration: - description: Duration represents the duration of the chaos - action. - type: string - instance: - description: Instance defines the name of the instance - type: string - project: - description: Project defines the name of gcp project. - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - secretName: - description: SecretName defines the name of kubernetes secret. - It is used for GCP credentials. - type: string - zone: - description: Zone defines the zone of gcp project. - type: string - required: - - action - - instance - - project - - zone - type: object - http_chaos: - properties: - action: - description: 'Action defines the specific pod chaos action. - Supported action: delay | abort | mixed Default action: - delay' - enum: - - delay - - abort - - mixed - type: string - duration: - description: Duration represents the duration of the chaos - action. It is required when the action is `PodFailureAction`. - 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". - type: string - headers: - description: Specifies how the header match will be performed - to route the request. - items: - properties: - exact_match: + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed type: string - invert_match: + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action type: string - name: + required: + - action + - mode + - selector + type: object + gcpChaos: + description: GCPChaosSpec is the content of the specification + for a GCPChaos + properties: + action: + description: 'Action defines the specific gcp chaos + action. Supported action: node-stop / node-reset / + disk-loss Default action: node-stop' + enum: + - node-stop + - node-reset + - disk-loss type: string - prefix_match: + deviceNames: + description: The device name of disks to detach. Needed + in disk-loss. + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action. type: string - present_match: + instance: + description: Instance defines the name of the instance type: string - range_match: + project: + description: Project defines the ID of gcp project. type: string - regex_match: + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed type: string - safe_regex_match: + secretName: + description: SecretName defines the name of kubernetes + secret. It is used for GCP credentials. type: string - suffix_match: + zone: + description: Zone defines the zone of gcp project. type: string required: - - name + - action + - instance + - project + - zone type: object - type: array - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - percent: - description: 'Percent defines the percentage of injection - errors and provides a number from 0-100. default: 100.' - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: + historyLimit: + minimum: 1 + type: integer + httpChaos: + properties: + abort: + description: Abort is a rule to abort a http session. + type: boolean + code: + description: Code is a rule to select target by http + status code in response. + format: int32 + type: integer + delay: + description: Delay represents the delay of the target + request/response. A duration string is a possibly + unsigned sequence of decimal numbers, each with optional + fraction and a unit suffix, such as "300ms", "2h45m". + Valid time units are "ns", "us" (or "µs"), "ms", "s", + "m", "h". type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. + duration: + description: Duration represents the duration of the + chaos action. + type: string + method: + description: Method is a rule to select target by http + method in request. + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + patch: + description: Patch is a rule to patch some contents + in target. properties: - key: - description: key is the label key that the selector - applies to. + body: + description: Body is a rule to patch message body + of target. + properties: + type: + description: Type represents the patch type, + only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) + currently. + type: string + value: + description: Value is the patch contents. + type: string + required: + - type + - value + type: object + headers: + description: 'Headers is a rule to append http headers + of target. For example: `[["Set-Cookie", ""], ["Set-Cookie", ""]]`.' + items: + items: + type: string + type: array + type: array + queries: + description: 'Queries is a rule to append uri queries + of target(Request only). For example: `[["foo", + "bar"], ["foo", "unknown"]]`.' + items: + items: + type: string + type: array + type: array + type: object + path: + description: Path is a rule to select target by uri + path in http request. + type: string + port: + description: Port represents the target port to be proxy + of. + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + replace: + description: Replace is a rule to replace some contents + in target. + properties: + body: + description: Body is a rule to replace http message + body in target. + format: byte type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. + code: + description: Code is a rule to replace http status + code in response. + format: int32 + type: integer + headers: + additionalProperties: + type: string + description: Headers is a rule to replace http headers + of target. The key-value pairs represent header + name and header value pairs. + type: object + method: + description: Method is a rule to replace http method + in request. type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. + path: + description: Path is rule to to replace uri path + in http request. + type: string + queries: + additionalProperties: + type: string + description: 'Queries is a rule to replace uri queries + in http request. For example, with value `{ "foo": + "unknown" }`, the `/?foo=bar` will be altered + to `/?foo=unknown`,' + type: object + type: object + request_headers: + additionalProperties: + type: string + description: RequestHeaders is a rule to select target + by http headers in request. The key-value pairs represent + header name and header value pairs. + type: object + response_headers: + additionalProperties: + type: string + description: ResponseHeaders is a rule to select target + by http headers in response. The key-value pairs represent + header name and header value pairs. + type: object + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. items: type: string type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + target: + description: Target is the object to be selected and + injected. + enum: + - Request + - Response + type: string + tls: + description: TLS is the tls config, will override PodHttpChaos + if there are multiple HTTPChaos experiments are applied + properties: + caName: + description: CAName represents the data name of + ca file in secret, `ca.crt` for example + type: string + certName: + description: CertName represents the data name of + cert file in secret, `tls.crt` for example + type: string + keyName: + description: KeyName represents the data name of + key file in secret, `tls.key` for example + type: string + secretName: + description: SecretName represents the name of required + secret resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace + of required secret resource + type: string required: - - key - - operator + - certName + - keyName + - secretName + - secretNamespace type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action type: string - type: array - nodeSelectors: - additionalProperties: + required: + - mode + - selector + - target + type: object + ioChaos: + description: IOChaosSpec defines the desired state of IOChaos + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: latency / fault / attrOverride + / mistake' + enum: + - latency + - fault + - attrOverride + - mistake type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: + attr: + description: Attr defines the overrided attribution + properties: + atime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + blocks: + format: int64 + type: integer + ctime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + gid: + format: int32 + type: integer + ino: + format: int64 + type: integer + kind: + description: FileType represents type of file + type: string + mtime: + description: Timespec represents a time + properties: + nsec: + format: int64 + type: integer + sec: + format: int64 + type: integer + required: + - nsec + - sec + type: object + nlink: + format: int32 + type: integer + perm: + type: integer + rdev: + format: int32 + type: integer + size: + format: int64 + type: integer + uid: + format: int32 + type: integer + type: object + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + delay: + description: Delay defines the value of I/O chaos action + delay. A delay string is a possibly signed sequence + of decimal numbers, each with optional fraction and + a unit suffix, such as "300ms". Valid time units are + "ns", "us" (or "µs"), "ms", "s", "m", "h". type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: + duration: + description: Duration represents the duration of the + chaos action. It is required when the action is `PodFailureAction`. + 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". type: string - type: array - pods: - additionalProperties: + errno: + description: 'Errno defines the error code that returned + by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' + format: int32 + type: integer + methods: + description: 'Methods defines the I/O methods for injecting + I/O chaos action. default: all I/O methods.' items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - action - - mode - - selector - type: object - io_chaos: - description: IoChaosSpec defines the desired state of IoChaos - properties: - action: - description: 'Action defines the specific pod chaos action. - Supported action: latency / fault / attrOverride / mistake' - enum: - - latency - - fault - - attrOverride - - mistake - type: string - attr: - description: Attr defines the overrided attribution - properties: - atime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - blocks: - format: int64 - type: integer - ctime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - gid: - format: int32 - type: integer - ino: - format: int64 - type: integer - kind: - description: FileType represents type of a file - type: string - mtime: - description: Timespec represents a time - properties: - nsec: - format: int64 - type: integer - sec: - format: int64 - type: integer - required: - - nsec - - sec - type: object - nlink: - format: int32 - type: integer - perm: - type: integer - rdev: - format: int32 - type: integer - size: - format: int64 - type: integer - uid: - format: int32 - type: integer - type: object - containerName: - description: ContainerName indicates the target container - to inject iochaos in - type: string - delay: - description: Delay defines the value of I/O chaos action delay. - A delay string is a possibly signed sequence of decimal - numbers, each with optional fraction and a unit suffix, - such as "300ms". Valid time units are "ns", "us" (or "µs"), - "ms", "s", "m", "h". - type: string - duration: - description: Duration represents the duration of the chaos - action. It is required when the action is `PodFailureAction`. - 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". - type: string - errno: - description: 'Errno defines the error code that returned by - I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html' - format: int32 - type: integer - methods: - description: 'Methods defines the I/O methods for injecting - I/O chaos action. default: all I/O methods.' - items: - type: string - type: array - mistake: - description: Mistake defines what types of incorrectness are - injected to IO operations - properties: - filling: - description: Filling determines what is filled in the - miskate data. - enum: - - zero - - random - type: string - maxLength: - description: Max length of each wrong data segment in - bytes - format: int64 - minimum: 1 - type: integer - maxOccurrences: - description: There will be [1, MaxOccurrences] segments - of wrong data. - format: int64 - minimum: 1 - type: integer - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - path: - description: Path defines the path of files for injecting - I/O chaos action. - type: string - percent: - description: 'Percent defines the percentage of injection - errors and provides a number from 0-100. default: 100.' - type: integer - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: + mistake: + description: Mistake defines what types of incorrectness + are injected to IO operations + properties: + filling: + description: Filling determines what is filled in + the mistake data. + enum: + - zero + - random + type: string + maxLength: + description: Max length of each wrong data segment + in bytes + format: int64 + minimum: 1 + type: integer + maxOccurrences: + description: There will be [1, MaxOccurrences] segments + of wrong data. + format: int64 + minimum: 1 + type: integer + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + path: + description: Path defines the path of files for injecting + I/O chaos action. + type: string + percent: + default: 100 + description: 'Percent defines the percentage of injection + errors and provides a number from 0-100. default: + 100.' + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. + volumePath: + description: VolumePath represents the mount path of + injected volume + type: string + required: + - action + - mode + - selector + - volumePath + type: object + jvmChaos: + description: JVMChaosSpec defines the desired state of JVMChaos + properties: + action: + description: 'Action defines the specific jvm chaos + action. Supported action: latency;return;exception;stress;gc;ruleData' + enum: + - latency + - return + - exception + - stress + - gc + - ruleData + - mysql + type: string + class: + description: Java class + type: string + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + cpuCount: + description: the CPU core number needs to use, only + set it when action is stress + type: integer + database: + description: the match database default value is "", + means match all database + type: string + duration: + description: Duration represents the duration of the + chaos action + type: string + exception: + description: the exception which needs to throw for + action `exception` or the exception message needs + to throw in action `mysql` + type: string + latency: + description: the latency duration for action 'latency', + unit ms or the latency duration in action `mysql` + type: integer + memType: + description: the memory type needs to locate, only set + it when action is stress, the value can be 'stack' + or 'heap' + type: string + method: + description: the method in Java class + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only + support 5.X.X(set to "5") and 8.X.X(set to "8") now + type: string + name: + description: byteman rule name, should be unique, and + will generate one if not set + type: string + pid: + description: the pid of Java process which needs to + attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + ruleData: + description: the byteman rule's data for action 'ruleData' + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + sqlType: + description: the match sql type default value is "", + means match all SQL type. The value can be 'select', + 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", means + match all table + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - action + - mode + - selector + type: object + kernelChaos: + description: KernelChaosSpec defines the desired state of + KernelChaos + properties: + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + failKernRequest: + description: FailKernRequest defines the request of + kernel injection + properties: + callchain: + description: 'Callchain indicate a special call + chain, such as: ext4_mount -> mount_subtree -> + ... -> should_failslab With an optional set of + predicates and an optional set of parameters, + which used with predicates. You can read call + chan and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. If no special call chain, just + keep Callchain empty, which means it will fail + at any call chain with slab alloc (eg: kmalloc).' + items: + description: Frame defines the function signature + and predicate in function's body + properties: + funcname: + description: Funcname can be find from kernel + source or `/proc/kallsyms`, such as `ext4_mount` + type: string + parameters: + description: Parameters is used with predicate, + for example, if you want to inject slab + error in `d_alloc_parallel(struct dentry + *parent, const struct qstr *name)` with + a special name `bananas`, you need to set + it to `struct dentry *parent, const struct + qstr *name` otherwise omit it. + type: string + predicate: + description: Predicate will access the arguments + of this Frame, example with Parameters's, + you can set it to `STRNCMP(name->name, "bananas", + 8)` to make inject only with it, or omit + it to inject for all d_alloc_parallel call + chain. + type: string + type: object + type: array + failtype: + description: 'FailType indicates what to fail, can + be set to ''0'' / ''1'' / ''2'' If `0`, indicates + slab to fail (should_failslab) If `1`, indicates + alloc_page to fail (should_fail_alloc_page) If + `2`, indicates bio to fail (should_fail_bio) You + can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more' + format: int32 + maximum: 2 + minimum: 0 + type: integer + headers: + description: 'Headers indicates the appropriate + kernel headers you need. Eg: "linux/mmzone.h", + "linux/blkdev.h" and so on' items: type: string type: array + probability: + description: Probability indicates the fails with + probability. If you want 1%, please set this field + with 1. + format: int32 + maximum: 100 + minimum: 0 + type: integer + times: + description: Times indicates the max times of fails. + format: int32 + minimum: 0 + type: integer required: - - key - - operator + - failtype type: object - type: array - fieldSelectors: - additionalProperties: + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action type: string - type: array - nodeSelectors: - additionalProperties: + required: + - failKernRequest + - mode + - selector + type: object + networkChaos: + description: NetworkChaosSpec defines the desired state + of NetworkChaos + properties: + action: + description: 'Action defines the specific network chaos + action. Supported action: partition, netem, delay, + loss, duplicate, corrupt Default action: delay' + enum: + - netem + - delay + - loss + - duplicate + - corrupt + - partition + - bandwidth type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: + bandwidth: + description: Bandwidth represents the detail about bandwidth + control action + properties: + buffer: + description: Buffer is the maximum amount of bytes + that tokens can be available for instantaneously. + format: int32 + minimum: 1 + type: integer + limit: + description: Limit is the number of bytes that can + be queued waiting for tokens to become available. + format: int32 + minimum: 1 + type: integer + minburst: + description: Minburst specifies the size of the + peakrate bucket. For perfect accuracy, should + be set to the MTU of the interface. If a peakrate + is needed, but some burstiness is acceptable, + this size can be raised. A 3000 byte minburst + allows around 3mbit/s of peakrate, given 1000 + byte packets. + format: int32 + minimum: 0 + type: integer + peakrate: + description: Peakrate is the maximum depletion rate + of the bucket. The peakrate does not need to be + set, it is only necessary if perfect millisecond + timescale shaping is required. + format: int64 + minimum: 0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, + kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, + tbps unit. bps means bytes per second. + type: string + required: + - buffer + - limit + - rate + type: object + corrupt: + description: Corrupt represents the detail about corrupt + action + properties: + correlation: + type: string + corrupt: + type: string + required: + - corrupt + type: object + delay: + description: Delay represents the detail about delay + action + properties: + correlation: + type: string + jitter: + type: string + latency: + type: string + reorder: + description: ReorderSpec defines details of packet + reorder. + properties: + correlation: + type: string + gap: + type: integer + reorder: + type: string + required: + - gap + - reorder + type: object + required: + - latency + type: object + device: + description: Device represents the network device to + be affected. type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: + direction: + default: to + description: Direction represents the direction, this + applies on netem and network partition action + enum: + - to + - from + - both type: string - type: array - pods: - additionalProperties: + duplicate: + description: DuplicateSpec represents the detail about + loss action + properties: + correlation: + type: string + duplicate: + type: string + required: + - duplicate + type: object + duration: + description: Duration represents the duration of the + chaos action + type: string + externalTargets: + description: ExternalTargets represents network targets + outside k8s items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - volumePath: - description: VolumePath represents the mount path of injected - volume - type: string - required: - - action - - mode - - selector - - volumePath - type: object - jvm_chaos: - description: JVMChaosSpec defines the desired state of JVMChaos - properties: - action: - description: 'Action defines the specific jvm chaos action. - Supported action: delay;return;script;cfl;oom;ccf;tce;cpf;tde;tpf' - enum: - - delay - - return - - script - - cfl - - oom - - ccf - - tce - - cpf - - tde - - tpf - type: string - duration: - description: Duration represents the duration of the chaos - action - type: string - flags: - additionalProperties: - type: string - description: Flags represents the flags of action - type: object - matchers: - additionalProperties: - type: string - description: Matchers represents the matching rules for the - target - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. + loss: + description: Loss represents the detail about loss action properties: - key: - description: key is the label key that the selector - applies to. + correlation: type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. + loss: type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. + required: + - loss + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + rate: + description: Rate represents the detail about rate control + action + properties: + rate: + description: Rate is the speed knob. Allows bit, + kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, + tbps unit. bps means bytes per second. + type: string + required: + - rate + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' items: type: string type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + target: + description: Target represents network target, this + applies on netem and network partition action + properties: + mode: + description: 'Mode defines the mode to run chaos + action. Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + selector: + description: Selector is used to select pods that + are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list + of selectors based on set-based label expressions. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector + based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace + to which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which + must match a node's labels, and objects must + belong to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and + objects must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of + condition of a pod at the current time. supported + value: Pending / Running / Succeeded / Failed + / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and + a set values that used to select pods. The + key defines the namespace which pods belong, + and the each values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is + set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to + do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent + of pods to do chaos action + type: string required: - - key - - operator + - mode + - selector type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: + targetDevice: + description: TargetDevice represents the network device + to be affected in target scope. type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: + required: + - action + - mode + - selector + type: object + physicalmachineChaos: + description: PhysicalMachineChaosSpec defines the desired + state of PhysicalMachineChaos + properties: + action: + description: the subAction, generate automatically + enum: + - stress-cpu + - stress-mem + - disk-read-payload + - disk-write-payload + - disk-fill + - network-corrupt + - network-duplicate + - network-loss + - network-delay + - network-partition + - network-dns + - network-bandwidth + - network-flood + - network-down + - process + - jvm-exception + - jvm-gc + - jvm-latency + - jvm-return + - jvm-stress + - jvm-rule-data + - jvm-mysql + - clock + - redis-expiration + - redis-penetration + - redis-cacheLimit + - redis-restart + - redis-stop + - kafka-fill + - kafka-flood + - kafka-io + - file-create + - file-modify + - file-delete + - file-rename + - file-append + - file-replace + - vm + - user_defined type: string - type: array - pods: - additionalProperties: + address: + description: 'DEPRECATED: Use Selector instead. Only + one of Address and Selector could be specified.' items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - target: - description: 'Target defines the specific jvm chaos target. - Supported target: servlet;psql;jvm;jedis;http;dubbo;rocketmq;tars;mysql;druid;redisson;rabbitmq;mongodb' - enum: - - servlet - - psql - - jvm - - jedis - - http - - dubbo - - rocketmq - - tars - - mysql - - druid - - redisson - - rabbitmq - - mongodb - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the % of pods to do chaos - action - type: string - required: - - action - - mode - - selector - - target - type: object - kernel_chaos: - description: KernelChaosSpec defines the desired state of KernelChaos - properties: - duration: - description: Duration represents the duration of the chaos - action - type: string - failKernRequest: - description: FailKernRequest defines the request of kernel - injection - properties: - callchain: - description: 'Callchain indicate a special call chain, - such as: ext4_mount -> mount_subtree -> - ... -> should_failslab With an optional - set of predicates and an optional set of parameters, - which used with predicates. You can read call chan and - predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples - to learn more. If no special call chain, just keep Callchain - empty, which means it will fail at any call chain with - slab alloc (eg: kmalloc).' - items: - description: Frame defines the function signature and - predicate in function's body + clock: properties: - funcname: - description: Funcname can be find from kernel source - or `/proc/kallsyms`, such as `ext4_mount` + clock-ids-slice: + description: the identifier of the particular clock + on which to act. More clock description in linux + kernel can be found in man page of clock_getres, + clock_gettime, clock_settime. Muti clock ids should + be split with "," type: string - parameters: - description: Parameters is used with predicate, - for example, if you want to inject slab error - in `d_alloc_parallel(struct dentry *parent, const - struct qstr *name)` with a special name `bananas`, - you need to set it to `struct dentry *parent, - const struct qstr *name` otherwise omit it. + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. type: string - predicate: - description: Predicate will access the arguments - of this Frame, example with Parameters's, you - can set it to `STRNCMP(name->name, "bananas", - 8)` to make inject only with it, or omit it to - inject for all d_alloc_parallel call chain. + type: object + disk-fill: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' type: string type: object - type: array - failtype: - description: 'FailType indicates what to fail, can be - set to ''0'' / ''1'' / ''2'' If `0`, indicates slab - to fail (should_failslab) If `1`, indicates alloc_page - to fail (should_fail_alloc_page) If `2`, indicates bio - to fail (should_fail_bio) You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html 2. - http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt - to learn more' - format: int32 - maximum: 2 - minimum: 0 - type: integer - headers: - description: 'Headers indicates the appropriate kernel - headers you need. Eg: "linux/mmzone.h", "linux/blkdev.h" - and so on' - items: - type: string - type: array - probability: - description: Probability indicates the fails with probability. - If you want 1%, please set this field with 1. - format: int32 - maximum: 100 - minimum: 0 - type: integer - times: - description: Times indicates the max times of fails. - format: int32 - minimum: 0 - type: integer - required: - - failtype - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: + disk-read-payload: + properties: + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + payload-process-num: + description: specifies the number of process work + on writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + disk-write-payload: + properties: + path: + description: specifies the location to fill data + in. if path not provided, payload will read/write + from/into a temp file, temp file will be deleted + after writing + type: string + payload-process-num: + description: specifies the number of process work + on writing, default 1, only 1-255 is valid value + type: integer + size: + description: 'specifies how many units of data will + write into the file path. support unit: c=1, w=2, + b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, + GB=1000*1000*1000, G=1024*1024*1024 BYTES. example + : 1M | 512kB' + type: string + type: object + duration: + description: Duration represents the duration of the + chaos action type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. + file-append: + properties: + count: + description: Count is the number of times to append + the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-create: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-delete: + properties: + dir-name: + description: DirName is the directory name to create + or delete. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + type: object + file-modify: + properties: + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to + be set. + format: int32 + type: integer + type: object + file-rename: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + file-replace: + properties: + dest-string: + description: DestStr is the destination string of + the file. + type: string + file-name: + description: FileName is the name of the file to + be created, modified, deleted, renamed, or appended. + type: string + line: + description: Line is the line number of the file + to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the + file. + type: string + type: object + http-abort: + properties: + code: + description: Code is a rule to select target by + http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP + connection, we will only attack HTTP connection + with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + required: + - proxy_ports + - target + type: object + http-config: properties: - key: - description: key is the label key that the selector - applies to. + file_path: + description: The config file path type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. + type: object + http-delay: + properties: + code: + description: Code is a rule to select target by + http status code in response type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. + delay: + description: Delay represents the delay of the target + request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service + listens on + format: int32 + type: integer + proxy_ports: + description: Composed with one of the port of HTTP + connection, we will only attack HTTP connection + with port inside proxy_ports items: - type: string + type: integer type: array + target: + description: 'HTTP target: Request or Response' + type: string required: - - key - - operator + - delay + - proxy_ports + - target type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: - items: - type: string - type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - failKernRequest - - mode - - selector - type: object - name: - type: string - network_chaos: - description: NetworkChaosSpec defines the desired state of NetworkChaos - properties: - action: - description: 'Action defines the specific network chaos action. - Supported action: partition, netem, delay, loss, duplicate, - corrupt Default action: delay' - enum: - - netem - - delay - - loss - - duplicate - - corrupt - - partition - - bandwidth - type: string - bandwidth: - description: Bandwidth represents the detail about bandwidth - control action - properties: - buffer: - description: Buffer is the maximum amount of bytes that - tokens can be available for instantaneously. - format: int32 - minimum: 1 - type: integer - limit: - description: Limit is the number of bytes that can be - queued waiting for tokens to become available. - format: int32 - minimum: 1 - type: integer - minburst: - description: Minburst specifies the size of the peakrate - bucket. For perfect accuracy, should be set to the MTU - of the interface. If a peakrate is needed, but some - burstiness is acceptable, this size can be raised. A - 3000 byte minburst allows around 3mbit/s of peakrate, - given 1000 byte packets. - format: int32 - minimum: 0 - type: integer - peakrate: - description: Peakrate is the maximum depletion rate of - the bucket. The peakrate does not need to be set, it - is only necessary if perfect millisecond timescale shaping - is required. - format: int64 - minimum: 0 - type: integer - rate: - description: Rate is the speed knob. Allows bps, kbps, - mbps, gbps, tbps unit. bps means bytes per second. - type: string - required: - - buffer - - limit - - rate - type: object - corrupt: - description: Corrupt represents the detail about corrupt action - properties: - correlation: - type: string - corrupt: - type: string - required: - - correlation - - corrupt - type: object - delay: - description: Delay represents the detail about delay action - properties: - correlation: - type: string - jitter: - type: string - latency: - type: string - reorder: - description: ReorderSpec defines details of packet reorder. - properties: - correlation: - type: string - gap: - type: integer - reorder: - type: string - required: - - correlation - - gap - - reorder - type: object - required: - - latency - type: object - direction: - description: Direction represents the direction, this applies - on netem and network partition action - enum: - - to - - from - - both - - "" - type: string - duplicate: - description: DuplicateSpec represents the detail about loss - action - properties: - correlation: - type: string - duplicate: - type: string - required: - - correlation - - duplicate - type: object - duration: - description: Duration represents the duration of the chaos - action - type: string - externalTargets: - description: ExternalTargets represents network targets outside - k8s - items: - type: string - type: array - loss: - description: Loss represents the detail about loss action - properties: - correlation: - type: string - loss: - type: string - required: - - correlation - - loss - type: object - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about network. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: + http-request: + description: used for HTTP request, now only support + GET + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + jvm-exception: + properties: + class: + description: Java class + type: string + exception: + description: the exception which needs to throw + for action `exception` + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-gc: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-latency: + properties: + class: + description: Java class + type: string + latency: + description: the latency duration for action 'latency', + unit ms + type: integer + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + jvm-mysql: + properties: + database: + description: the match database default value is + "", means match all database + type: string + exception: + description: The exception which needs to throw + for action `exception` or the exception message + needs to throw in action `mysql` + type: string + latency: + description: The latency duration for action 'latency' + or the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, + only support 5.X.X(set to "5") and 8.X.X(set to + "8") now + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + sqlType: + description: the match sql type default value is + "", means match all SQL type. The value can be + 'select', 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: the match table default value is "", + means match all table + type: string + type: object + jvm-return: + properties: + class: + description: Java class + type: string + method: + description: the method in Java class + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + jvm-rule-data: + properties: + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + rule-data: + description: RuleData used to save the rule file's + data, will use it when recover + type: string + type: object + jvm-stress: + properties: + cpu-count: + description: the CPU core number need to use, only + set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, only + set it when action is stress, the value can be + 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs + to attach + type: integer + port: + description: the port of agent server, default 9277 + format: int32 + type: integer + type: object + kafka-fill: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + format: int64 + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-flood: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + kafka-io: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. + network-bandwidth: + properties: + buffer: + format: int32 + minimum: 1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + format: int32 + minimum: 1 + type: integer + minburst: + format: int32 + type: integer + peakrate: + format: int64 + type: integer + rate: + type: string + required: + - buffer + - limit + - rate + type: object + network-corrupt: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 + is 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-delay: + properties: + accept-tcp-flags: + description: only the packet which match the tcp + flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used for + partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or + µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, + us (or µs), ms, s, m, h.' + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-dns: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf + with this value + type: string + type: object + network-down: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us + (or µs), ms, s, m, h.' + type: string + type: object + network-duplicate: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate + (10 is 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-flood: + properties: + duration: + description: The number of seconds to run the iperf + test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client + threads to run + format: int32 + type: integer + port: + description: Generate traffic to this port on the + IP address + type: string + rate: + description: The speed of network traffic, allows + bps, kbps, mbps, gbps, tbps unit. bps means bytes + per second + type: string + required: + - duration + - rate + type: object + network-loss: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: only impact egress traffic to these + destination ports, use a ',' to separate or to + indicate the range, such as 80, 8001:8010. it + can only be used in conjunction with -p tcp or + -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP + protocol, supported: tcp, udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is + 10%) + type: string + source-port: + description: only impact egress traffic from these + source ports, use a ',' to separate or to indicate + the range, such as 80, 8001:8010. it can only + be used in conjunction with -p tcp or -p udp + type: string + type: object + network-partition: + properties: + accept-tcp-flags: + description: only the packet which match the tcp + flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used for + partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: specifies the partition direction, + values can be 'from', 'to'. 'from' means packets + coming from the 'IPAddress' or 'Hostname' and + going to your server, 'to' means packets originating + from your server and going to the 'IPAddress' + or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these + IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these + IP addresses + type: string + type: object + process: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering + experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + redis-cacheLimit: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage + of the original value + type: string + type: object + redis-expiration: properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string key: - description: key is the label key that the selector - applies to. + description: The keys to be expired type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. + option: + description: Additional options for `expiration` type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. + password: + description: The password of Redis server + type: string + type: object + redis-penetration: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + redis-restart: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + redis-stop: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether + to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line + tool + type: boolean + type: object + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select physical machines + that are used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. items: type: string type: array - required: - - key - - operator + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: PhysicalMachines is a map of string + keys and a set values that used to select physical + machines. The key defines the namespace which + physical machine belong, and each value is a set + of physical machine names. + type: object type: object - type: array - fieldSelectors: - additionalProperties: + stress-cpu: + properties: + load: + description: specifies P percent loading per CPU + worker. 0 is effectively a sleep (no load) and + 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + stress-mem: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: specifies N bytes consumed per vm worker, + default is the total available memory. One can + specify the size as % of total available memory + or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + uid: + description: the experiment ID type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: + user_defined: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of physical machines + to do chaos action. If `FixedPercentMode`, provide + a number from 0-100 to specify the percent of physical + machines the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: + vm: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + required: + - action + - mode + type: object + podChaos: + description: PodChaosSpec defines the attributes that a + user creates on a chaos experiment about pods. + properties: + action: + description: 'Action defines the specific pod chaos + action. Supported action: pod-kill / pod-failure / + container-kill Default action: pod-kill' + enum: + - pod-kill + - pod-failure + - container-kill type: string - type: array - nodeSelectors: - additionalProperties: + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action. It is required when the action is `PodFailureAction`. + 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". type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: + gracePeriod: + description: GracePeriod is used in pod-kill action. + It represents the duration in seconds before the pod + should be deleted. Value must be non-negative integer. + The default value is zero that indicates delete immediately. + format: int64 + minimum: 0 + type: integer + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action type: string - type: array - pods: - additionalProperties: + required: + - action + - mode + - selector + type: object + schedule: + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + nullable: true + type: integer + stressChaos: + description: StressChaosSpec defines the desired state of + StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - target: - description: Target represents network target, this applies - on netem and network partition action - properties: - mode: - description: TargetMode defines the target selector mode - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - - "" - type: string - selector: - description: TargetSelector defines the target selector - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can - be used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions - that can be used to select objects. A list of selectors - based on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors + just like `Stressors` except that it's an experimental + feature and more powerful. You can define stressors + in `stress-ng` (see also `man stress-ng`) dialect, + however not all of the supported stressors are well + tested. It maybe retired in later releases. You should + always use `Stressors` to define the stressors and + use this only when you want more stressors unsupported + by `Stressors`. When both `StressngStressors` and + `Stressors` are defined, `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported + to stress system components out. You can use one or + more of them to make up various kinds of stresses. + At least one of the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading + per CPU worker. 0 is effectively a sleep (no + load) and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options items: type: string type: array + workers: + description: Workers specifies N workers to + apply the stressor. Maximum 8192 workers can + run by stress-ng + maximum: 8192 + type: integer required: - - key - - operator + - workers type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can - be used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can - be used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can - be used to select nodes. Selector which must match - a node's labels, and objects must belong to these - selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects - must belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + memory: + description: MemoryStressor stresses virtual memory + out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` to + know more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed + per vm worker, default is the total available + memory. One can specify the size as % of total + available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB. + type: string + workers: + description: Workers specifies N workers to + apply the stressor. Maximum 8192 workers can + run by stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + type: object + timeChaos: + description: TimeChaosSpec defines the desired state of + TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id + All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name + of affected container. If not set, the first container + will be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the + chaos action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent + / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are + used to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions + that can be used to select objects. A list of + selectors based on set-based label expressions. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select objects. A selector based + on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to + which objects belong. items: type: string type: array - description: Pods is a map of string keys and a set - values that used to select pods. The key defines - the namespace which pods belong, and the each values - is a set of pod names. - type: object - type: object - value: - description: TargetValue is required when the mode is - set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. - If `FixedPodMode`, provide an integer of pods to do - chaos action. If `FixedPercentPodMod`, provide a number - from 0-100 to specify the percent of pods the server - can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods - to do chaos action - type: string - required: - - mode - - selector - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - action - - mode - - selector - type: object - pod_chaos: - description: PodChaosSpec defines the attributes that a user creates - on a chaos experiment about pods. - properties: - action: - description: 'Action defines the specific pod chaos action. - Supported action: pod-kill / pod-failure / container-kill - Default action: pod-kill' - enum: - - pod-kill - - pod-failure - - container-kill - type: string - containerName: - description: ContainerName indicates the name of the container. - Needed in container-kill. - type: string - duration: - description: Duration represents the duration of the chaos - action. It is required when the action is `PodFailureAction`. - 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". - type: string - gracePeriod: - description: GracePeriod is used in pod-kill action. It represents - the duration in seconds before the pod should be deleted. - Value must be non-negative integer. The default value is - zero that indicates delete immediately. - format: int64 - minimum: 0 - type: integer - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about pods. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that + can be used to select nodes. Selector which must + match a node's labels, and objects must belong + to these selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: + Pending / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a + set values that used to select pods. The key defines + the namespace which pods belong, and the each + values is a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected + program. It's a possibly signed sequence of decimal + numbers, such as "300ms", "-1.5h" or "2h45m". Valid + time units are "ns", "us" (or "µs"), "ms", "s", "m", + "h". + type: string + value: + description: Value is required when the mode is set + to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos + action. If `FixedPercentMode`, provide a number from + 0-100 to specify the percent of pods the server can + do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of + pods to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + type: + type: string + required: + - schedule + - type + type: object + statusCheck: + description: StatusCheck describe the behavior of StatusCheck. + Only used when Type is TypeStatusCheck. + properties: + duration: + description: Duration defines the duration of the whole + status check if the number of failed execution does not + exceed the failure threshold. Duration is available to + both `Synchronous` and `Continuous` mode. 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". + type: string + failureThreshold: + default: 3 + description: FailureThreshold defines the minimum consecutive + failure for the status check to be considered failed. + minimum: 1 + type: integer + http: + properties: + body: type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. + criteria: + description: Criteria defines how to determine the result + of the status check. properties: - key: - description: key is the label key that the selector - applies to. + statusCode: + description: StatusCode defines the expected http + status code for the request. A statusCode string + could be a single code (e.g. 200), or an inclusive + range (e.g. 200-400, both `200` and `400` are + included). type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. + required: + - statusCode + type: object + headers: + additionalProperties: + items: type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. + type: array + description: "A Header represents the key-value pairs + in an HTTP header. \n The keys should be in canonical + form, as returned by CanonicalHeaderKey." + type: object + method: + default: GET + enum: + - GET + - POST + type: string + url: + type: string + required: + - criteria + - url + type: object + intervalSeconds: + default: 10 + description: IntervalSeconds defines how often (in seconds) + to perform an execution of status check. + minimum: 1 + type: integer + mode: + description: 'Mode defines the execution mode of the status + check. Support type: Synchronous / Continuous' + enum: + - Synchronous + - Continuous + type: string + recordsHistoryLimit: + default: 100 + description: RecordsHistoryLimit defines the number of record + to retain. + maximum: 1000 + minimum: 1 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold defines the minimum consecutive + successes for the status check to be considered successful. + SuccessThreshold only works for `Synchronous` mode. + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: TimeoutSeconds defines the number of seconds + after which an execution of status check times out. + minimum: 1 + type: integer + type: + default: HTTP + description: 'Type defines the specific status check type. + Support type: HTTP' + enum: + - HTTP + type: string + required: + - type + type: object + stressChaos: + description: StressChaosSpec defines the desired state of StressChaos + properties: + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action + type: string + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. + type: object + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + stressngStressors: + description: StressngStressors defines plenty of stressors + just like `Stressors` except that it's an experimental + feature and more powerful. You can define stressors in + `stress-ng` (see also `man stress-ng`) dialect, however + not all of the supported stressors are well tested. It + maybe retired in later releases. You should always use + `Stressors` to define the stressors and use this only + when you want more stressors unsupported by `Stressors`. + When both `StressngStressors` and `Stressors` are defined, + `StressngStressors` wins. + type: string + stressors: + description: Stressors defines plenty of stressors supported + to stress system components out. You can use one or more + of them to make up various kinds of stresses. At least + one of the stressors should be specified. + properties: + cpu: + description: CPUStressor stresses CPU out + properties: + load: + description: Load specifies P percent loading per + CPU worker. 0 is effectively a sleep (no load) + and 100 is full loading. + maximum: 100 + minimum: 0 + type: integer + options: + description: extend stress-ng options items: type: string type: array + workers: + description: Workers specifies N workers to apply + the stressor. Maximum 8192 workers can run by + stress-ng + maximum: 8192 + type: integer required: - - key - - operator + - workers type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: + memory: + description: MemoryStressor stresses virtual memory + out + properties: + oomScoreAdj: + default: 0 + description: OOMScoreAdj sets the oom_score_adj + of the stress process. See `man 5 proc` to know + more about this option. + maximum: 1000 + minimum: -1000 + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: Size specifies N bytes consumed per + vm worker, default is the total available memory. + One can specify the size as % of total available + memory or in units of B, KB/KiB, MB/MiB, GB/GiB, + TB/TiB. + type: string + workers: + description: Workers specifies N workers to apply + the stressor. Maximum 8192 workers can run by + stress-ng + maximum: 8192 + type: integer + required: + - workers + type: object + type: object + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - mode + - selector + type: object + task: + description: Task describes the behavior of the custom task. + Only used when Type is TypeTask. + properties: + container: + description: Container is the main container image to run + in the pod + properties: + args: + description: 'Arguments to the entrypoint. The container + image''s CMD is used if this is not provided. Variable + references $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, the + reference in the input string will be unchanged. Double + $$ are reduced to a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Cannot be updated. More info: + https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The container image''s ENTRYPOINT is used + if this is not provided. Variable references $(VAR_NAME) + are expanded using the container''s environment. If + a variable cannot be resolved, the reference in the + input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable exists + or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set in + the container. Cannot be updated. + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined environment + variables in the container and any service environment + variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults + to "".' + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: + supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, + requests.cpu, requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in + the pod's namespace + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined within + a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container is + starting. When a key exists in multiple sources, the + value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will + take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source of + a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config + management to default or override container images + in workload controllers like Deployments and StatefulSets.' type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, + IfNotPresent. Defaults to Always if :latest tag is + specified, or IfNotPresent otherwise. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: + lifecycle: + description: Actions that the management system should + take in response to container lifecycle events. Cannot + be updated. + properties: + postStart: + description: 'PostStart is called immediately after + a container is created. If the handler fails, + the container is terminated and restarted according + to its restart policy. Other management of the + container blocks until the hook completes. More + info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of + this field and lifecycle hooks will fail in + runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately before + a container is terminated due to an API request + or management event such as liveness/startup probe + failure, preemption, resource contention, etc. + The handler is not called if the container crashes + or exits. The Pod''s termination grace period + countdown begins before the PreStop hook is executed. + Regardless of the outcome of the handler, the + container will eventually terminate within the + Pod''s termination grace period (unless delayed + by finalizers). Other management of the container + blocks until the hook completes or until the termination + grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names will + be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of + this field and lifecycle hooks will fail in + runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. Cannot + be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. type: string - type: array - pods: - additionalProperties: + ports: + description: List of ports to expose from the container. + Not specifying a port here DOES NOT prevent that port + from being exposed. Any port which is listening on + the default "0.0.0.0" address inside a container will + be accessible from the network. Modifying this array + with strategic merge patch may corrupt the data. For + more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. items: - type: string + description: ContainerPort represents a network port + in a single container. + properties: + containerPort: + description: Number of port to expose on the pod's + IP address. This must be a valid port number, + 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on the host. + If specified, this must be a valid port number, + 0 < x < 65536. If HostNetwork is specified, + this must match ContainerPort. Most containers + do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an IANA_SVC_NAME + and unique within the pod. Each named port in + a pod must have a unique name. Name for the + port that can be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, TCP, + or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. IF `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - action - - mode - - selector - type: object - stress_chaos: - description: StressChaosSpec defines the desired state of StressChaos - properties: - containerName: - description: ContainerName indicates the target container - to inject stress in - type: string - duration: - description: Duration represents the duration of the chaos - action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service readiness. + Container will be removed from service endpoints if + the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource + resize policy for the container. + properties: + resourceName: + description: 'Name of the resource to which this + resource resize policy applies. Supported values: + cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when specified + resource is resized. If not specified, it defaults + to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this container. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. + claims: + description: "Claims lists the names of resources, + defined in spec.resourceClaims, that are used + by this container. \n This is an alpha field and + requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can + only be set for containers." items: - type: string + description: ResourceClaim references one entry + in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one + entry in pod.spec.resourceClaims of the + Pod where this field is used. It makes that + resource available inside a container. + type: string + required: + - name + type: object type: array - required: - - key - - operator + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount + of compute resources required. If Requests is + omitted for a container, it defaults to Limits + if that is explicitly specified, otherwise to + an implementation-defined value. Requests cannot + exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: + restartPolicy: + description: 'RestartPolicy defines the restart behavior + of individual containers in a pod. This field may + only be set for init containers, and the only allowed + value is "Always". For non-init containers or when + this field is not specified, the restart behavior + is defined by the Pod''s restart policy and the container + type. Setting the RestartPolicy as "Always" for the + init container will have the following effect: this + init container will be continually restarted on exit + until all regular containers have terminated. Once + all regular containers have completed, all init containers + with restartPolicy "Always" will be shut down. This + lifecycle differs from normal init containers and + is often referred to as a "sidecar" container. Although + this init container still starts in the init container + sequence, it does not wait for the container to complete + before proceeding to the next init container. Instead, + the next init container starts immediately after this + init container is started, or after any startupProbe + has successfully completed.' type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: + securityContext: + description: 'SecurityContext defines the security options + the container should be run with. If set, the fields + of SecurityContext override the equivalent fields + of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges than + its parent process. This bool directly controls + if the no_new_privs flag will be set on the container + process. AllowPrivilegeEscalation is true always + when the container is: 1) run as Privileged 2) + has CAP_SYS_ADMIN Note that this field cannot + be set when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running + containers. Defaults to the default set of capabilities + granted by the container runtime. Note that this + field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes + in privileged containers are essentially equivalent + to root on the host. Defaults to false. Note that + this field cannot be set when spec.os.name is + windows. + type: boolean + procMount: + description: procMount denotes the type of proc + mount to use for the containers. The default is + DefaultProcMount which uses the container runtime + defaults for readonly paths and masked paths. + This requires the ProcMountType feature flag to + be enabled. Note that this field cannot be set + when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only + root filesystem. Default is false. Note that this + field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the + container process. Uses runtime default if unset. + May also be set in PodSecurityContext. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run + as a non-root user. If true, the Kubelet will + validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start + the container if it does. If unset or false, no + such validation will be performed. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in + SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the + container process. Defaults to user specified + in image metadata if unspecified. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in + SecurityContext takes precedence. Note that this + field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to + the container. If unspecified, the container runtime + will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + properties: + level: + description: Level is SELinux level label that + applies to the container. + type: string + role: + description: Role is a SELinux role label that + applies to the container. + type: string + type: + description: Type is a SELinux type label that + applies to the container. + type: string + user: + description: User is a SELinux user label that + applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this + container. If seccomp options are provided at + both the pod & container level, the container + options override the pod options. Note that this + field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. + The profile must be preconfigured on the node + to work. Must be a descending path, relative + to the kubelet's configured seccomp profile + location. Must be set if type is "Localhost". + Must NOT be set for any other type. + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: + \n Localhost - a profile defined in a file + on the node should be used. RuntimeDefault + - the container runtime default profile should + be used. Unconfined - no profile should be + applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options + from the PodSecurityContext will be used. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the + GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name + of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. + All of a Pod's containers must have the same + effective HostProcess value (it is not allowed + to have a mix of HostProcess containers and + non-HostProcess containers). In addition, + if HostProcess is true then HostNetwork must + also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run + the entrypoint of the container process. Defaults + to the user specified in image metadata if + unspecified. May also be set in PodSecurityContext. + If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the Pod has + successfully initialized. If specified, no other probes + are executed until this completes successfully. If + this probe fails, the Pod will be restarted, just + as if the livenessProbe failed. This can be used to + provide different probe parameters at the beginning + of a Pod''s lifecycle, when it might take a long time + to load data or warm a cache, than during steady-state + operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name. This + will be canonicalized upon output, so + case-variant names will be understood + as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will + always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close + the stdin channel after it has been opened by a single + attach. When stdin is true the stdin stream will remain + open across multiple attach sessions. If stdinOnce + is set to true, stdin is opened on container start, + is empty until the first client attaches to stdin, + and then remains open and accepts data until the client + disconnects, at which time stdin is closed and remains + closed until the container is restarted. If this flag + is false, a container processes that reads from stdin + will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to which + the container''s termination message will be written + is mounted into the container''s filesystem. Message + written is intended to be brief final status, such + as an assertion failure message. Will be truncated + by the node if greater than 4096 bytes. The total + message length across all containers will be limited + to 12kb. Defaults to /dev/termination-log. Cannot + be updated.' type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: + terminationMessagePolicy: + description: Indicate how the termination message should + be populated. File will use the contents of terminationMessagePath + to populate the container status message on both success + and failure. FallbackToLogsOnError will use the last + chunk of container log output if the termination message + file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, + whichever is smaller. Defaults to File. Cannot be + updated. type: string - type: array - pods: - additionalProperties: + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices + to be used by the container. items: - type: string + description: volumeDevice describes a mapping of a + raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside of + the container that the device will be mapped + to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - stressngStressors: - description: StressngStressors defines plenty of stressors - just like `Stressors` except that it's an experimental feature - and more powerful. You can define stressors in `stress-ng` - (see also `man stress-ng`) dialect, however not all of the - supported stressors are well tested. It maybe retired in - later releases. You should always use `Stressors` to define - the stressors and use this only when you want more stressors - unsupported by `Stressors`. When both `StressngStressors` - and `Stressors` are defined, `StressngStressors` wins. - type: string - stressors: - description: Stressors defines plenty of stressors supported - to stress system components out. You can use one or more - of them to make up various kinds of stresses. At least one - of the stressors should be specified. - properties: - cpu: - description: CPUStressor stresses CPU out - properties: - load: - description: Load specifies P percent loading per - CPU worker. 0 is effectively a sleep (no load) and - 100 is full loading. - type: integer - options: - description: extend stress-ng options - items: - type: string - type: array - workers: - description: Workers specifies N workers to apply - the stressor. - type: integer - required: - - workers - type: object - memory: - description: MemoryStressor stresses virtual memory out + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting of a + Volume within a container. + properties: + mountPath: + description: Path within the container at which + the volume should be mounted. Must not contain + ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts + are propagated from the host to container and + the other way around. When not set, MountPropagationNone + is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write + otherwise (false or unspecified). Defaults to + false. + type: boolean + subPath: + description: Path within the volume from which + the container's volume should be mounted. Defaults + to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from + which the container's volume should be mounted. + Behaves similarly to SubPath but environment + variable references $(VAR_NAME) are expanded + using the container's environment. Defaults + to "" (volume's root). SubPathExpr and SubPath + are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not specified, + the container runtime's default will be used, which + might be configured in the container image. Cannot + be updated. + type: string + required: + - name + type: object + volumes: + description: Volumes is a list of volumes that can be mounted + by containers in a template. + items: + description: Volume represents a named volume in a pod + that may be accessed by any container in the pod. properties: - options: - description: extend stress-ng options - items: - type: string - type: array - size: - description: Size specifies N bytes consumed per vm - worker, default is the total available memory. One - can specify the size as % of total available memory - or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. + awsElasticBlockStore: + description: 'awsElasticBlockStore represents an AWS + Disk resource that is attached to a kubelet''s host + machine and then exposed to the pod. More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in the + volume that you want to mount. If omitted, the + default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for + /dev/sda is "0" (or you can leave the property + empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force the + readOnly setting in VolumeMounts. More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the persistent + disk resource in AWS (Amazon EBS volume). More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data Disk + mount on the host and bind mount to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching + mode: None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data + disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in + the blob storage + type: string + fsType: + description: fsType is Filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: + multiple blob disks per storage account Dedicated: + single blob disk per storage account Managed: + azure managed data disk (only in managed availability + set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File Service + mount on the host and bind mount to the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret + that contains Azure Storage Account Name and + Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount on + the host that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors is + a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the mounted + root, rather than the full Ceph tree, default + is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile + is the path to key ring for User, default is + /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef + is reference to the authentication secret for + User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the rados + user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume attached + and mounted on kubelets host machine. More info: + https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Examples: "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points to + a secret object containing parameters used to + connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the volume + in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that + should populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced ConfigMap + will be projected into the volume as a file + whose name is the key and content is the value. + If specified, the listed keys will be projected + into the specified paths, and unlisted keys + will not be present. If a key is specified which + is not present in the ConfigMap, the volume + setup will error unless it is marked optional. + Paths must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 and + 0777 or a decimal value between 0 and + 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. If not specified, the volume + defaultMode will be used. This might be + in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path of + the file to map the key to. May not be + an absolute path. May not contain the + path element '..'. May not start with + the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents + ephemeral storage that is handled by certain external + CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI driver + that handles this volume. Consult with your + admin for the correct name as registered in + the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", "xfs", + "ntfs". If not provided, the empty value is + passed to the associated CSI driver which will + determine the default filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference + to the secret object containing sensitive information + to pass to the CSI driver to complete the CSI + NodePublishVolume and NodeUnpublishVolume calls. + This field is optional, and may be empty if + no secret is required. If the secret object + contains more than one secret, all secret references + are passed. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only configuration + for the volume. Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. + Consult your driver's documentation for supported + values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API about + the pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on created + files by default. Must be a Optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: Items is a list of downward API volume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, + defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used to + set permissions on this file, must be + an octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML + accepts both octal and decimal values, + JSON requires decimal values for mode + bits. If not specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must + not be absolute or contain the ''..'' + path. Must be utf-8 encoded. The first + item of the relative path must not start + with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the + container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu + and requests.memory) are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults + to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary directory + that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type of storage + medium should back this directory. The default + is "" which means to use the node''s default + medium. Must be an empty string (default) or + Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount of + local storage required for this EmptyDir volume. + The size limit is also applicable for memory + medium. The maximum usage on memory medium EmptyDir + would be the minimum value between the SizeLimit + specified here and the sum of memory limits + of all containers in a pod. The default is nil + which means that the limit is undefined. More + info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume that is + handled by a cluster storage driver. The volume's + lifecycle is tied to the pod that defines it - it + will be created before the pod starts, and deleted + when the pod is removed. \n Use this if: a) the + volume is only needed while the pod runs, b) features + of normal volumes like restoring from snapshot or + capacity tracking are needed, c) the storage driver + is specified through a storage class, and d) the + storage driver supports dynamic volume provisioning + through a PersistentVolumeClaim (see EphemeralVolumeSource + for more information on the connection between this + volume type and PersistentVolumeClaim). \n Use PersistentVolumeClaim + or one of the vendor-specific APIs for volumes that + persist for longer than the lifecycle of an individual + pod. \n Use CSI for light-weight local ephemeral + volumes if the CSI driver is meant to be used that + way - see the documentation of the driver for more + information. \n A pod can use both types of ephemeral + volumes and persistent volumes at the same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone + PVC to provision the volume. The pod in which + this EphemeralVolumeSource is embedded will + be the owner of the PVC, i.e. the PVC will be + deleted together with the pod. The name of + the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` + array entry. Pod validation will reject the + pod if the concatenated name is not valid for + a PVC (for example, too long). \n An existing + PVC with that name that is not owned by the + pod will *not* be used for the pod to avoid + using an unrelated volume by mistake. Starting + the pod is then blocked until the unrelated + PVC is removed. If such a pre-created PVC is + meant to be used by the pod, the PVC has to + updated with an owner reference to the pod once + the pod exists. Normally this should not be + necessary, but it may be useful when manually + reconstructing a broken cluster. \n This field + is read-only and no changes will be made by + Kubernetes to the PVC after it has been created. + \n Required, must not be nil." + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when creating + it. No other fields are allowed and will + be rejected during validation. + type: object + spec: + description: The specification for the PersistentVolumeClaim. + The entire content is copied unchanged into + the PVC that gets created from this template. + The same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: 'accessModes contains the + desired access modes the volume should + have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can be + used to specify either: * An existing + VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller + can support the specified data source, + it will create a new volume based on + the contents of the specified data source. + When the AnyVolumeDataSource feature + gate is enabled, dataSource contents + will be copied to dataSourceRef, and + dataSourceRef contents will be copied + to dataSource when dataSourceRef.namespace + is not specified. If the namespace is + specified, then dataSourceRef will not + be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, the + specified Kind must be in the core + API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies + the object from which to populate the + volume with data, if a non-empty volume + is desired. This may be any object from + a non-empty API group (non core object) + or a PersistentVolumeClaim object. When + this field is specified, volume binding + will only succeed if the type of the + specified object matches some installed + volume populator or dynamic provisioner. + This field will replace the functionality + of the dataSource field and as such + if both fields are non-empty, they must + have the same value. For backwards compatibility, + when namespace isn''t specified in dataSourceRef, + both fields (dataSource and dataSourceRef) + will be set to the same value automatically + if one of them is empty and the other + is non-empty. When namespace is specified + in dataSourceRef, dataSource isn''t + set to the same value and must be empty. + There are three important differences + between dataSource and dataSourceRef: + * While dataSource only allows two specific + types of objects, dataSourceRef allows + any non-core object, as well as PersistentVolumeClaim + objects. * While dataSource ignores + disallowed values (dropping them), dataSourceRef + preserves all values, and generates + an error if a disallowed value is specified. + * While dataSource only allows local + objects, dataSourceRef allows objects + in any namespaces. (Beta) Using this + field requires the AnyVolumeDataSource + feature gate to be enabled. (Alpha) + Using the namespace field of dataSourceRef + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, the + specified Kind must be in the core + API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: Namespace is the namespace + of resource being referenced Note + that when a namespace is specified, + a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent + namespace to allow that namespace's + owner to accept the reference. See + the ReferenceGrant documentation + for details. (Alpha) This field + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents the + minimum resources the volume should + have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed + to specify resource requirements that + are lower than previous value but must + still be higher than capacity recorded + in the status field of the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the names + of resources, defined in spec.resourceClaims, + that are used by this container. + \n This is an alpha field and requires + enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. + It can only be set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match + the name of one entry in pod.spec.resourceClaims + of the Pod where this field + is used. It makes that resource + available inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the + maximum amount of compute resources + allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the + minimum amount of compute resources + required. If Requests is omitted + for a container, it defaults to + Limits if that is explicitly specified, + otherwise to an implementation-defined + value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query + over volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a + list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a + set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values + array must be non-empty. If + the operator is Exists or + DoesNotExist, the values array + must be empty. This array + is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName is the + name of the StorageClass required by + the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type + of volume is required by the claim. + Value of Filesystem is implied when + not included in claim spec. + type: string + volumeName: + description: volumeName is the binding + reference to the PersistentVolume backing + this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource + that is attached to a kubelet's host machine and + then exposed to the pod. + properties: + fsType: + description: 'fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. TODO: how do we prevent errors + in the filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target + worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume world + wide identifiers (wwids) Either wwids or combination + of targetWWNs and lun must be set, but not both + simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume + resource that is provisioned/attached using an exec + based plugin. + properties: + driver: + description: driver is the name of the driver + to use for this volume. + type: string + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". The default filesystem depends on FlexVolume + script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field + holds extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef + is reference to the secret object containing + sensitive information to pass to the plugin + scripts. This may be empty if no secret object + is specified. If the secret object contains + more than one secret, all secrets are passed + to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume attached + to a kubelet's host machine. This depends on the + Flocker control service being running + properties: + datasetName: + description: datasetName is Name of the dataset + stored as metadata -> name on the dataset for + Flocker should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. + This is unique identifier of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE Disk + resource that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of the + volume that you want to mount. Tip: Ensure that + the filesystem type is supported by the host + operating system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in the + volume that you want to mount. If omitted, the + default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for + /dev/sda is "0" (or you can leave the property + empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the PD + resource in GCE. Used to identify the disk in + GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository + at a particular revision. DEPRECATED: GitRepo is + deprecated. To provision a container with a git + repo, mount an EmptyDir into an InitContainer that + clones the repo using git, then mount the EmptyDir + into the Pod''s container.' + properties: + directory: + description: directory is the target directory + name. Must not contain or start with '..'. If + '.' is supplied, the volume directory will be + the git repository. Otherwise, if specified, + the volume will contain the git repository in + the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the + specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs mount + on the host that shares a pod''s lifetime. More + info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name that + details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume path. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the Glusterfs + volume to be mounted with read-only permissions. + Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing file + or directory on the host machine that is directly + exposed to the container. This is generally used + for system agents or other privileged things that + are allowed to see the host machine. Most containers + will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can use + host directory mounts and who can/can not mount + host directories as read/write.' + properties: + path: + description: 'path of the directory on the host. + If the path is a symlink, it will follow the + link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults + to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource + that is attached to a kubelet''s host machine and + then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether + support iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support + iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI + Initiator Name. If initiatorName is specified + with iscsiInterface simultaneously, new iSCSI + interface : will + be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified + Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface Name + that uses an iSCSI transport. Defaults to 'default' + (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal + List. The portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for + iSCSI target and initiator authentication + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target Portal. + The Portal is either an IP or ip_addr:port if + the port is other than default (typically TCP + ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL + and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' type: string - workers: - description: Workers specifies N workers to apply - the stressor. - type: integer + nfs: + description: 'nfs represents an NFS mount on the host + that shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the NFS + server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the NFS + export to be mounted with read-only permissions. + Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP address + of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource represents + a reference to a PersistentVolumeClaim in the same + namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this + volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets + host machine + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon + Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx + volume attached and mounted on kubelets host machine + properties: + fsType: + description: fSType represents the filesystem + type to mount Must be a filesystem type supported + by the host operating system. Ex. "ext4", "xfs". + Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx + volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources + secrets, configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits used + to set permissions on created files by default. + Must be an octal value between 0000 and 0777 + or a decimal value between 0 and 511. YAML accepts + both octal and decimal values, JSON requires + decimal values for mode bits. Directories within + the path are not affected by this setting. This + might be in conflict with other options that + affect the file mode, like fsGroup, and the + result can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume projections + items: + description: Projection that may be projected + along with other supported volume types + properties: + configMap: + description: configMap information about + the configMap data to project + properties: + items: + description: items if unspecified, each + key-value pair in the Data field of + the referenced ConfigMap will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will + be projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not + present in the ConfigMap, the volume + setup will error unless it is marked + optional. Paths must be relative and + may not contain the '..' path or start + with '..'. + items: + description: Maps a string key to + a path within a volume. + properties: + key: + description: key is the key to + project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 + or a decimal value between 0 + and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume + defaultMode will be used. This + might be in conflict with other + options that affect the file + mode, like fsGroup, and the + result can be other mode bits + set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the + key to. May not be an absolute + path. May not contain the path + element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about + the downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile + represents information to create + the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only annotations, + labels, name and namespace are + supported.' + properties: + apiVersion: + description: Version of the + schema the FieldPath is + written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field + to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits + used to set permissions on this + file, must be an octal value + between 0000 and 0777 or a decimal + value between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If not + specified, the volume defaultMode + will be used. This might be + in conflict with other options + that affect the file mode, like + fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file + to be created. Must not be absolute + or contain the ''..'' path. + Must be utf-8 encoded. The first + item of the relative path must + not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource + of the container: only resources + limits and requests (limits.cpu, + limits.memory, requests.cpu + and requests.memory) are currently + supported.' + properties: + containerName: + description: 'Container name: + required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the + output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about the + secret data to project + properties: + items: + description: items if unspecified, each + key-value pair in the Data field of + the referenced Secret will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will + be projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not + present in the Secret, the volume + setup will error unless it is marked + optional. Paths must be relative and + may not contain the '..' path or start + with '..'. + items: + description: Maps a string key to + a path within a volume. + properties: + key: + description: key is the key to + project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 + or a decimal value between 0 + and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume + defaultMode will be used. This + might be in conflict with other + options that affect the file + mode, like fsGroup, and the + result can be other mode bits + set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the + key to. May not be an absolute + path. May not contain the path + element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional field specify + whether the Secret or its key must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to + project + properties: + audience: + description: audience is the intended + audience of the token. A recipient + of a token must identify itself with + an identifier specified in the audience + of the token, and otherwise should + reject the token. The audience defaults + to the identifier of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is the + requested duration of validity of + the service account token. As the + token approaches expiration, the kubelet + volume plugin will proactively rotate + the service account token. The kubelet + will start trying to rotate the token + if the token is older than 80 percent + of its time to live or if the token + is older than 24 hours.Defaults to + 1 hour and must be at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative + to the mount point of the file to + project the token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount on + the host that shares a pod's lifetime + properties: + group: + description: group to map volume access to Default + is no group + type: string + readOnly: + description: readOnly here will force the Quobyte + volume to be mounted with read-only permissions. + Defaults to false. + type: boolean + registry: + description: registry represents a single or multiple + Quobyte Registry services specified as a string + as host:port pair (multiple entries are separated + with commas) which acts as the central registry + for volumes + type: string + tenant: + description: tenant owning the given Quobyte volume + in the Backend Used with dynamically provisioned + Quobyte volumes, value is set by the plugin + type: string + user: + description: user to map volume access to Defaults + to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + image: + description: 'image is the rados image name. More + info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring + for RBDUser. Default is /etc/ceph/keyring. More + info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of Ceph + monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. Default + is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides keyring. + Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. Default + is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of the + ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the + ScaleIO Protection Domain for the configured + storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret + for ScaleIO user and other sensitive information. + If this is not provided, Login operation will + fail. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL + communication with Gateway, default false + type: boolean + storageMode: + description: storageMode indicates whether the + storage for a volume should be ThickProvisioned + or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage + Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage + system as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume + already created in the ScaleIO system that is + associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that should + populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: items If unspecified, each key-value + pair in the Data field of the referenced Secret + will be projected into the volume as a file + whose name is the key and content is the value. + If specified, the listed keys will be projected + into the specified paths, and unlisted keys + will not be present. If a key is specified which + is not present in the Secret, the volume setup + will error unless it is marked optional. Paths + must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 and + 0777 or a decimal value between 0 and + 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. If not specified, the volume + defaultMode will be used. This might be + in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path of + the file to map the key to. May not be + an absolute path. May not contain the + path element '..'. May not start with + the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether the + Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the secret + in the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS volume + attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret to + use for obtaining the StorageOS API credentials. If + not specified, default values will be attempted. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable + name of the StorageOS volume. Volume names + are only unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the scope + of the volume within StorageOS. If no namespace + is specified then the Pod's namespace will be + used. This allows the Kubernetes name scoping + to be mirrored within StorageOS for tighter + integration. Set VolumeName to any name to override + the default behaviour. Set to "default" if you + are not using namespaces within StorageOS. Namespaces + that do not pre-exist within StorageOS will + be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere volume + attached and mounted on kubelets host machine + properties: + fsType: + description: fsType is filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy + Based Management (SPBM) profile ID associated + with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage + Policy Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object required: - - workers + - name type: object - type: object - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the max % of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the % of pods to do chaos - action - type: string - required: - - mode - - selector - type: object - tasks: - items: + type: array + type: object + templateType: type: string - type: array - template_type: - type: string - time_chaos: - description: TimeChaosSpec defines the desired state of TimeChaos - properties: - clockIds: - description: ClockIds defines all affected clock id All available - options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", - "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", - "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] - items: + timeChaos: + description: TimeChaosSpec defines the desired state of TimeChaos + properties: + clockIds: + description: ClockIds defines all affected clock id All + available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: ContainerNames indicates list of the name of + affected container. If not set, the first container will + be injected + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos + action type: string - type: array - containerNames: - description: ContainerName indicates the name of affected - container. If not set, all containers will be injected - items: + mode: + description: 'Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent' + enum: + - one + - all + - fixed + - fixed-percent + - random-max-percent type: string - type: array - duration: - description: Duration represents the duration of the chaos - action - type: string - mode: - description: 'Mode defines the mode to run chaos action. Supported - mode: one / all / fixed / fixed-percent / random-max-percent' - enum: - - one - - all - - fixed - - fixed-percent - - random-max-percent - type: string - scheduler: - description: Scheduler defines some schedule rules to control - the running time of the chaos experiment about time. - properties: - cron: - description: "Cron defines a cron job rule. \n Some rule - examples: \"0 30 * * * *\" means to \"Every hour on - the half hour\" \"@hourly\" means to \"Every hour\" - \"@every 1h30m\" means to \"Every hour thirty\" \n More - rule info: https://godoc.org/github.com/robfig/cron" - type: string - required: - - cron - type: object - selector: - description: Selector is used to select pods that are used - to inject chaos action. - properties: - annotationSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on annotations. - type: object - expressionSelectors: - description: a slice of label selector expressions that - can be used to select objects. A list of selectors based - on set-based label expressions. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + description: Selector is used to select pods that are used + to inject chaos action. + properties: + annotationSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on annotations. + type: object + expressionSelectors: + description: a slice of label selector expressions that + can be used to select objects. A list of selectors + based on set-based label expressions. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. type: string - type: array - required: - - key - - operator + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + fieldSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on fields. type: object - type: array - fieldSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on fields. - type: object - labelSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select objects. A selector based on labels. - type: object - namespaces: - description: Namespaces is a set of namespace to which - objects belong. - items: - type: string - type: array - nodeSelectors: - additionalProperties: - type: string - description: Map of string keys and values that can be - used to select nodes. Selector which must match a node's - labels, and objects must belong to these selected nodes. - type: object - nodes: - description: Nodes is a set of node name and objects must - belong to these nodes. - items: - type: string - type: array - podPhaseSelectors: - description: 'PodPhaseSelectors is a set of condition - of a pod at the current time. supported value: Pending - / Running / Succeeded / Failed / Unknown' - items: - type: string - type: array - pods: - additionalProperties: + labelSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select objects. A selector based on labels. + type: object + namespaces: + description: Namespaces is a set of namespace to which + objects belong. items: type: string type: array - description: Pods is a map of string keys and a set values - that used to select pods. The key defines the namespace - which pods belong, and the each values is a set of pod - names. - type: object - type: object - timeOffset: - description: TimeOffset defines the delta time of injected - program. It's a possibly signed sequence of decimal numbers, - such as "300ms", "-1.5h" or "2h45m". Valid time units are - "ns", "us" (or "µs"), "ms", "s", "m", "h". - type: string - value: - description: Value is required when the mode is set to `FixedPodMode` - / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. If `FixedPodMode`, - provide an integer of pods to do chaos action. If `FixedPercentPodMod`, - provide a number from 0-100 to specify the percent of pods - the server can do chaos action. If `RandomMaxPercentPodMod`, provide - a number from 0-100 to specify the max percent of pods to - do chaos action - type: string - required: - - mode - - selector - - timeOffset - type: object - required: - - name - - template_type - type: object - type: array - required: - - entry - - templates - type: object - status: - description: Most recently observed status of the workflow - properties: - entry_node: - type: string - type: object - required: - - spec - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + nodeSelectors: + additionalProperties: + type: string + description: Map of string keys and values that can + be used to select nodes. Selector which must match + a node's labels, and objects must belong to these + selected nodes. + type: object + nodes: + description: Nodes is a set of node name and objects + must belong to these nodes. + items: + type: string + type: array + podPhaseSelectors: + description: 'PodPhaseSelectors is a set of condition + of a pod at the current time. supported value: Pending + / Running / Succeeded / Failed / Unknown' + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: Pods is a map of string keys and a set + values that used to select pods. The key defines the + namespace which pods belong, and the each values is + a set of pod names. + type: object + type: object + timeOffset: + description: TimeOffset defines the delta time of injected + program. It's a possibly signed sequence of decimal numbers, + such as "300ms", "-1.5h" or "2h45m". Valid time units + are "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: Value is required when the mode is set to `FixedMode` + / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, + provide an integer of pods to do chaos action. If `FixedPercentMode`, + provide a number from 0-100 to specify the percent of + pods the server can do chaos action. IF `RandomMaxPercentMode`, provide + a number from 0-100 to specify the max percent of pods + to do chaos action + type: string + required: + - mode + - selector + - timeOffset + type: object + required: + - name + - templateType + type: object + type: array + required: + - entry + - templates + type: object + status: + description: Most recently observed status of the workflow + properties: + conditions: + description: Represents the latest available observations of a workflow's + current state. + items: + properties: + reason: + type: string + startTime: + format: date-time + type: string + status: + type: string + type: + type: string + required: + - reason + - status + - type + type: object + type: array + endTime: + format: date-time + type: string + entryNode: + type: string + startTime: + format: date-time + type: string + type: object + required: + - spec + type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] + subresources: + status: {} diff --git a/manifests/local-volume-provisioner.yaml b/manifests/local-volume-provisioner.yaml index df1e99e2c2..d3d489759d 100644 --- a/manifests/local-volume-provisioner.yaml +++ b/manifests/local-volume-provisioner.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: diff --git a/manifests/monitoring/README.md b/manifests/monitoring/README.md new file mode 100644 index 0000000000..9dcda5d063 --- /dev/null +++ b/manifests/monitoring/README.md @@ -0,0 +1,26 @@ +# Monitoring Chaos Mesh + +Most of Chaos Mesh components has some built-in metrics collectors/exporters for monitoring with [Prometheus](https://prometheus.io/). + +## Configure with Prometheus Operator + +With Prometheus Operator, we could easily monitoring Kubernetes Concepts like Service, Pod, etc with CRD. + +We provide several `ServiceMonitor` examples under directory `prometheus-operator`, you could build your own monitoring rules with them as references. + +## Configure with Prometheus Kubernetes Service Discovery + +There are several common-used annotations like `prometehus.io/scrape` and `prometehus.io/path` on Chaos Mesh components to configure Prometheus Kubernetes Discovery. After installing Chaos Mesh, you could use these following annotations to configure Prometheus Kubernetes Service Discovery. + +We provide a configuration example under directory `prometheus-kubernetes-service-discovery`. +## Setup Grafana Dashboard + +There are several Grafana Dashboards available for monitoring Chaos Mesh components: + +- Chaos Mesh Overview, [Grafana Dashboard](https://grafana.com/grafana/dashboards/15918) +- Chaos Mesh | Chaos Daemon, [Grafana Dashboard](https://grafana.com/grafana/dashboards/15919) + +And there are also other dashboards available for monitoring [controller-runtime](https://github.com/kubernetes-sigs/controller-runtime), which drives Chaos Mesh: + +- Controller Runtime Controllers Detail, [Grafana Dashboard](https://grafana.com/grafana/dashboards/15920) +- Controller Runtime Webhooks Detail, [Grafana Dashboard](https://grafana.com/grafana/dashboards/15921) diff --git a/manifests/monitoring/prometheus-kubernetes-service-discovery/prometheus-additional.yaml b/manifests/monitoring/prometheus-kubernetes-service-discovery/prometheus-additional.yaml new file mode 100644 index 0000000000..cba816f159 --- /dev/null +++ b/manifests/monitoring/prometheus-kubernetes-service-discovery/prometheus-additional.yaml @@ -0,0 +1,138 @@ +- job_name: "chaos-mesh-controller-manager" + kubernetes_sd_configs: + - role: endpoints + relabel_configs: + # keep only those services that has "prometheus.io/scrape: true" anootation. + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + regex: true + action: keep + # keep only those services that has "app.kubernetes.io/name: chaos-mesh" label + - source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_name] + regex: chaos-mesh + action: keep + # keep only those services that has "app.kubernetes.io/component: controller-manager" label + - source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_component] + regex: controller-manager + action: keep + # read the metric path from "prometheus.io/path: " annotation + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + regex: (.+) + target_label: __metrics_path__ + action: replace + # read the scrapping scheme from "prometheus.io/scheme: " annotation + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + # read the port from "prometheus.io/port: " annotation and update scrapping address accordingly + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + # add service namespace as label to the scrapped metrics + - source_labels: [__meta_kubernetes_namespace] + separator: ; + regex: (.*) + target_label: namespace + replacement: $1 + action: replace + # add service name as label to the scrapped metrics + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*) + target_label: service + replacement: $1 + action: replace +- job_name: "chaos-daemon" + kubernetes_sd_configs: + - role: endpoints + relabel_configs: + # keep only those services that has "prometheus.io/scrape: true" anootation. + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + regex: true + action: keep + # keep only those services that has "app.kubernetes.io/name: chaos-mesh" label + - source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_name] + regex: chaos-mesh + action: keep + # keep only those services that has "app.kubernetes.io/component: controller-manager" label + - source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_component] + regex: chaos-daemon + action: keep + # read the metric path from "prometheus.io/path: " annotation + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + regex: (.+) + target_label: __metrics_path__ + action: replace + # read the scrapping scheme from "prometheus.io/scheme: " annotation + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + # read the port from "prometheus.io/port: " annotation and update scrapping address accordingly + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + # add service namespace as label to the scrapped metrics + - source_labels: [__meta_kubernetes_namespace] + separator: ; + regex: (.*) + target_label: namespace + replacement: $1 + action: replace + # add service name as label to the scrapped metrics + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*) + target_label: service + replacement: $1 + action: replace +- job_name: "chaos-dashboard" + kubernetes_sd_configs: + - role: endpoints + relabel_configs: + # keep only those services that has "prometheus.io/scrape: true" anootation. + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + regex: true + action: keep + # keep only those services that has "app.kubernetes.io/name: chaos-mesh" label + - source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_name] + regex: chaos-mesh + action: keep + # keep only those services that has "app.kubernetes.io/component: controller-manager" label + - source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_component] + regex: chaos-dashboard + action: keep + # read the metric path from "prometheus.io/path: " annotation + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + regex: (.+) + target_label: __metrics_path__ + action: replace + # read the scrapping scheme from "prometheus.io/scheme: " annotation + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + # read the port from "prometheus.io/port: " annotation and update scrapping address accordingly + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + # add service namespace as label to the scrapped metrics + - source_labels: [__meta_kubernetes_namespace] + separator: ; + regex: (.*) + target_label: namespace + replacement: $1 + action: replace + # add service name as label to the scrapped metrics + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*) + target_label: service + replacement: $1 + action: replace diff --git a/manifests/monitoring/prometheus-operator/chaos-controller-manager-servicemonitor.yaml b/manifests/monitoring/prometheus-operator/chaos-controller-manager-servicemonitor.yaml new file mode 100644 index 0000000000..6ed1ee7a3b --- /dev/null +++ b/manifests/monitoring/prometheus-operator/chaos-controller-manager-servicemonitor.yaml @@ -0,0 +1,12 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: chaos-controller-manager +spec: + endpoints: + - interval: 30s + port: http + selector: + matchLabels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/component: controller-manager diff --git a/manifests/monitoring/prometheus-operator/chaos-daemon-servicemonitor.yaml b/manifests/monitoring/prometheus-operator/chaos-daemon-servicemonitor.yaml new file mode 100644 index 0000000000..2cf1761267 --- /dev/null +++ b/manifests/monitoring/prometheus-operator/chaos-daemon-servicemonitor.yaml @@ -0,0 +1,12 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: chaos-daemon +spec: + endpoints: + - interval: 30s + port: http + selector: + matchLabels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/component: chaos-daemon diff --git a/manifests/monitoring/prometheus-operator/chaos-dashboard-servicemonitor.yaml b/manifests/monitoring/prometheus-operator/chaos-dashboard-servicemonitor.yaml new file mode 100644 index 0000000000..77150f7628 --- /dev/null +++ b/manifests/monitoring/prometheus-operator/chaos-dashboard-servicemonitor.yaml @@ -0,0 +1,12 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: chaos-dashboard +spec: + endpoints: + - interval: 30s + port: metric + selector: + matchLabels: + app.kubernetes.io/name: chaos-mesh + app.kubernetes.io/component: chaos-dashboard diff --git a/pkg/annotation/utils.go b/pkg/annotation/utils.go index 19fc71d2fb..1894f978f4 100644 --- a/pkg/annotation/utils.go +++ b/pkg/annotation/utils.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package annotation @@ -24,7 +26,12 @@ const ( AnnotationPrefix = "chaos-mesh" ) -func GenKeyForImage(pc *v1alpha1.PodChaos, containerName string) string { +func GenKeyForImage(pc *v1alpha1.PodChaos, containerName string, isInit bool) string { + if isInit { + containerName += "-init" + } else { + containerName += "-normal" + } imageKey := fmt.Sprintf("%s-%s-%s-%s-image", AnnotationPrefix, pc.Name, pc.Spec.Action, containerName) // name part of annotation must be no more than 63 characters. diff --git a/pkg/apiserver/archive/archive.go b/pkg/apiserver/archive/archive.go deleted file mode 100644 index d7c3407e0b..0000000000 --- a/pkg/apiserver/archive/archive.go +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package archive - -import ( - "context" - "fmt" - "net/http" - "strings" - "time" - - "github.com/gin-gonic/gin" - "github.com/jinzhu/gorm" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/apiserver/utils" - "github.com/chaos-mesh/chaos-mesh/pkg/core" -) - -// Service defines a handler service for archive experiments. -type Service struct { - archive core.ExperimentStore - event core.EventStore -} - -// NewService returns an archive experiment service instance. -func NewService( - archive core.ExperimentStore, - event core.EventStore, -) *Service { - return &Service{ - archive: archive, - event: event, - } -} - -// StatusResponse defines a common status struct. -type StatusResponse struct { - Status string `json:"status"` -} - -// Register mounts our HTTP handler on the mux. -func Register(r *gin.RouterGroup, s *Service) { - endpoint := r.Group("/archives") - endpoint.Use(utils.AuthRequired) - - endpoint.GET("", s.list) - endpoint.GET("/detail", s.detail) - endpoint.GET("/report", s.report) - endpoint.DELETE("/:uid", s.delete) - endpoint.DELETE("/", s.batchDelete) -} - -// Archive defines the basic information of an archive. -type Archive struct { - UID string `json:"uid"` - Kind string `json:"kind"` - Namespace string `json:"namespace"` - Name string `json:"name"` - Action string `json:"action"` - StartTime time.Time `json:"start_time"` - FinishTime time.Time `json:"finish_time"` -} - -// Detail represents an archive instance. -type Detail struct { - Archive - YAML core.KubeObjectYAMLDescription `json:"yaml"` -} - -// Report defines the report of archive experiments. -type Report struct { - Meta *Archive `json:"meta"` - Events []*core.Event `json:"events"` - TotalTime string `json:"total_time"` - TotalFaultTime string `json:"total_fault_time"` -} - -// @Summary Get archived chaos experiments. -// @Description Get archived chaos experiments. -// @Tags archives -// @Produce json -// @Param namespace query string false "namespace" -// @Param name query string false "name" -// @Param kind query string false "kind" Enums(PodChaos, IoChaos, NetworkChaos, TimeChaos, KernelChaos, StressChaos) -// @Success 200 {array} Archive -// @Router /archives [get] -// @Failure 500 {object} utils.APIError -func (s *Service) list(c *gin.Context) { - kind := c.Query("kind") - name := c.Query("name") - ns := c.Query("namespace") - - metas, err := s.archive.ListMeta(context.Background(), kind, ns, name, true) - if err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.NewWithNoMessage()) - return - } - - archives := make([]Archive, 0) - - for _, meta := range metas { - archives = append(archives, Archive{ - UID: meta.UID, - Kind: meta.Kind, - Namespace: meta.Namespace, - Name: meta.Name, - Action: meta.Action, - StartTime: meta.StartTime, - FinishTime: meta.FinishTime, - }) - } - - c.JSON(http.StatusOK, archives) -} - -// @Summary Get the detail of an archived chaos experiment. -// @Description Get the detail of an archived chaos experiment. -// @Tags archives -// @Produce json -// @Param uid query string true "uid" -// @Success 200 {object} Detail -// @Router /archives/detail [get] -// @Failure 500 {object} utils.APIError -func (s *Service) detail(c *gin.Context) { - var ( - err error - yaml core.KubeObjectYAMLDescription - detail Detail - ) - uid := c.Query("uid") - namespace := c.Query("namespace") - - if uid == "" { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInvalidRequest.New("uid cannot be empty")) - return - } - - exp, err := s.archive.FindByUID(context.Background(), uid) - if err != nil { - if gorm.IsRecordNotFoundError(err) { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInvalidRequest.New("the archive is not found")) - } else { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.NewWithNoMessage()) - } - return - } - - if len(namespace) != 0 && exp.Namespace != namespace { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInvalidRequest.New("exp %s belong to namespace %s but not namespace %s", uid, exp.Namespace, namespace)) - return - } - - switch exp.Kind { - case v1alpha1.KindPodChaos: - yaml, err = exp.ParsePodChaos() - case v1alpha1.KindIoChaos: - yaml, err = exp.ParseIOChaos() - case v1alpha1.KindNetworkChaos: - yaml, err = exp.ParseNetworkChaos() - case v1alpha1.KindTimeChaos: - yaml, err = exp.ParseTimeChaos() - case v1alpha1.KindKernelChaos: - yaml, err = exp.ParseKernelChaos() - case v1alpha1.KindStressChaos: - yaml, err = exp.ParseStressChaos() - case v1alpha1.KindDNSChaos: - yaml, err = exp.ParseDNSChaos() - case v1alpha1.KindAwsChaos: - yaml, err = exp.ParseAwsChaos() - default: - err = fmt.Errorf("kind %s is not support", exp.Kind) - } - if err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - return - } - - detail = Detail{ - Archive: Archive{ - UID: exp.UID, - Kind: exp.Kind, - Name: exp.Name, - Namespace: exp.Namespace, - Action: exp.Action, - StartTime: exp.StartTime, - FinishTime: exp.FinishTime, - }, - YAML: yaml, - } - - c.JSON(http.StatusOK, detail) -} - -// @Summary Get the report of an archived chaos experiment. -// @Description Get the report of an archived chaos experiment. -// @Tags archives -// @Produce json -// @Param uid query string true "uid" -// @Success 200 {array} Report -// @Router /archives/report [get] -// @Failure 500 {object} utils.APIError -func (s *Service) report(c *gin.Context) { - var ( - err error - report Report - ) - uid := c.Query("uid") - namespace := c.Query("namespace") - - if uid == "" { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInvalidRequest.New("uid cannot be empty")) - return - } - - meta, err := s.archive.FindMetaByUID(context.Background(), uid) - if err != nil { - if gorm.IsRecordNotFoundError(err) { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInvalidRequest.New("the archive is not found")) - } else { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.NewWithNoMessage()) - } - return - } - - if len(namespace) != 0 && meta.Namespace != namespace { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInvalidRequest.New("exp %s belong to namespace %s but not namespace %s", uid, meta.Namespace, namespace)) - return - } - - report.Meta = &Archive{ - UID: meta.UID, - Kind: meta.Kind, - Namespace: meta.Namespace, - Name: meta.Name, - Action: meta.Action, - StartTime: meta.StartTime, - FinishTime: meta.FinishTime, - } - - report.Events, err = s.event.ListByUID(context.TODO(), uid) - if err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.NewWithNoMessage()) - return - } - - report.TotalTime = report.Meta.FinishTime.Sub(report.Meta.StartTime).String() - - timeNow := time.Now() - timeAfter := timeNow - for _, et := range report.Events { - timeAfter = timeAfter.Add(et.FinishTime.Sub(*et.StartTime)) - } - report.TotalFaultTime = timeAfter.Sub(timeNow).String() - - c.JSON(http.StatusOK, report) -} - -// @Summary Delete the specified archived experiment. -// @Description Delete the specified archived experiment. -// @Tags archives -// @Produce json -// @Param uid path string true "uid" -// @Success 200 {object} StatusResponse -// @Failure 500 {object} utils.APIError -// @Router /archives/{uid} [delete] -func (s *Service) delete(c *gin.Context) { - var ( - err error - exp *core.Experiment - ) - - uid := c.Param("uid") - - if exp, err = s.archive.FindByUID(context.Background(), uid); err != nil { - if gorm.IsRecordNotFoundError(err) { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInvalidRequest.New("the archived experiment is not found")) - } else { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - } - return - } - - if err = s.archive.Delete(context.Background(), exp); err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - } else { - if err = s.event.DeleteByUID(context.Background(), uid); err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - } else { - c.JSON(http.StatusOK, StatusResponse{Status: "success"}) - } - } -} - -// @Summary Delete the specified archived experiment. -// @Description Delete the specified archived experiment. -// @Tags archives -// @Produce json -// @Param uids query string true "uids" -// @Success 200 {object} StatusResponse -// @Failure 500 {object} utils.APIError -// @Router /archives [delete] -func (s *Service) batchDelete(c *gin.Context) { - var ( - err error - uidSlice []string - ) - - uids := c.Query("uids") - if uids == "" { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(fmt.Errorf("uids cannot be empty"))) - return - } - uidSlice = strings.Split(uids, ",") - - if err = s.archive.DeleteByUIDs(context.Background(), uidSlice); err != nil { - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - c.Status(http.StatusInternalServerError) - return - } - if err = s.event.DeleteByUIDs(context.Background(), uidSlice); err != nil { - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - c.Status(http.StatusInternalServerError) - return - } - - c.JSON(http.StatusOK, StatusResponse{Status: "success"}) -} diff --git a/pkg/apiserver/archive/archive_test.go b/pkg/apiserver/archive/archive_test.go deleted file mode 100644 index e934e42941..0000000000 --- a/pkg/apiserver/archive/archive_test.go +++ /dev/null @@ -1,584 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package archive - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "net/http/httptest" - "testing" - "time" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/core" - pkgmock "github.com/chaos-mesh/chaos-mesh/pkg/mock" - - "github.com/gin-gonic/gin" - "github.com/jinzhu/gorm" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/stretchr/testify/mock" -) - -// MockExperimentStore is a mock type for ExperimentStore -type MockExperimentStore struct { - mock.Mock -} - -func TestEvent(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Archive Suite") -} - -func (m *MockExperimentStore) ListMeta(ctx context.Context, kind, namespace, name string, archived bool) ([]*core.ExperimentMeta, error) { - var res []*core.ExperimentMeta - var err error - if kind == "testKind" { - expMeta := &core.ExperimentMeta{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - UID: "testUID", - Kind: "testKind", - Name: "testName", - Namespace: "testNamespace", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - Archived: true, - } - res = append(res, expMeta) - } else { - err = fmt.Errorf("test err") - } - return res, err -} - -func (m *MockExperimentStore) FindByUID(ctx context.Context, UID string) (*core.Experiment, error) { - var res *core.Experiment - var err error - switch UID { - case "testPodChaos": - chaos := v1alpha1.PodChaos{} - jsonStr, _ := json.Marshal(chaos) - res = &core.Experiment{ - ExperimentMeta: core.ExperimentMeta{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - UID: UID, - Kind: v1alpha1.KindPodChaos, - Name: "testName", - Namespace: "testNamespace", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - Archived: true, - }, - Experiment: string(jsonStr), - } - case "testIoChaos": - chaos := v1alpha1.IoChaos{} - jsonStr, _ := json.Marshal(chaos) - res = &core.Experiment{ - ExperimentMeta: core.ExperimentMeta{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - UID: UID, - Kind: v1alpha1.KindIoChaos, - Name: "testName", - Namespace: "testNamespace", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - Archived: true, - }, - Experiment: string(jsonStr), - } - case "testNetworkChaos": - chaos := v1alpha1.NetworkChaos{} - jsonStr, _ := json.Marshal(chaos) - res = &core.Experiment{ - ExperimentMeta: core.ExperimentMeta{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - UID: UID, - Kind: v1alpha1.KindNetworkChaos, - Name: "testName", - Namespace: "testNamespace", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - Archived: true, - }, - Experiment: string(jsonStr), - } - case "testTimeChaos": - chaos := v1alpha1.TimeChaos{} - jsonStr, _ := json.Marshal(chaos) - res = &core.Experiment{ - ExperimentMeta: core.ExperimentMeta{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - UID: UID, - Kind: v1alpha1.KindTimeChaos, - Name: "testName", - Namespace: "testNamespace", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - Archived: true, - }, - Experiment: string(jsonStr), - } - case "testKernelChaos": - chaos := v1alpha1.KernelChaos{} - jsonStr, _ := json.Marshal(chaos) - res = &core.Experiment{ - ExperimentMeta: core.ExperimentMeta{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - UID: UID, - Kind: v1alpha1.KindKernelChaos, - Name: "testName", - Namespace: "testNamespace", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - Archived: true, - }, - Experiment: string(jsonStr), - } - case "testStressChaos": - chaos := v1alpha1.StressChaos{} - jsonStr, _ := json.Marshal(chaos) - res = &core.Experiment{ - ExperimentMeta: core.ExperimentMeta{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - UID: UID, - Kind: v1alpha1.KindStressChaos, - Name: "testName", - Namespace: "testNamespace", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - Archived: true, - }, - Experiment: string(jsonStr), - } - case "testOtherChaos": - res = &core.Experiment{ - ExperimentMeta: core.ExperimentMeta{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - UID: UID, - Kind: "OtherChaos", - Name: "testName", - Namespace: "testNamespace", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - Archived: true, - }, - Experiment: "", - } - case "testErrRecordNotFound": - err = gorm.ErrRecordNotFound - default: - err = fmt.Errorf("test err") - } - return res, err -} - -func (m *MockExperimentStore) FindMetaByUID(ctx context.Context, UID string) (*core.ExperimentMeta, error) { - var res *core.ExperimentMeta - var err error - switch UID { - case "tsetUID": - res = &core.ExperimentMeta{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - UID: "testUID", - Kind: "testKind", - Name: "testName", - Namespace: "testNamespace", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - Archived: true, - } - case "testErrRecordNotFound": - err = gorm.ErrRecordNotFound - default: - err = fmt.Errorf("test err") - } - return res, err -} - -func (m *MockExperimentStore) Set(context.Context, *core.Experiment) error { - panic("implement me") -} - -func (m *MockExperimentStore) Archive(ctx context.Context, namespace, name string) error { - panic("implement me") -} - -func (m *MockExperimentStore) Delete(context.Context, *core.Experiment) error { - panic("implement me") -} - -func (m *MockExperimentStore) DeleteByFinishTime(context.Context, time.Duration) error { - panic("implement me") -} - -func (m *MockExperimentStore) DeleteIncompleteExperiments(context.Context) error { - panic("implement me") -} - -func (m *MockExperimentStore) DeleteByUIDs(context.Context, []string) error { - panic("implement me") -} - -var _ = Describe("event", func() { - var router *gin.Engine - BeforeEach(func() { - pkgmock.With("MockAuthRequired", true) - - mockExpStore := new(MockExperimentStore) - - s := Service{ - archive: mockExpStore, - event: nil, - } - router = gin.Default() - r := router.Group("/api") - endpoint := r.Group("/archives") - - endpoint.GET("", s.list) - endpoint.GET("/detail", s.detail) - endpoint.GET("/report", s.report) - }) - - AfterEach(func() { - // Add any setup steps that needs to be executed after each test - pkgmock.Reset("MockAuthRequired") - }) - - Context("List", func() { - It("success", func() { - response := []Archive{ - Archive{ - UID: "testUID", - Kind: "testKind", - Namespace: "testNamespace", - Name: "testName", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - }, - } - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives?kind=testKind", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusOK)) - responseBody, err := json.Marshal(response) - Expect(err).ShouldNot(HaveOccurred()) - Expect(rr.Body.Bytes()).Should(Equal(responseBody)) - }) - - It("test err", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) - }) - }) - - Context("Detail", func() { - It("empty uid", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives/detail", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusBadRequest)) - }) - - It("testPodChaos", func() { - chaos := &v1alpha1.PodChaos{} - response := Detail{ - Archive: Archive{ - UID: "testPodChaos", - Kind: v1alpha1.KindPodChaos, - Namespace: "testNamespace", - Name: "testName", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - }, - YAML: core.KubeObjectYAMLDescription{ - APIVersion: "", - Kind: "", - Metadata: core.KubeObjectYAMLMetadata{ - Name: "", - Namespace: "", - Labels: nil, - Annotations: nil, - }, - Spec: chaos.Spec, - }, - } - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives/detail?uid=testPodChaos", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusOK)) - responseBody, err := json.Marshal(response) - Expect(err).ShouldNot(HaveOccurred()) - Expect(rr.Body.Bytes()).Should(Equal(responseBody)) - }) - - It("testIoChaos", func() { - chaos := &v1alpha1.IoChaos{} - response := Detail{ - Archive: Archive{ - UID: "testIoChaos", - Kind: v1alpha1.KindIoChaos, - Namespace: "testNamespace", - Name: "testName", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - }, - YAML: core.KubeObjectYAMLDescription{ - APIVersion: "", - Kind: "", - Metadata: core.KubeObjectYAMLMetadata{ - Name: "", - Namespace: "", - Labels: nil, - Annotations: nil, - }, - Spec: chaos.Spec, - }, - } - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives/detail?uid=testIoChaos", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusOK)) - responseBody, err := json.Marshal(response) - Expect(err).ShouldNot(HaveOccurred()) - Expect(rr.Body.Bytes()).Should(Equal(responseBody)) - }) - - It("testNetworkChaos", func() { - chaos := &v1alpha1.NetworkChaos{} - response := Detail{ - Archive: Archive{ - UID: "testNetworkChaos", - Kind: v1alpha1.KindNetworkChaos, - Namespace: "testNamespace", - Name: "testName", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - }, - YAML: core.KubeObjectYAMLDescription{ - APIVersion: "", - Kind: "", - Metadata: core.KubeObjectYAMLMetadata{ - Name: "", - Namespace: "", - Labels: nil, - Annotations: nil, - }, - Spec: chaos.Spec, - }, - } - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives/detail?uid=testNetworkChaos", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusOK)) - responseBody, err := json.Marshal(response) - Expect(err).ShouldNot(HaveOccurred()) - Expect(rr.Body.Bytes()).Should(Equal(responseBody)) - }) - - It("testTimeChaos", func() { - chaos := &v1alpha1.TimeChaos{} - response := Detail{ - Archive: Archive{ - UID: "testTimeChaos", - Kind: v1alpha1.KindTimeChaos, - Namespace: "testNamespace", - Name: "testName", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - }, - YAML: core.KubeObjectYAMLDescription{ - APIVersion: "", - Kind: "", - Metadata: core.KubeObjectYAMLMetadata{ - Name: "", - Namespace: "", - Labels: nil, - Annotations: nil, - }, - Spec: chaos.Spec, - }, - } - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives/detail?uid=testTimeChaos", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusOK)) - responseBody, err := json.Marshal(response) - Expect(err).ShouldNot(HaveOccurred()) - Expect(rr.Body.Bytes()).Should(Equal(responseBody)) - }) - - It("testKernelChaos", func() { - chaos := &v1alpha1.KernelChaos{} - response := Detail{ - Archive: Archive{ - UID: "testKernelChaos", - Kind: v1alpha1.KindKernelChaos, - Namespace: "testNamespace", - Name: "testName", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - }, - YAML: core.KubeObjectYAMLDescription{ - APIVersion: "", - Kind: "", - Metadata: core.KubeObjectYAMLMetadata{ - Name: "", - Namespace: "", - Labels: nil, - Annotations: nil, - }, - Spec: chaos.Spec, - }, - } - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives/detail?uid=testKernelChaos", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusOK)) - responseBody, err := json.Marshal(response) - Expect(err).ShouldNot(HaveOccurred()) - Expect(rr.Body.Bytes()).Should(Equal(responseBody)) - }) - - It("testStressChaos", func() { - chaos := &v1alpha1.StressChaos{} - response := Detail{ - Archive: Archive{ - UID: "testStressChaos", - Kind: v1alpha1.KindStressChaos, - Namespace: "testNamespace", - Name: "testName", - Action: "testAction", - StartTime: time.Time{}, - FinishTime: time.Time{}, - }, - YAML: core.KubeObjectYAMLDescription{ - APIVersion: "", - Kind: "", - Metadata: core.KubeObjectYAMLMetadata{ - Name: "", - Namespace: "", - Labels: nil, - Annotations: nil, - }, - Spec: chaos.Spec, - }, - } - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives/detail?uid=testStressChaos", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusOK)) - responseBody, err := json.Marshal(response) - Expect(err).ShouldNot(HaveOccurred()) - Expect(rr.Body.Bytes()).Should(Equal(responseBody)) - }) - - It("testOtherChaos", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives/detail?uid=testOtherChaos", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) - }) - - It("testErrRecordNotFound", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives/detail?uid=testErrRecordNotFound", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) - }) - - It("test err", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives/detail?uid=testErr", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) - }) - }) - - Context("Report", func() { - It("empty uid", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives/report", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusBadRequest)) - }) - - It("testErrRecordNotFound", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives/report?uid=testErrRecordNotFound", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) - }) - - It("test err", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives/report?uid=testErr", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) - }) - - It("testUID", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/archives/report?uid=testUID", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) - }) - }) -}) diff --git a/pkg/apiserver/common/common.go b/pkg/apiserver/common/common.go deleted file mode 100644 index c192014c51..0000000000 --- a/pkg/apiserver/common/common.go +++ /dev/null @@ -1,442 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package common - -import ( - "context" - "fmt" - "math/rand" - "net/http" - "sort" - "strings" - "time" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/apiserver/utils" - "github.com/chaos-mesh/chaos-mesh/pkg/clientpool" - "github.com/chaos-mesh/chaos-mesh/pkg/config" - "github.com/chaos-mesh/chaos-mesh/pkg/core" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" - - "github.com/gin-gonic/gin" - v1 "k8s.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - roleManager = "manager" - roleViewer = "viewer" - - serviceAccountTemplate = `kind: ServiceAccount -apiVersion: v1 -metadata: - namespace: %s - name: %s -` - roleTemplate = `kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - namespace: %s - name: %s -rules: -- apiGroups: [""] - resources: ["pods", "namespaces"] - verbs: ["get", "watch", "list"] -- apiGroups: - - chaos-mesh.org - resources: [ "*" ] - verbs: [%s] -` - clusterRoleTemplate = `kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: %s -rules: -- apiGroups: [""] - resources: ["pods", "namespaces"] - verbs: ["get", "watch", "list"] -- apiGroups: - - chaos-mesh.org - resources: [ "*" ] - verbs: [%s] -` - roleBindingTemplate = `apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: %s - namespace: %s -subjects: -- kind: ServiceAccount - name: %s - namespace: %s -roleRef: - kind: Role - name: %s - apiGroup: rbac.authorization.k8s.io -` - clusterRoleBindingTemplate = `apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: %s -subjects: -- kind: ServiceAccount - name: %s - namespace: %s -roleRef: - kind: ClusterRole - name: %s - apiGroup: rbac.authorization.k8s.io -` -) - -// Pod defines the basic information of a pod -type Pod struct { - Name string `json:"name"` - IP string `json:"ip"` - Namespace string `json:"namespace"` - State string `json:"state"` -} - -// Service defines a handler service for cluster common objects. -type Service struct { - // this kubeCli use the local token, used for list namespace of the K8s cluster - kubeCli client.Client - conf *config.ChaosDashboardConfig -} - -// NewService returns an experiment service instance. -func NewService( - conf *config.ChaosDashboardConfig, - kubeCli client.Client, -) *Service { - return &Service{ - conf: conf, - kubeCli: kubeCli, - } -} - -// Register mounts our HTTP handler on the mux. -func Register(r *gin.RouterGroup, s *Service) { - endpoint := r.Group("/common") - - endpoint.POST("/pods", s.listPods) - endpoint.GET("/namespaces", s.listNamespaces) - endpoint.GET("/chaos-available-namespaces", s.getChaosAvailableNamespaces) - endpoint.GET("/kinds", s.getKinds) - endpoint.GET("/labels", s.getLabels) - endpoint.GET("/annotations", s.getAnnotations) - endpoint.GET("/config", s.getConfig) - endpoint.GET("/rbac-config", s.getRbacConfig) -} - -// @Summary Get pods from Kubernetes cluster. -// @Description Get pods from Kubernetes cluster. -// @Tags common -// @Produce json -// @Param request body core.SelectorInfo true "Request body" -// @Success 200 {array} Pod -// @Router /common/pods [post] -// @Failure 500 {object} utils.APIError -func (s *Service) listPods(c *gin.Context) { - kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - exp := &core.SelectorInfo{} - if err := c.ShouldBindJSON(exp); err != nil { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - ctx := context.TODO() - filteredPods, err := selector.SelectPods(ctx, kubeCli, nil, exp.ParseSelector(), s.conf.ClusterScoped, s.conf.TargetNamespace, s.conf.EnableFilterNamespace) - if err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - return - } - - pods := make([]Pod, 0, len(filteredPods)) - for _, pod := range filteredPods { - pods = append(pods, Pod{ - Name: pod.Name, - IP: pod.Status.PodIP, - Namespace: pod.Namespace, - State: string(pod.Status.Phase), - }) - } - - c.JSON(http.StatusOK, pods) -} - -// @Summary Get all namespaces from Kubernetes cluster. -// @Description Get all from Kubernetes cluster. -// @Deprecated This API only works within cluster scoped mode. Please use /common/chaos-available-namespaces instead. -// @Tags common -// @Produce json -// @Success 200 {array} string -// @Router /common/namespaces [get] -// @Failure 500 {object} utils.APIError -func (s *Service) listNamespaces(c *gin.Context) { - - var namespaces sort.StringSlice - - var nsList v1.NamespaceList - if err := s.kubeCli.List(context.Background(), &nsList); err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - return - } - namespaces = make(sort.StringSlice, 0, len(nsList.Items)) - for _, ns := range nsList.Items { - namespaces = append(namespaces, ns.Name) - } - - sort.Sort(namespaces) - c.JSON(http.StatusOK, namespaces) -} - -// @Summary Get all namespaces which could inject chaos(explosion scope) from Kubernetes cluster. -// @Description Get all namespaces which could inject chaos(explosion scope) from Kubernetes cluster. -// @Tags common -// @Produce json -// @Success 200 {array} string -// @Router /common/chaos-available-namespaces [get] -// @Failure 500 {object} utils.APIError -func (s *Service) getChaosAvailableNamespaces(c *gin.Context) { - - var namespaces sort.StringSlice - - if s.conf.ClusterScoped { - var nsList v1.NamespaceList - if err := s.kubeCli.List(context.Background(), &nsList); err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - return - } - namespaces = make(sort.StringSlice, 0, len(nsList.Items)) - for _, ns := range nsList.Items { - namespaces = append(namespaces, ns.Name) - } - } else { - namespaces = append(namespaces, s.conf.TargetNamespace) - } - - sort.Sort(namespaces) - c.JSON(http.StatusOK, namespaces) -} - -// @Summary Get all chaos kinds from Kubernetes cluster. -// @Description Get all chaos kinds from Kubernetes cluster. -// @Tags common -// @Produce json -// @Success 200 {array} string -// @Router /common/kinds [get] -// @Failure 500 {object} utils.APIError -func (s *Service) getKinds(c *gin.Context) { - var kinds []string - - allKinds := v1alpha1.AllKinds() - for name := range allKinds { - kinds = append(kinds, name) - } - - sort.Strings(kinds) - c.JSON(http.StatusOK, kinds) -} - -// MapSlice defines a common map -type MapSlice map[string][]string - -// @Summary Get the labels of the pods in the specified namespace from Kubernetes cluster. -// @Description Get the labels of the pods in the specified namespace from Kubernetes cluster. -// @Tags common -// @Produce json -// @Param podNamespaceList query string true "The pod's namespace list, split by ," -// @Success 200 {object} MapSlice -// @Router /common/labels [get] -// @Failure 500 {object} utils.APIError -func (s *Service) getLabels(c *gin.Context) { - - kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - podNamespaceList := c.Query("podNamespaceList") - - if podNamespaceList == "" { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(fmt.Errorf("podNamespaceList cannot be empty"))) - return - } - - exp := &core.SelectorInfo{} - nsList := strings.Split(podNamespaceList, ",") - exp.NamespaceSelectors = nsList - - ctx := context.TODO() - filteredPods, err := selector.SelectPods(ctx, kubeCli, nil, exp.ParseSelector(), s.conf.ClusterScoped, s.conf.TargetNamespace, s.conf.EnableFilterNamespace) - if err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - return - } - - labels := make(map[string][]string) - - for _, pod := range filteredPods { - for k, v := range pod.Labels { - if _, ok := labels[k]; ok { - if !inSlice(v, labels[k]) { - labels[k] = append(labels[k], v) - } - } else { - labels[k] = []string{v} - } - } - } - c.JSON(http.StatusOK, labels) -} - -// @Summary Get the annotations of the pods in the specified namespace from Kubernetes cluster. -// @Description Get the annotations of the pods in the specified namespace from Kubernetes cluster. -// @Tags common -// @Produce json -// @Param podNamespaceList query string true "The pod's namespace list, split by ," -// @Success 200 {object} MapSlice -// @Router /common/annotations [get] -// @Failure 500 {object} utils.APIError -func (s *Service) getAnnotations(c *gin.Context) { - - kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - podNamespaceList := c.Query("podNamespaceList") - - if podNamespaceList == "" { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(fmt.Errorf("podNamespaceList cannot be empty"))) - return - } - - exp := &core.SelectorInfo{} - nsList := strings.Split(podNamespaceList, ",") - exp.NamespaceSelectors = nsList - - ctx := context.TODO() - filteredPods, err := selector.SelectPods(ctx, kubeCli, nil, exp.ParseSelector(), s.conf.ClusterScoped, s.conf.TargetNamespace, s.conf.EnableFilterNamespace) - if err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - return - } - - annotations := make(map[string][]string) - - for _, pod := range filteredPods { - for k, v := range pod.Annotations { - if _, ok := annotations[k]; ok { - if !inSlice(v, annotations[k]) { - annotations[k] = append(annotations[k], v) - } - } else { - annotations[k] = []string{v} - } - } - } - c.JSON(http.StatusOK, annotations) -} - -// @Summary Get the config of Dashboard. -// @Description Get the config of Dashboard. -// @Tags common -// @Produce json -// @Success 200 {object} config.ChaosDashboardConfig -// @Router /common/config [get] -// @Failure 500 {object} utils.APIError -func (s *Service) getConfig(c *gin.Context) { - c.JSON(http.StatusOK, s.conf) -} - -// @Summary Get the rbac config according to the user's choice. -// @Description Get the rbac config according to the user's choice. -// @Tags common -// @Produce json -// @Success 200 {object} MapSlice -// @Router /common/rbac-config [get] -// @Failure 500 {object} utils.APIError -func (s *Service) getRbacConfig(c *gin.Context) { - namespace := c.Query("namespace") - roleType := c.Query("role") - - var serviceAccount, role, roleBinding, verbs string - randomStr := randomStringWithCharset(5, charset) - - scope := namespace - if len(namespace) == 0 { - namespace = "default" - scope = "cluster" - } - if roleType == roleManager { - verbs = `"get", "list", "watch", "create", "delete", "patch", "update"` - } else { - verbs = `"get", "list", "watch"` - } - - serviceAccountName := fmt.Sprintf("account-%s-%s-%s", scope, roleType, randomStr) - roleName := fmt.Sprintf("role-%s-%s-%s", scope, roleType, randomStr) - roleBindingName := fmt.Sprintf("bind-%s-%s-%s", scope, roleType, randomStr) - - serviceAccount = fmt.Sprintf(serviceAccountTemplate, namespace, serviceAccountName) - if scope == "cluster" { - role = fmt.Sprintf(clusterRoleTemplate, roleName, verbs) - roleBinding = fmt.Sprintf(clusterRoleBindingTemplate, roleBindingName, serviceAccountName, namespace, roleName) - } else { - role = fmt.Sprintf(roleTemplate, namespace, roleName, verbs) - roleBinding = fmt.Sprintf(roleBindingTemplate, roleBindingName, namespace, serviceAccountName, namespace, roleName) - } - - rbacMap := make(map[string]string) - rbacMap[serviceAccountName] = serviceAccount + "\n---\n" + role + "\n---\n" + roleBinding - - c.JSON(http.StatusOK, rbacMap) -} - -// inSlice checks given string in string slice or not. -func inSlice(v string, sl []string) bool { - for _, vv := range sl { - if vv == v { - return true - } - } - return false -} - -const charset = "abcdefghijklmnopqrstuvwxyz" - -func randomStringWithCharset(length int, charset string) string { - var seededRand = rand.New(rand.NewSource(time.Now().UnixNano())) - b := make([]byte, length) - for i := range b { - b[i] = charset[seededRand.Intn(len(charset))] - } - return string(b) -} diff --git a/pkg/apiserver/event/event.go b/pkg/apiserver/event/event.go deleted file mode 100644 index 5bd3a04a8e..0000000000 --- a/pkg/apiserver/event/event.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package event - -import ( - "context" - "fmt" - "net/http" - "strconv" - - "github.com/gin-gonic/gin" - "github.com/jinzhu/gorm" - - "github.com/chaos-mesh/chaos-mesh/pkg/apiserver/utils" - "github.com/chaos-mesh/chaos-mesh/pkg/config" - "github.com/chaos-mesh/chaos-mesh/pkg/core" -) - -// Service defines a handler service for events. -type Service struct { - conf *config.ChaosDashboardConfig - archive core.ExperimentStore - event core.EventStore -} - -// NewService return an event service instance. -func NewService( - conf *config.ChaosDashboardConfig, - archive core.ExperimentStore, - event core.EventStore, -) *Service { - return &Service{ - conf: conf, - archive: archive, - event: event, - } -} - -// Register mounts our HTTP handler on the mux. -func Register(r *gin.RouterGroup, s *Service) { - endpoint := r.Group("/events") - endpoint.Use(utils.AuthRequired) - - // TODO: add more api handlers - endpoint.GET("", s.listEvents) - endpoint.GET("/dry", s.listDryEvents) - endpoint.GET("/get", s.getEvent) -} - -// @Summary Get the list of events from db. -// @Description Get the list of events from db. -// @Tags events -// @Produce json -// @Param podName query string false "The pod's name" -// @Param podNamespace query string false "The pod's namespace" -// @Param startTime query string false "The start time of events" -// @Param endTime query string false "The end time of events" -// @Param experimentName query string false "The name of the experiment" -// @Param experimentNamespace query string false "The namespace of the experiment" -// @Param uid query string false "The UID of the experiment" -// @Param kind query string false "kind" Enums(PodChaos, IoChaos, NetworkChaos, TimeChaos, KernelChaos, StressChaos) -// @Param limit query string false "The max length of events list" -// @Success 200 {array} core.Event -// @Router /events [get] -// @Failure 500 {object} utils.APIError -func (s *Service) listEvents(c *gin.Context) { - filter := core.Filter{ - PodName: c.Query("podName"), - PodNamespace: c.Query("podNamespace"), - StartTimeStr: c.Query("startTime"), - FinishTimeStr: c.Query("finishTime"), - ExperimentName: c.Query("experimentName"), - ExperimentNamespace: c.Query("namespace"), - UID: c.Query("uid"), - Kind: c.Query("kind"), - LimitStr: c.Query("limit"), - } - - if filter.PodName != "" && filter.PodNamespace == "" { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(fmt.Errorf("when podName is not empty, podNamespace cannot be empty"))) - return - } - - eventList, err := s.event.ListByFilter(context.Background(), filter) - if err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - return - } - - c.JSON(http.StatusOK, eventList) -} - -// @Summary Get the list of events without pod records from db. -// @Description Get the list of events without pod records from db. -// @Tags events -// @Produce json -// @Param startTime query string false "The start time of events" -// @Param endTime query string false "The end time of events" -// @Param experimentName query string false "The name of the experiment" -// @Param experimentNamespace query string false "The namespace of the experiment" -// @Param kind query string false "kind" Enums(PodChaos, IoChaos, NetworkChaos, TimeChaos, KernelChaos, StressChaos) -// @Param limit query string false "The max length of events list" -// @Success 200 {array} core.Event -// @Router /events/dry [get] -// @Failure 500 {object} utils.APIError -func (s *Service) listDryEvents(c *gin.Context) { - filter := core.Filter{ - StartTimeStr: c.Query("startTime"), - FinishTimeStr: c.Query("finishTime"), - ExperimentName: c.Query("experimentName"), - ExperimentNamespace: c.Query("namespace"), - Kind: c.Query("kind"), - LimitStr: c.Query("limit"), - } - - eventList, err := s.event.DryListByFilter(context.Background(), filter) - if err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - return - } - - c.JSON(http.StatusOK, eventList) -} - -// @Summary Get the event from db by ID. -// @Description Get the event from db by ID. -// @Tags events -// @Produce json -// @Param id query uint true "The id of the event" -// @Success 200 {object} core.Event -// @Router /events/get [get] -// @Failure 500 {object} utils.APIError -func (s *Service) getEvent(c *gin.Context) { - idStr := c.Query("id") - namespace := c.Query("namespace") - - if idStr == "" { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInvalidRequest.New("id cannot be empty")) - return - } - - id, err := strconv.Atoi(idStr) - if err != nil { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInvalidRequest.New("the format of id is wrong")) - return - } - - event, err := s.event.Find(context.Background(), uint(id)) - if err != nil { - if gorm.IsRecordNotFoundError(err) { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInvalidRequest.New("the event is not found")) - } else { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.NewWithNoMessage()) - } - return - } - - if len(namespace) != 0 && event.Namespace != namespace { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInvalidRequest.New("event %s belong to namespace %s but not namespace %s", idStr, event.Namespace, namespace)) - return - } - - c.JSON(http.StatusOK, event) -} diff --git a/pkg/apiserver/event/event_test.go b/pkg/apiserver/event/event_test.go deleted file mode 100644 index f13e786931..0000000000 --- a/pkg/apiserver/event/event_test.go +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package event - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "net/http/httptest" - "testing" - "time" - - "github.com/chaos-mesh/chaos-mesh/pkg/core" - pkgmock "github.com/chaos-mesh/chaos-mesh/pkg/mock" - - "github.com/gin-gonic/gin" - "github.com/jinzhu/gorm" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/stretchr/testify/mock" -) - -// MockEventService is a mock type for event.Service -type MockEventService struct { - mock.Mock -} - -func (m *MockEventService) List(context.Context) ([]*core.Event, error) { - panic("implement me") -} - -func (m *MockEventService) ListByExperiment(context.Context, string, string) ([]*core.Event, error) { - panic("implement me") -} - -func (m *MockEventService) ListByNamespace(context.Context, string) ([]*core.Event, error) { - panic("implement me") -} - -func (m *MockEventService) ListByPod(context.Context, string, string) ([]*core.Event, error) { - panic("implement me") -} - -func (m *MockEventService) ListByUID(context.Context, string) ([]*core.Event, error) { - panic("implement me") -} - -func (m *MockEventService) ListByUIDs(context.Context, []string) ([]*core.Event, error) { - panic("implement me") -} - -func (m *MockEventService) ListByFilter(ctx context.Context, filter core.Filter) ([]*core.Event, error) { - var res []*core.Event - var err error - if filter.UID == "testUID" { - event := &core.Event{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - Experiment: "testExperiment", - Namespace: "testNamespace", - Kind: "testKind", - Message: "test", - StartTime: nil, - FinishTime: nil, - Duration: "1m", - Pods: nil, - ExperimentID: "testUID", - } - res = append(res, event) - } else { - err = fmt.Errorf("test err") - } - return res, err -} - -func (m *MockEventService) DryListByFilter(_ context.Context, filter core.Filter) ([]*core.Event, error) { - var res []*core.Event - var err error - if filter.Kind == "testKind" { - event := &core.Event{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - Experiment: "testExperiment", - Namespace: "testNamespace", - Kind: "testKind", - Message: "test", - StartTime: nil, - FinishTime: nil, - Duration: "1m", - Pods: nil, - ExperimentID: "testUID", - } - res = append(res, event) - } else { - err = fmt.Errorf("test err") - } - return res, err -} - -func (m *MockEventService) Find(_ context.Context, id uint) (*core.Event, error) { - var res *core.Event - var err error - if id == 0 { - res = &core.Event{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - Experiment: "testExperiment", - Namespace: "testNamespace", - Kind: "testKind", - Message: "test", - StartTime: nil, - FinishTime: nil, - Duration: "1m", - Pods: nil, - ExperimentID: "testUID", - } - } else { - if id == 1 { - err = gorm.ErrRecordNotFound - } else { - err = fmt.Errorf("test err") - } - } - return res, err -} - -func (m *MockEventService) FindByExperimentAndStartTime(context.Context, string, string, *time.Time) (*core.Event, error) { - panic("implement me") -} - -func (m *MockEventService) Create(context.Context, *core.Event) error { - panic("implement me") -} - -func (m *MockEventService) Update(context.Context, *core.Event) error { - panic("implement me") -} - -func (m *MockEventService) DeleteIncompleteEvents(context.Context) error { - panic("implement me") -} - -func (m *MockEventService) DeleteByUIDs(context.Context, []string) error { - panic("implement me") -} - -func (m *MockEventService) DeleteByFinishTime(context.Context, time.Duration) error { - panic("implement me") -} - -func (m *MockEventService) DeleteByUID(context.Context, string) error { - panic("implement me") -} - -func (m *MockEventService) UpdateIncompleteEvents(context.Context, string, string) error { - panic("implement me") -} - -func TestEvent(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Event Suite") -} - -var _ = Describe("event", func() { - var router *gin.Engine - BeforeEach(func() { - pkgmock.With("MockAuthRequired", true) - - mockes := new(MockEventService) - - s := Service{ - conf: nil, - archive: nil, - event: mockes, - } - router = gin.Default() - r := router.Group("/api") - endpoint := r.Group("/events") - endpoint.GET("", s.listEvents) - endpoint.GET("/dry", s.listDryEvents) - endpoint.GET("/get", s.getEvent) - }) - - AfterEach(func() { - // Add any teardown steps that needs to be executed after each test - pkgmock.Reset("MockAuthRequired") - }) - - Context("ListEvents", func() { - It("empty podNamespace", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/events?podName=testpodNamespace", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) - }) - - It("success", func() { - response := []*core.Event{ - &core.Event{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - Experiment: "testExperiment", - Namespace: "testNamespace", - Kind: "testKind", - Message: "test", - StartTime: nil, - FinishTime: nil, - Duration: "1m", - Pods: nil, - ExperimentID: "testUID", - }, - } - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/events?uid=testUID", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusOK)) - responseBody, err := json.Marshal(response) - Expect(err).ShouldNot(HaveOccurred()) - Expect(rr.Body.Bytes()).Should(Equal(responseBody)) - }) - - It("test err", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/events?uid=err", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) - }) - }) - - Context("ListDryEvents", func() { - It("success", func() { - response := []*core.Event{ - &core.Event{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - Experiment: "testExperiment", - Namespace: "testNamespace", - Kind: "testKind", - Message: "test", - StartTime: nil, - FinishTime: nil, - Duration: "1m", - Pods: nil, - ExperimentID: "testUID", - }, - } - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/events/dry?kind=testKind", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusOK)) - responseBody, err := json.Marshal(response) - Expect(err).ShouldNot(HaveOccurred()) - Expect(rr.Body.Bytes()).Should(Equal(responseBody)) - }) - - It("test err", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/events/dry?kind=err", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) - }) - }) - - Context("GetEvent", func() { - It("success", func() { - response := &core.Event{ - ID: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: nil, - Experiment: "testExperiment", - Namespace: "testNamespace", - Kind: "testKind", - Message: "test", - StartTime: nil, - FinishTime: nil, - Duration: "1m", - Pods: nil, - ExperimentID: "testUID", - } - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/events/get?id=0", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusOK)) - responseBody, err := json.Marshal(response) - Expect(err).ShouldNot(HaveOccurred()) - Expect(rr.Body.Bytes()).Should(Equal(responseBody)) - }) - - It("empty id", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/events/get", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusBadRequest)) - }) - - It("bad id", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/events/get?id=badID", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusBadRequest)) - }) - - It("not found", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/events/get?id=1", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) - }) - - It("other err", func() { - rr := httptest.NewRecorder() - request, _ := http.NewRequest(http.MethodGet, "/api/events/get?id=2", nil) - router.ServeHTTP(rr, request) - Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) - }) - }) -}) diff --git a/pkg/apiserver/experiment/experiment.go b/pkg/apiserver/experiment/experiment.go deleted file mode 100644 index 6cbcec527a..0000000000 --- a/pkg/apiserver/experiment/experiment.go +++ /dev/null @@ -1,1535 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package experiment - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "strings" - "sync" - "time" - - "github.com/gin-gonic/gin" - "github.com/jinzhu/gorm" - "github.com/mitchellh/mapstructure" - "golang.org/x/sync/errgroup" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/common" - "github.com/chaos-mesh/chaos-mesh/pkg/apiserver/utils" - "github.com/chaos-mesh/chaos-mesh/pkg/clientpool" - "github.com/chaos-mesh/chaos-mesh/pkg/config" - "github.com/chaos-mesh/chaos-mesh/pkg/core" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/util/retry" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/apiutil" -) - -var log = ctrl.Log.WithName("experiment api") - -// ChaosState defines the number of chaos experiments of each phase -type ChaosState struct { - Running int `json:"Running"` - Waiting int `json:"Waiting"` - Paused int `json:"Paused"` - Failed int `json:"Failed"` - Finished int `json:"Finished"` -} - -// Service defines a handler service for experiments. -type Service struct { - archive core.ExperimentStore - event core.EventStore - conf *config.ChaosDashboardConfig - scheme *runtime.Scheme -} - -// NewService returns an experiment service instance. -func NewService( - archive core.ExperimentStore, - event core.EventStore, - conf *config.ChaosDashboardConfig, - scheme *runtime.Scheme, -) *Service { - return &Service{ - archive: archive, - event: event, - conf: conf, - scheme: scheme, - } -} - -// Register mounts HTTP handler on the mux. -func Register(r *gin.RouterGroup, s *Service) { - endpoint := r.Group("/experiments") - - endpoint.GET("", s.listExperiments) - endpoint.POST("/new", s.createExperiment) - endpoint.GET("/detail/:uid", s.getExperimentDetail) - endpoint.DELETE("/:uid", s.deleteExperiment) - endpoint.DELETE("/", s.batchDeleteExperiment) - endpoint.PUT("/update", s.updateExperiment) - endpoint.PUT("/pause/:uid", s.pauseExperiment) - endpoint.PUT("/start/:uid", s.startExperiment) - endpoint.GET("/state", s.state) -} - -// Base represents the base info of an experiment. -type Base struct { - Kind string `json:"kind"` - Namespace string `json:"namespace"` - Name string `json:"name"` -} - -// Experiment defines the basic information of an experiment -type Experiment struct { - Base - UID string `json:"uid"` - Created string `json:"created"` - Status string `json:"status"` - FailedMessage string `json:"failed_message,omitempty"` -} - -// Detail represents an experiment instance. -type Detail struct { - Experiment - YAML core.KubeObjectYAMLDescription `json:"yaml"` -} - -type createExperimentFunc func(*core.ExperimentInfo, client.Client) error -type updateExperimentFunc func(*core.KubeObjectYAMLDescription, client.Client) error - -// StatusResponse defines a common status struct. -type StatusResponse struct { - Status string `json:"status"` -} - -// @Summary Create a new chaos experiment. -// @Description Create a new chaos experiment. -// @Tags experiments -// @Produce json -// @Param request body core.ExperimentInfo true "Request body" -// @Success 200 {object} core.ExperimentInfo -// @Failure 400 {object} utils.APIError -// @Failure 500 {object} utils.APIError -// @Router /experiments/new [post] -func (s *Service) createExperiment(c *gin.Context) { - kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - exp := &core.ExperimentInfo{} - if err := c.ShouldBindJSON(exp); err != nil { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - createFuncs := map[string]createExperimentFunc{ - v1alpha1.KindPodChaos: s.createPodChaos, - v1alpha1.KindNetworkChaos: s.createNetworkChaos, - v1alpha1.KindIoChaos: s.createIOChaos, - v1alpha1.KindStressChaos: s.createStressChaos, - v1alpha1.KindTimeChaos: s.createTimeChaos, - v1alpha1.KindKernelChaos: s.createKernelChaos, - v1alpha1.KindDNSChaos: s.createDNSChaos, - v1alpha1.KindAwsChaos: s.createAwsChaos, - } - - f, ok := createFuncs[exp.Target.Kind] - if !ok { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInvalidRequest.New(exp.Target.Kind + " is not supported")) - return - } - - if err := f(exp, kubeCli); err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - return - } - - c.JSON(http.StatusOK, exp) -} - -func (s *Service) createPodChaos(exp *core.ExperimentInfo, kubeCli client.Client) error { - chaos := &v1alpha1.PodChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: exp.Name, - Namespace: exp.Namespace, - Labels: exp.Labels, - Annotations: exp.Annotations, - }, - Spec: v1alpha1.PodChaosSpec{ - Selector: exp.Scope.ParseSelector(), - Action: v1alpha1.PodChaosAction(exp.Target.PodChaos.Action), - Mode: v1alpha1.PodMode(exp.Scope.Mode), - Value: exp.Scope.Value, - ContainerName: exp.Target.PodChaos.ContainerName, - GracePeriod: exp.Target.PodChaos.GracePeriod, - }, - } - - if exp.Scheduler.Cron != "" { - chaos.Spec.Scheduler = &v1alpha1.SchedulerSpec{Cron: exp.Scheduler.Cron} - } - - if exp.Scheduler.Duration != "" { - chaos.Spec.Duration = &exp.Scheduler.Duration - } - - return kubeCli.Create(context.Background(), chaos) -} - -func (s *Service) createNetworkChaos(exp *core.ExperimentInfo, kubeCli client.Client) error { - chaos := &v1alpha1.NetworkChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: exp.Name, - Namespace: exp.Namespace, - Labels: exp.Labels, - Annotations: exp.Annotations, - }, - Spec: v1alpha1.NetworkChaosSpec{ - Selector: exp.Scope.ParseSelector(), - Action: v1alpha1.NetworkChaosAction(exp.Target.NetworkChaos.Action), - Mode: v1alpha1.PodMode(exp.Scope.Mode), - Value: exp.Scope.Value, - TcParameter: v1alpha1.TcParameter{ - Delay: exp.Target.NetworkChaos.Delay, - Loss: exp.Target.NetworkChaos.Loss, - Duplicate: exp.Target.NetworkChaos.Duplicate, - Corrupt: exp.Target.NetworkChaos.Corrupt, - Bandwidth: exp.Target.NetworkChaos.Bandwidth, - }, - Direction: v1alpha1.Direction(exp.Target.NetworkChaos.Direction), - ExternalTargets: exp.Target.NetworkChaos.ExternalTargets, - }, - } - - if exp.Target.NetworkChaos.TargetScope != nil { - chaos.Spec.Target = &v1alpha1.Target{ - TargetSelector: exp.Target.NetworkChaos.TargetScope.ParseSelector(), - TargetMode: v1alpha1.PodMode(exp.Target.NetworkChaos.TargetScope.Mode), - TargetValue: exp.Target.NetworkChaos.TargetScope.Value, - } - } - - if exp.Scheduler.Cron != "" { - chaos.Spec.Scheduler = &v1alpha1.SchedulerSpec{Cron: exp.Scheduler.Cron} - } - - if exp.Scheduler.Duration != "" { - chaos.Spec.Duration = &exp.Scheduler.Duration - } - - return kubeCli.Create(context.Background(), chaos) -} - -func (s *Service) createIOChaos(exp *core.ExperimentInfo, kubeCli client.Client) error { - chaos := &v1alpha1.IoChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: exp.Name, - Namespace: exp.Namespace, - Labels: exp.Labels, - Annotations: exp.Annotations, - }, - Spec: v1alpha1.IoChaosSpec{ - Selector: exp.Scope.ParseSelector(), - Mode: v1alpha1.PodMode(exp.Scope.Mode), - Value: exp.Scope.Value, - Action: v1alpha1.IoChaosType(exp.Target.IOChaos.Action), - Delay: exp.Target.IOChaos.Delay, - Errno: exp.Target.IOChaos.Errno, - Attr: exp.Target.IOChaos.Attr, - Mistake: exp.Target.IOChaos.Mistake, - Path: exp.Target.IOChaos.Path, - Methods: exp.Target.IOChaos.Methods, - Percent: exp.Target.IOChaos.Percent, - VolumePath: exp.Target.IOChaos.VolumePath, - ContainerName: &exp.Target.IOChaos.ContainerName, - }, - } - - if exp.Scheduler.Cron != "" { - chaos.Spec.Scheduler = &v1alpha1.SchedulerSpec{Cron: exp.Scheduler.Cron} - } - - if exp.Scheduler.Duration != "" { - chaos.Spec.Duration = &exp.Scheduler.Duration - } - - return kubeCli.Create(context.Background(), chaos) -} - -func (s *Service) createTimeChaos(exp *core.ExperimentInfo, kubeCli client.Client) error { - chaos := &v1alpha1.TimeChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: exp.Name, - Namespace: exp.Namespace, - Labels: exp.Labels, - Annotations: exp.Annotations, - }, - Spec: v1alpha1.TimeChaosSpec{ - Selector: exp.Scope.ParseSelector(), - Mode: v1alpha1.PodMode(exp.Scope.Mode), - Value: exp.Scope.Value, - TimeOffset: exp.Target.TimeChaos.TimeOffset, - ClockIds: exp.Target.TimeChaos.ClockIDs, - ContainerNames: exp.Target.TimeChaos.ContainerNames, - }, - } - - if exp.Scheduler.Cron != "" { - chaos.Spec.Scheduler = &v1alpha1.SchedulerSpec{Cron: exp.Scheduler.Cron} - } - - if exp.Scheduler.Duration != "" { - chaos.Spec.Duration = &exp.Scheduler.Duration - } - - return kubeCli.Create(context.Background(), chaos) -} - -func (s *Service) createKernelChaos(exp *core.ExperimentInfo, kubeCli client.Client) error { - chaos := &v1alpha1.KernelChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: exp.Name, - Namespace: exp.Namespace, - Labels: exp.Labels, - Annotations: exp.Annotations, - }, - Spec: v1alpha1.KernelChaosSpec{ - Selector: exp.Scope.ParseSelector(), - Mode: v1alpha1.PodMode(exp.Scope.Mode), - Value: exp.Scope.Value, - FailKernRequest: exp.Target.KernelChaos.FailKernRequest, - }, - } - - if exp.Scheduler.Cron != "" { - chaos.Spec.Scheduler = &v1alpha1.SchedulerSpec{Cron: exp.Scheduler.Cron} - } - - if exp.Scheduler.Duration != "" { - chaos.Spec.Duration = &exp.Scheduler.Duration - } - - return kubeCli.Create(context.Background(), chaos) -} - -func (s *Service) createStressChaos(exp *core.ExperimentInfo, kubeCli client.Client) error { - var stressors *v1alpha1.Stressors - - // Error checking - if exp.Target.StressChaos.Stressors.CPUStressor.Workers <= 0 && exp.Target.StressChaos.Stressors.MemoryStressor.Workers > 0 { - stressors = &v1alpha1.Stressors{ - MemoryStressor: exp.Target.StressChaos.Stressors.MemoryStressor, - } - } else if exp.Target.StressChaos.Stressors.MemoryStressor.Workers <= 0 && exp.Target.StressChaos.Stressors.CPUStressor.Workers > 0 { - stressors = &v1alpha1.Stressors{ - CPUStressor: exp.Target.StressChaos.Stressors.CPUStressor, - } - } else { - stressors = exp.Target.StressChaos.Stressors - } - - chaos := &v1alpha1.StressChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: exp.Name, - Namespace: exp.Namespace, - Labels: exp.Labels, - Annotations: exp.Annotations, - }, - Spec: v1alpha1.StressChaosSpec{ - Selector: exp.Scope.ParseSelector(), - Mode: v1alpha1.PodMode(exp.Scope.Mode), - Value: exp.Scope.Value, - Stressors: stressors, - StressngStressors: exp.Target.StressChaos.StressngStressors, - }, - } - - if exp.Scheduler.Cron != "" { - chaos.Spec.Scheduler = &v1alpha1.SchedulerSpec{Cron: exp.Scheduler.Cron} - } - - if exp.Scheduler.Duration != "" { - chaos.Spec.Duration = &exp.Scheduler.Duration - } - - if exp.Target.StressChaos.ContainerName != nil { - chaos.Spec.ContainerName = exp.Target.StressChaos.ContainerName - } - - return kubeCli.Create(context.Background(), chaos) -} - -func (s *Service) createDNSChaos(exp *core.ExperimentInfo, kubeCli client.Client) error { - chaos := &v1alpha1.DNSChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: exp.Name, - Namespace: exp.Namespace, - Labels: exp.Labels, - Annotations: exp.Annotations, - }, - Spec: v1alpha1.DNSChaosSpec{ - Selector: exp.Scope.ParseSelector(), - Mode: v1alpha1.PodMode(exp.Scope.Mode), - Value: exp.Scope.Value, - Action: v1alpha1.DNSChaosAction(exp.Target.DNSChaos.Action), - DomainNamePatterns: exp.Target.DNSChaos.DomainNamePatterns, - }, - } - - if exp.Scheduler.Cron != "" { - chaos.Spec.Scheduler = &v1alpha1.SchedulerSpec{Cron: exp.Scheduler.Cron} - } - - if exp.Scheduler.Duration != "" { - chaos.Spec.Duration = &exp.Scheduler.Duration - } - - return kubeCli.Create(context.Background(), chaos) -} - -func (s *Service) createAwsChaos(exp *core.ExperimentInfo, kubeCli client.Client) error { - chaos := &v1alpha1.AwsChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: exp.Name, - Namespace: exp.Namespace, - Labels: exp.Labels, - Annotations: exp.Annotations, - }, - Spec: v1alpha1.AwsChaosSpec{ - Action: v1alpha1.AwsChaosAction(exp.Target.AwsChaos.Action), - SecretName: exp.Target.AwsChaos.SecretName, - AwsRegion: exp.Target.AwsChaos.AwsRegion, - Ec2Instance: exp.Target.AwsChaos.Ec2Instance, - EbsVolume: exp.Target.AwsChaos.EbsVolume, - DeviceName: exp.Target.AwsChaos.DeviceName, - }, - } - - if exp.Scheduler.Cron != "" { - chaos.Spec.Scheduler = &v1alpha1.SchedulerSpec{Cron: exp.Scheduler.Cron} - } - - if exp.Scheduler.Duration != "" { - chaos.Spec.Duration = &exp.Scheduler.Duration - } - - return kubeCli.Create(context.Background(), chaos) -} - -func (s *Service) getPodChaosDetail(namespace string, name string, kubeCli client.Client) (Detail, error) { - chaos := &v1alpha1.PodChaos{} - - chaosKey := types.NamespacedName{Namespace: namespace, Name: name} - if err := kubeCli.Get(context.Background(), chaosKey, chaos); err != nil { - if apierrors.IsNotFound(err) { - return Detail{}, utils.ErrNotFound.NewWithNoMessage() - } - - return Detail{}, err - } - - gvk, err := apiutil.GVKForObject(chaos, s.scheme) - if err != nil { - return Detail{}, err - } - - return Detail{ - Experiment: Experiment{ - Base: Base{ - Kind: gvk.Kind, - Namespace: chaos.Namespace, - Name: chaos.Name, - }, - UID: chaos.GetChaos().UID, - Created: chaos.GetChaos().StartTime.Format(time.RFC3339), - Status: chaos.GetChaos().Status, - FailedMessage: chaos.GetStatus().FailedMessage, - }, - YAML: core.KubeObjectYAMLDescription{ - APIVersion: gvk.GroupVersion().String(), - Kind: gvk.Kind, - Metadata: core.KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, - }, nil -} - -func (s *Service) getIoChaosDetail(namespace string, name string, kubeCli client.Client) (Detail, error) { - chaos := &v1alpha1.IoChaos{} - - chaosKey := types.NamespacedName{Namespace: namespace, Name: name} - if err := kubeCli.Get(context.Background(), chaosKey, chaos); err != nil { - if apierrors.IsNotFound(err) { - return Detail{}, utils.ErrNotFound.NewWithNoMessage() - } - - return Detail{}, err - } - - gvk, err := apiutil.GVKForObject(chaos, s.scheme) - if err != nil { - return Detail{}, err - } - - return Detail{ - Experiment: Experiment{ - Base: Base{ - Kind: gvk.Kind, - Namespace: chaos.Namespace, - Name: chaos.Name, - }, - UID: chaos.GetChaos().UID, - Created: chaos.GetChaos().StartTime.Format(time.RFC3339), - Status: chaos.GetChaos().Status, - FailedMessage: chaos.GetStatus().FailedMessage, - }, - YAML: core.KubeObjectYAMLDescription{ - APIVersion: gvk.GroupVersion().String(), - Kind: gvk.Kind, - Metadata: core.KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, - }, nil -} - -func (s *Service) getNetworkChaosDetail(namespace string, name string, kubeCli client.Client) (Detail, error) { - chaos := &v1alpha1.NetworkChaos{} - - chaosKey := types.NamespacedName{Namespace: namespace, Name: name} - if err := kubeCli.Get(context.Background(), chaosKey, chaos); err != nil { - if apierrors.IsNotFound(err) { - return Detail{}, utils.ErrNotFound.NewWithNoMessage() - } - - return Detail{}, err - } - - gvk, err := apiutil.GVKForObject(chaos, s.scheme) - if err != nil { - return Detail{}, err - } - - return Detail{ - Experiment: Experiment{ - Base: Base{ - Kind: gvk.Kind, - Namespace: chaos.Namespace, - Name: chaos.Name, - }, - UID: chaos.GetChaos().UID, - Created: chaos.GetChaos().StartTime.Format(time.RFC3339), - Status: chaos.GetChaos().Status, - FailedMessage: chaos.GetStatus().FailedMessage, - }, - YAML: core.KubeObjectYAMLDescription{ - APIVersion: gvk.GroupVersion().String(), - Kind: gvk.Kind, - Metadata: core.KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, - }, nil -} - -func (s *Service) getTimeChaosDetail(namespace string, name string, kubeCli client.Client) (Detail, error) { - chaos := &v1alpha1.TimeChaos{} - - chaosKey := types.NamespacedName{Namespace: namespace, Name: name} - if err := kubeCli.Get(context.Background(), chaosKey, chaos); err != nil { - if apierrors.IsNotFound(err) { - return Detail{}, utils.ErrNotFound.NewWithNoMessage() - } - - return Detail{}, err - } - - gvk, err := apiutil.GVKForObject(chaos, s.scheme) - if err != nil { - return Detail{}, err - } - - return Detail{ - Experiment: Experiment{ - Base: Base{ - Kind: gvk.Kind, - Namespace: chaos.Namespace, - Name: chaos.Name, - }, - Created: chaos.GetChaos().StartTime.Format(time.RFC3339), - Status: chaos.GetChaos().Status, - UID: chaos.GetChaos().UID, - FailedMessage: chaos.GetStatus().FailedMessage, - }, - YAML: core.KubeObjectYAMLDescription{ - APIVersion: gvk.GroupVersion().String(), - Kind: gvk.Kind, - Metadata: core.KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, - }, nil -} - -func (s *Service) getKernelChaosDetail(namespace string, name string, kubeCli client.Client) (Detail, error) { - chaos := &v1alpha1.KernelChaos{} - - chaosKey := types.NamespacedName{Namespace: namespace, Name: name} - if err := kubeCli.Get(context.Background(), chaosKey, chaos); err != nil { - if apierrors.IsNotFound(err) { - return Detail{}, utils.ErrNotFound.NewWithNoMessage() - } - - return Detail{}, err - } - - gvk, err := apiutil.GVKForObject(chaos, s.scheme) - if err != nil { - return Detail{}, err - } - - return Detail{ - Experiment: Experiment{ - Base: Base{ - Kind: gvk.Kind, - Namespace: chaos.Namespace, - Name: chaos.Name, - }, - Created: chaos.GetChaos().StartTime.Format(time.RFC3339), - Status: chaos.GetChaos().Status, - UID: chaos.GetChaos().UID, - FailedMessage: chaos.GetStatus().FailedMessage, - }, - YAML: core.KubeObjectYAMLDescription{ - APIVersion: gvk.GroupVersion().String(), - Kind: gvk.Kind, - Metadata: core.KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, - }, nil -} - -func (s *Service) getStressChaosDetail(namespace string, name string, kubeCli client.Client) (Detail, error) { - chaos := &v1alpha1.StressChaos{} - - chaosKey := types.NamespacedName{Namespace: namespace, Name: name} - if err := kubeCli.Get(context.Background(), chaosKey, chaos); err != nil { - if apierrors.IsNotFound(err) { - return Detail{}, utils.ErrNotFound.NewWithNoMessage() - } - - return Detail{}, err - } - - gvk, err := apiutil.GVKForObject(chaos, s.scheme) - if err != nil { - return Detail{}, err - } - - return Detail{ - Experiment: Experiment{ - Base: Base{ - Kind: gvk.Kind, - Namespace: chaos.Namespace, - Name: chaos.Name, - }, - Created: chaos.GetChaos().StartTime.Format(time.RFC3339), - Status: chaos.GetChaos().Status, - UID: chaos.GetChaos().UID, - FailedMessage: chaos.GetStatus().FailedMessage, - }, - YAML: core.KubeObjectYAMLDescription{ - APIVersion: gvk.GroupVersion().String(), - Kind: gvk.Kind, - Metadata: core.KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, - }, nil -} - -func (s *Service) getDNSChaosDetail(namespace string, name string, kubeCli client.Client) (Detail, error) { - chaos := &v1alpha1.DNSChaos{} - - chaosKey := types.NamespacedName{Namespace: namespace, Name: name} - if err := kubeCli.Get(context.Background(), chaosKey, chaos); err != nil { - if apierrors.IsNotFound(err) { - return Detail{}, utils.ErrNotFound.NewWithNoMessage() - } - - return Detail{}, err - } - - gvk, err := apiutil.GVKForObject(chaos, s.scheme) - if err != nil { - return Detail{}, err - } - - return Detail{ - Experiment: Experiment{ - Base: Base{ - Kind: gvk.Kind, - Namespace: chaos.Namespace, - Name: chaos.Name, - }, - Created: chaos.GetChaos().StartTime.Format(time.RFC3339), - Status: chaos.GetChaos().Status, - UID: chaos.GetChaos().UID, - FailedMessage: chaos.GetStatus().FailedMessage, - }, - YAML: core.KubeObjectYAMLDescription{ - APIVersion: gvk.GroupVersion().String(), - Kind: gvk.Kind, - Metadata: core.KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, - }, nil -} - -func (s *Service) getAwsChaosDetail(namespace string, name string, kubeCli client.Client) (Detail, error) { - chaos := &v1alpha1.AwsChaos{} - - chaosKey := types.NamespacedName{Namespace: namespace, Name: name} - if err := kubeCli.Get(context.Background(), chaosKey, chaos); err != nil { - if apierrors.IsNotFound(err) { - return Detail{}, utils.ErrNotFound.NewWithNoMessage() - } - - return Detail{}, err - } - - gvk, err := apiutil.GVKForObject(chaos, s.scheme) - if err != nil { - return Detail{}, err - } - - return Detail{ - Experiment: Experiment{ - Base: Base{ - Kind: gvk.Kind, - Namespace: chaos.Namespace, - Name: chaos.Name, - }, - Created: chaos.GetChaos().StartTime.Format(time.RFC3339), - Status: chaos.GetChaos().Status, - UID: chaos.GetChaos().UID, - FailedMessage: chaos.GetStatus().FailedMessage, - }, - YAML: core.KubeObjectYAMLDescription{ - APIVersion: gvk.GroupVersion().String(), - Kind: gvk.Kind, - Metadata: core.KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, - }, nil -} - -// @Summary Get chaos experiments from Kubernetes cluster. -// @Description Get chaos experiments from Kubernetes cluster. -// @Tags experiments -// @Produce json -// @Param namespace query string false "namespace" -// @Param name query string false "name" -// @Param kind query string false "kind" Enums(PodChaos, IoChaos, NetworkChaos, TimeChaos, KernelChaos, StressChaos) -// @Param status query string false "status" Enums(Running, Paused, Failed, Finished) -// @Success 200 {array} Experiment -// @Router /experiments [get] -// @Failure 500 {object} utils.APIError -func (s *Service) listExperiments(c *gin.Context) { - kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - kind := c.Query("kind") - name := c.Query("name") - ns := c.Query("namespace") - status := c.Query("status") - - if !s.conf.ClusterScoped { - log.Info("Overwrite namespace within namespace scoped mode", "origin", ns, "new", s.conf.TargetNamespace) - ns = s.conf.TargetNamespace - } - - exps := make([]*Experiment, 0) - for key, list := range v1alpha1.AllKinds() { - if kind != "" && key != kind { - continue - } - if err := kubeCli.List(context.Background(), list.ChaosList, &client.ListOptions{Namespace: ns}); err != nil { - c.Status(http.StatusInternalServerError) - utils.SetErrorForGinCtx(c, err) - return - } - for _, chaos := range list.ListChaos() { - if name != "" && chaos.Name != name { - continue - } - if status != "" && chaos.Status != status { - continue - } - exps = append(exps, &Experiment{ - Base: Base{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Kind: chaos.Kind, - }, - Created: chaos.StartTime.Format(time.RFC3339), - Status: chaos.Status, - UID: chaos.UID, - }) - } - } - - c.JSON(http.StatusOK, exps) -} - -// @Summary Get detailed information about the specified chaos experiment. -// @Description Get detailed information about the specified chaos experiment. -// @Tags experiments -// @Produce json -// @Param uid path string true "uid" -// @Router /experiments/detail/{uid} [GET] -// @Success 200 {object} Detail -// @Failure 400 {object} utils.APIError -// @Failure 500 {object} utils.APIError -func (s *Service) getExperimentDetail(c *gin.Context) { - var ( - exp *core.Experiment - expDetail Detail - ) - - kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - uid := c.Param("uid") - if exp, err = s.archive.FindByUID(context.Background(), uid); err != nil { - if gorm.IsRecordNotFoundError(err) { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInvalidRequest.New("the experiment is not found")) - } else { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.NewWithNoMessage()) - } - return - } - - kind := exp.Kind - ns := exp.Namespace - name := exp.Name - - switch kind { - case v1alpha1.KindPodChaos: - expDetail, err = s.getPodChaosDetail(ns, name, kubeCli) - case v1alpha1.KindIoChaos: - expDetail, err = s.getIoChaosDetail(ns, name, kubeCli) - case v1alpha1.KindNetworkChaos: - expDetail, err = s.getNetworkChaosDetail(ns, name, kubeCli) - case v1alpha1.KindTimeChaos: - expDetail, err = s.getTimeChaosDetail(ns, name, kubeCli) - case v1alpha1.KindKernelChaos: - expDetail, err = s.getKernelChaosDetail(ns, name, kubeCli) - case v1alpha1.KindStressChaos: - expDetail, err = s.getStressChaosDetail(ns, name, kubeCli) - case v1alpha1.KindDNSChaos: - expDetail, err = s.getDNSChaosDetail(ns, name, kubeCli) - case v1alpha1.KindAwsChaos: - expDetail, err = s.getAwsChaosDetail(ns, name, kubeCli) - } - if err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - return - } - - c.JSON(http.StatusOK, expDetail) -} - -// @Summary Delete the specified chaos experiment. -// @Description Delete the specified chaos experiment. -// @Tags experiments -// @Produce json -// @Param uid path string true "uid" -// @Param force query string true "force" Enums(true, false) -// @Success 200 {object} StatusResponse -// @Failure 400 {object} utils.APIError -// @Failure 404 {object} utils.APIError -// @Failure 500 {object} utils.APIError -// @Router /experiments/{uid} [delete] -func (s *Service) deleteExperiment(c *gin.Context) { - var ( - chaosKind *v1alpha1.ChaosKind - ok bool - exp *core.Experiment - ) - - kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - uid := c.Param("uid") - if exp, err = s.archive.FindByUID(context.Background(), uid); err != nil { - if gorm.IsRecordNotFoundError(err) { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInvalidRequest.New("the experiment is not found")) - } else { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.NewWithNoMessage()) - } - return - } - - kind := exp.Kind - ns := exp.Namespace - name := exp.Name - force := c.DefaultQuery("force", "false") - - ctx := context.TODO() - chaosKey := types.NamespacedName{Namespace: ns, Name: name} - - if chaosKind, ok = v1alpha1.AllKinds()[kind]; !ok { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInvalidRequest.New(kind + " is not supported")) - return - } - if err := kubeCli.Get(ctx, chaosKey, chaosKind.Chaos); err != nil { - if apierrors.IsNotFound(err) { - c.Status(http.StatusNotFound) - _ = c.Error(utils.ErrNotFound.NewWithNoMessage()) - } else { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - } - return - } - - if force == "true" { - err = retry.RetryOnConflict(retry.DefaultRetry, func() error { - return setAnnotation(kubeCli, kind, ns, name) - }) - if err != nil { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(fmt.Errorf("forced deletion of chaos failed, because update chaos annotation error"))) - return - } - } - - if err := kubeCli.Delete(ctx, chaosKind.Chaos, &client.DeleteOptions{}); err != nil { - if apierrors.IsNotFound(err) { - c.Status(http.StatusNotFound) - _ = c.Error(utils.ErrNotFound.NewWithNoMessage()) - } else { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - } - return - } - - c.JSON(http.StatusOK, StatusResponse{Status: "success"}) -} - -// @Summary Delete the specified chaos experiment. -// @Description Delete the specified chaos experiment. -// @Tags experiments -// @Produce json -// @Param uids query string true "uids" -// @Param force query string true "force" Enums(true, false) -// @Success 200 {object} StatusResponse -// @Failure 400 {object} utils.APIError -// @Failure 404 {object} utils.APIError -// @Failure 500 {object} utils.APIError -// @Router /experiments [delete] -func (s *Service) batchDeleteExperiment(c *gin.Context) { - var ( - chaosKind *v1alpha1.ChaosKind - ok bool - exp *core.Experiment - errFlag bool - uidSlice []string - ) - - kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - uids := c.Query("uids") - if uids == "" { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(fmt.Errorf("uids cannot be empty"))) - return - } - force := c.DefaultQuery("force", "false") - uidSlice = strings.Split(uids, ",") - errFlag = false - - for _, uid := range uidSlice { - if exp, err = s.archive.FindByUID(context.Background(), uid); err != nil { - if gorm.IsRecordNotFoundError(err) { - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(fmt.Errorf("delete experiment uid (%s) error, because the experiment is not found", uid))) - } else { - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(fmt.Errorf("delete experiment uid (%s) error, because %s", uid, err.Error()))) - } - errFlag = true - continue - } - - kind := exp.Kind - ns := exp.Namespace - name := exp.Name - - ctx := context.TODO() - chaosKey := types.NamespacedName{Namespace: ns, Name: name} - - if chaosKind, ok = v1alpha1.AllKinds()[kind]; !ok { - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(fmt.Errorf("delete experiment uid (%s) error, because kind (%s) is not supported", uid, kind))) - errFlag = true - continue - } - if err := kubeCli.Get(ctx, chaosKey, chaosKind.Chaos); err != nil { - if apierrors.IsNotFound(err) { - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(fmt.Errorf("delete experiment uid (%s) error, because the chaos is not found", uid))) - } else { - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(fmt.Errorf("delete experiment uid (%s) error, because %s", uid, err.Error()))) - } - errFlag = true - continue - } - - if force == "true" { - err = retry.RetryOnConflict(retry.DefaultRetry, func() error { - return setAnnotation(kubeCli, kind, ns, name) - }) - if err != nil { - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(fmt.Errorf("forced delete experiment uid (%s) error, because update chaos annotation error", uid))) - errFlag = true - continue - } - } - - if err := kubeCli.Delete(ctx, chaosKind.Chaos, &client.DeleteOptions{}); err != nil { - if apierrors.IsNotFound(err) { - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(fmt.Errorf("delete experiment uid (%s) error, because the chaos is not found", uid))) - } else { - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(fmt.Errorf("delete experiment uid (%s) error, because %s", uid, err.Error()))) - } - errFlag = true - continue - } - } - if errFlag == true { - c.Status(http.StatusInternalServerError) - } else { - c.JSON(http.StatusOK, StatusResponse{Status: "success"}) - } -} - -// @Summary Get chaos experiments state from Kubernetes cluster. -// @Description Get chaos experiments state from Kubernetes cluster. -// @Tags experiments -// @Produce json -// @Param namespace query string false "namespace" -// @Success 200 {object} ChaosState -// @Router /experiments/state [get] -// @Failure 500 {object} utils.APIError -func (s *Service) state(c *gin.Context) { - kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - namespace := c.Query("namespace") - - states := new(ChaosState) - - g, ctx := errgroup.WithContext(context.Background()) - m := &sync.Mutex{} - kinds := v1alpha1.AllKinds() - - var listOptions []client.ListOption - if !s.conf.ClusterScoped { - listOptions = append(listOptions, &client.ListOptions{Namespace: s.conf.TargetNamespace}) - } else if len(namespace) != 0 { - listOptions = append(listOptions, &client.ListOptions{Namespace: namespace}) - } - - for index := range kinds { - list := kinds[index] - g.Go(func() error { - if err := kubeCli.List(ctx, list.ChaosList, listOptions...); err != nil { - return err - } - m.Lock() - for _, chaos := range list.ListChaos() { - switch chaos.Status { - case string(v1alpha1.ExperimentPhaseRunning): - states.Running++ - case string(v1alpha1.ExperimentPhaseWaiting): - states.Waiting++ - case string(v1alpha1.ExperimentPhasePaused): - states.Paused++ - case string(v1alpha1.ExperimentPhaseFailed): - states.Failed++ - case string(v1alpha1.ExperimentPhaseFinished): - states.Finished++ - } - } - m.Unlock() - return nil - }) - } - if err := g.Wait(); err != nil { - c.Status(http.StatusInternalServerError) - utils.SetErrorForGinCtx(c, err) - return - } - - c.JSON(http.StatusOK, states) -} - -// @Summary Pause a chaos experiment. -// @Description Pause a chaos experiment. -// @Tags experiments -// @Produce json -// @Param uid path string true "uid" -// @Success 200 {object} StatusResponse -// @Failure 400 {object} utils.APIError -// @Failure 404 {object} utils.APIError -// @Failure 500 {object} utils.APIError -// @Router /experiments/pause/{uid} [put] -func (s *Service) pauseExperiment(c *gin.Context) { - var experiment *core.Experiment - - kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - uid := c.Param("uid") - if experiment, err = s.archive.FindByUID(context.Background(), uid); err != nil { - if gorm.IsRecordNotFoundError(err) { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInvalidRequest.New("the experiment is not found")) - } else { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.NewWithNoMessage()) - } - return - } - - exp := &Base{ - Kind: experiment.Kind, - Name: experiment.Name, - Namespace: experiment.Namespace, - } - - annotations := map[string]string{ - v1alpha1.PauseAnnotationKey: "true", - } - if err := s.patchExperiment(exp, annotations, kubeCli); err != nil { - if apierrors.IsNotFound(err) { - c.Status(http.StatusNotFound) - _ = c.Error(utils.ErrNotFound.WrapWithNoMessage(err)) - return - } - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - return - } - - c.JSON(http.StatusOK, StatusResponse{Status: "success"}) -} - -// @Summary Start a chaos experiment. -// @Description Start a chaos experiment. -// @Tags experiments -// @Produce json -// @Param uid path string true "uid" -// @Success 200 {object} StatusResponse -// @Failure 400 {object} utils.APIError -// @Failure 404 {object} utils.APIError -// @Failure 500 {object} utils.APIError -// @Router /experiments/start/{uid} [put] -func (s *Service) startExperiment(c *gin.Context) { - var experiment *core.Experiment - - kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - uid := c.Param("uid") - if experiment, err = s.archive.FindByUID(context.Background(), uid); err != nil { - if gorm.IsRecordNotFoundError(err) { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInvalidRequest.New("the experiment is not found")) - } else { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.NewWithNoMessage()) - } - return - } - - exp := &Base{ - Kind: experiment.Kind, - Name: experiment.Name, - Namespace: experiment.Namespace, - } - - annotations := map[string]string{ - v1alpha1.PauseAnnotationKey: "false", - } - - if err := s.patchExperiment(exp, annotations, kubeCli); err != nil { - if apierrors.IsNotFound(err) { - c.Status(http.StatusNotFound) - _ = c.Error(utils.ErrNotFound.WrapWithNoMessage(err)) - return - } - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - return - } - - c.JSON(http.StatusOK, StatusResponse{Status: "success"}) -} - -func (s *Service) patchExperiment(exp *Base, annotations map[string]string, kubeCli client.Client) error { - var ( - chaosKind *v1alpha1.ChaosKind - ok bool - ) - - if chaosKind, ok = v1alpha1.AllKinds()[exp.Kind]; !ok { - return fmt.Errorf("%s is not supported", exp.Kind) - } - - key := types.NamespacedName{Namespace: exp.Namespace, Name: exp.Name} - if err := kubeCli.Get(context.Background(), key, chaosKind.Chaos); err != nil { - return err - } - - var mergePatch []byte - mergePatch, _ = json.Marshal(map[string]interface{}{ - "metadata": map[string]interface{}{ - "annotations": annotations, - }, - }) - - return kubeCli.Patch(context.Background(), - chaosKind.Chaos, - client.ConstantPatch(types.MergePatchType, mergePatch)) -} - -// @Summary Update a chaos experiment. -// @Description Update a chaos experiment. -// @Tags experiments -// @Produce json -// @Param request body core.KubeObjectYAMLDescription true "Request body" -// @Success 200 {object} core.KubeObjectYAMLDescription -// @Failure 400 {object} utils.APIError -// @Failure 500 {object} utils.APIError -// @Router /experiments/update [put] -func (s *Service) updateExperiment(c *gin.Context) { - kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - exp := &core.KubeObjectYAMLDescription{} - if err := c.ShouldBindJSON(exp); err != nil { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - updateFuncs := map[string]updateExperimentFunc{ - v1alpha1.KindPodChaos: s.updatePodChaos, - v1alpha1.KindNetworkChaos: s.updateNetworkChaos, - v1alpha1.KindIoChaos: s.updateIOChaos, - v1alpha1.KindStressChaos: s.updateStressChaos, - v1alpha1.KindTimeChaos: s.updateTimeChaos, - v1alpha1.KindKernelChaos: s.updateKernelChaos, - v1alpha1.KindDNSChaos: s.updateDNSChaos, - v1alpha1.KindAwsChaos: s.updateAwsChaos, - } - - f, ok := updateFuncs[exp.Kind] - if !ok { - c.Status(http.StatusBadRequest) - _ = c.Error(utils.ErrInvalidRequest.New(exp.Kind + " is not supported")) - return - } - err = retry.RetryOnConflict(retry.DefaultRetry, func() error { - return f(exp, kubeCli) - }) - if err != nil { - if apierrors.IsNotFound(err) { - c.Status(http.StatusNotFound) - _ = c.Error(utils.ErrNotFound.WrapWithNoMessage(err)) - } else { - c.Status(http.StatusInternalServerError) - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - } - return - } - c.JSON(http.StatusOK, exp) -} - -func (s *Service) updatePodChaos(exp *core.KubeObjectYAMLDescription, kubeCli client.Client) error { - chaos := &v1alpha1.PodChaos{} - meta := &exp.Metadata - key := types.NamespacedName{Namespace: meta.Namespace, Name: meta.Name} - - if err := kubeCli.Get(context.Background(), key, chaos); err != nil { - return err - } - - chaos.SetLabels(meta.Labels) - chaos.SetAnnotations(meta.Annotations) - - var spec v1alpha1.PodChaosSpec - mapstructure.Decode(exp.Spec, &spec) - chaos.Spec = spec - - return kubeCli.Update(context.Background(), chaos) -} - -func (s *Service) updateNetworkChaos(exp *core.KubeObjectYAMLDescription, kubeCli client.Client) error { - chaos := &v1alpha1.NetworkChaos{} - meta := &exp.Metadata - key := types.NamespacedName{Namespace: meta.Namespace, Name: meta.Name} - - if err := kubeCli.Get(context.Background(), key, chaos); err != nil { - return err - } - - chaos.SetLabels(meta.Labels) - chaos.SetAnnotations(meta.Annotations) - - var spec v1alpha1.NetworkChaosSpec - mapstructure.Decode(exp.Spec, &spec) - chaos.Spec = spec - - var tcParameter v1alpha1.TcParameter - mapstructure.Decode(exp.Spec, &tcParameter) - chaos.Spec.TcParameter = tcParameter - - return kubeCli.Update(context.Background(), chaos) -} - -func (s *Service) updateIOChaos(exp *core.KubeObjectYAMLDescription, kubeCli client.Client) error { - chaos := &v1alpha1.IoChaos{} - meta := &exp.Metadata - key := types.NamespacedName{Namespace: meta.Namespace, Name: meta.Name} - - if err := kubeCli.Get(context.Background(), key, chaos); err != nil { - return err - } - - chaos.SetLabels(meta.Labels) - chaos.SetAnnotations(meta.Annotations) - - var spec v1alpha1.IoChaosSpec - mapstructure.Decode(exp.Spec, &spec) - chaos.Spec = spec - - return kubeCli.Update(context.Background(), chaos) -} - -func (s *Service) updateKernelChaos(exp *core.KubeObjectYAMLDescription, kubeCli client.Client) error { - chaos := &v1alpha1.KernelChaos{} - meta := &exp.Metadata - key := types.NamespacedName{Namespace: meta.Namespace, Name: meta.Name} - - if err := kubeCli.Get(context.Background(), key, chaos); err != nil { - return err - } - - chaos.SetLabels(meta.Labels) - chaos.SetAnnotations(meta.Annotations) - - var spec v1alpha1.KernelChaosSpec - mapstructure.Decode(exp.Spec, &spec) - chaos.Spec = spec - - return kubeCli.Update(context.Background(), chaos) -} - -func (s *Service) updateTimeChaos(exp *core.KubeObjectYAMLDescription, kubeCli client.Client) error { - chaos := &v1alpha1.TimeChaos{} - meta := &exp.Metadata - key := types.NamespacedName{Namespace: meta.Namespace, Name: meta.Name} - - if err := kubeCli.Get(context.Background(), key, chaos); err != nil { - return err - } - - chaos.SetLabels(meta.Labels) - chaos.SetAnnotations(meta.Annotations) - - var spec v1alpha1.TimeChaosSpec - mapstructure.Decode(exp.Spec, &spec) - chaos.Spec = spec - - return kubeCli.Update(context.Background(), chaos) -} - -func (s *Service) updateStressChaos(exp *core.KubeObjectYAMLDescription, kubeCli client.Client) error { - chaos := &v1alpha1.StressChaos{} - meta := &exp.Metadata - key := types.NamespacedName{Namespace: meta.Namespace, Name: meta.Name} - - if err := kubeCli.Get(context.Background(), key, chaos); err != nil { - return err - } - - chaos.SetLabels(meta.Labels) - chaos.SetAnnotations(meta.Annotations) - - var spec v1alpha1.StressChaosSpec - mapstructure.Decode(exp.Spec, &spec) - chaos.Spec = spec - - return kubeCli.Update(context.Background(), chaos) -} - -func (s *Service) updateDNSChaos(exp *core.KubeObjectYAMLDescription, kubeCli client.Client) error { - chaos := &v1alpha1.DNSChaos{} - meta := &exp.Metadata - key := types.NamespacedName{Namespace: meta.Namespace, Name: meta.Name} - - if err := kubeCli.Get(context.Background(), key, chaos); err != nil { - return err - } - - chaos.SetLabels(meta.Labels) - chaos.SetAnnotations(meta.Annotations) - - var spec v1alpha1.DNSChaosSpec - mapstructure.Decode(exp.Spec, &spec) - chaos.Spec = spec - - return kubeCli.Update(context.Background(), chaos) -} - -func (s *Service) updateAwsChaos(exp *core.KubeObjectYAMLDescription, kubeCli client.Client) error { - chaos := &v1alpha1.AwsChaos{} - meta := &exp.Metadata - key := types.NamespacedName{Namespace: meta.Namespace, Name: meta.Name} - - if err := kubeCli.Get(context.Background(), key, chaos); err != nil { - return err - } - - chaos.SetLabels(meta.Labels) - chaos.SetAnnotations(meta.Annotations) - - var spec v1alpha1.AwsChaosSpec - mapstructure.Decode(exp.Spec, &spec) - chaos.Spec = spec - - return kubeCli.Update(context.Background(), chaos) -} - -func setAnnotation(kubeCli client.Client, kind string, ns string, name string) error { - var ( - chaosKind *v1alpha1.ChaosKind - chaosMeta metav1.Object - ok bool - ) - - if chaosKind, ok = v1alpha1.AllKinds()[kind]; !ok { - return fmt.Errorf(kind + " is not supported") - } - ctx := context.TODO() - chaosKey := types.NamespacedName{Namespace: ns, Name: name} - if err := kubeCli.Get(ctx, chaosKey, chaosKind.Chaos); err != nil { - return err - } - - if chaosMeta, ok = chaosKind.Chaos.(metav1.Object); !ok { - return fmt.Errorf("failed to get chaos meta information") - } - annotations := chaosMeta.GetAnnotations() - if annotations == nil { - annotations = make(map[string]string) - } - annotations[common.AnnotationCleanFinalizer] = common.AnnotationCleanFinalizerForced - chaosMeta.SetAnnotations(annotations) - - return kubeCli.Update(context.Background(), chaosKind.Chaos) -} diff --git a/pkg/apiserver/handler.go b/pkg/apiserver/handler.go deleted file mode 100644 index 81c4655bb8..0000000000 --- a/pkg/apiserver/handler.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package apiserver - -import ( - "go.uber.org/fx" - - "github.com/chaos-mesh/chaos-mesh/pkg/apiserver/archive" - "github.com/chaos-mesh/chaos-mesh/pkg/apiserver/common" - "github.com/chaos-mesh/chaos-mesh/pkg/apiserver/event" - "github.com/chaos-mesh/chaos-mesh/pkg/apiserver/experiment" - "github.com/chaos-mesh/chaos-mesh/pkg/apiserver/workflow" -) - -var handlerModule = fx.Options( - fx.Provide( - common.NewService, - experiment.NewService, - event.NewService, - archive.NewService, - workflow.NewServiceWithKubeRepo, - ), - fx.Invoke( - common.Register, - experiment.Register, - event.Register, - archive.Register, - workflow.Register, - ), -) diff --git a/pkg/apiserver/server.go b/pkg/apiserver/server.go deleted file mode 100644 index f8b34aca13..0000000000 --- a/pkg/apiserver/server.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package apiserver - -import ( - "fmt" - "net/http" - - "go.uber.org/fx" - - "github.com/gin-contrib/pprof" - "github.com/gin-gonic/gin" - "github.com/gin-gonic/gin/binding" - "github.com/go-playground/validator/v10" - - apiutils "github.com/chaos-mesh/chaos-mesh/pkg/apiserver/utils" - "github.com/chaos-mesh/chaos-mesh/pkg/apivalidator" - "github.com/chaos-mesh/chaos-mesh/pkg/config" - "github.com/chaos-mesh/chaos-mesh/pkg/swaggerserver" - "github.com/chaos-mesh/chaos-mesh/pkg/uiserver" -) - -var ( - // Module includes the providers (gin engine and api router) and the registers. - Module = fx.Options( - fx.Provide( - newEngine, - newAPIRouter, - ), - handlerModule, - fx.Invoke(serverRegister), - ) -) - -func serverRegister(r *gin.Engine, conf *config.ChaosDashboardConfig) { - listenAddr := fmt.Sprintf("%s:%d", conf.ListenHost, conf.ListenPort) - - go r.Run(listenAddr) -} - -func newEngine() *gin.Engine { - r := gin.Default() - - // default is "/debug/pprof/" - pprof.Register(r) - - r.Use(apiutils.MWHandleErrors()) - - if v, ok := binding.Validator.Engine().(*validator.Validate); ok { - v.RegisterValidation("NameValid", apivalidator.NameValid) - v.RegisterValidation("NamespaceSelectorsValid", apivalidator.NamespaceSelectorsValid) - v.RegisterValidation("MapSelectorsValid", apivalidator.MapSelectorsValid) - v.RegisterValidation("RequirementSelectorsValid", apivalidator.RequirementSelectorsValid) - v.RegisterValidation("PhaseSelectorsValid", apivalidator.PhaseSelectorsValid) - v.RegisterValidation("CronValid", apivalidator.CronValid) - v.RegisterValidation("DurationValid", apivalidator.DurationValid) - v.RegisterValidation("ValueValid", apivalidator.ValueValid) - v.RegisterValidation("PodsValid", apivalidator.PodsValid) - v.RegisterValidation("RequiredFieldEqual", apivalidator.RequiredFieldEqualValid, true) - } - - moveToUIRoot := func(c *gin.Context) { - c.Redirect(http.StatusMovedPermanently, "/dashboard") - } - - r.GET("/", moveToUIRoot) - ui := uiserver.AssetsFS() - if ui != nil { - newDashboardRouter(r, ui) - } else { - r.GET("/dashboard", func(c *gin.Context) { - c.String(http.StatusOK, "Dashboard UI is not built. Please run `UI=1 make`.") - }) - } - r.NoRoute(moveToUIRoot) - - return r -} - -func newAPIRouter(r *gin.Engine) *gin.RouterGroup { - api := r.Group("/api") - { - api.GET("/swagger/*any", swaggerserver.Handler()) - } - - return api -} - -func newDashboardRouter(r *gin.Engine, ui http.FileSystem) { - renderRequest := func(c *gin.Context) { - c.FileFromFS(c.Request.URL.Path, ui) - } - - r.GET("/dashboard/*any", func(c *gin.Context) { - c.FileFromFS("/", ui) - }) - r.GET("/static/*any", renderRequest) - r.GET("/favicon.ico", renderRequest) -} diff --git a/pkg/apiserver/utils/auth.go b/pkg/apiserver/utils/auth.go deleted file mode 100644 index 56c1d1392c..0000000000 --- a/pkg/apiserver/utils/auth.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package utils - -import ( - "net/http" - - "github.com/gin-gonic/gin" - authorizationv1 "k8s.io/api/authorization/v1" - - "github.com/chaos-mesh/chaos-mesh/pkg/clientpool" - "github.com/chaos-mesh/chaos-mesh/pkg/mock" -) - -func AuthRequired(c *gin.Context) { - if mockResult := mock.On("MockAuthRequired"); mockResult != nil { - c.Next() - return - } - - authCli, err := clientpool.ExtractTokenAndGetAuthClient(c.Request.Header) - if err != nil { - c.AbortWithError(http.StatusUnauthorized, ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - namespace := c.Query("namespace") - verb := "list" - if c.Request.Method != http.MethodGet { - // patch is used to indicate delete, create, patch, delete and other write operations - verb = "patch" - } - - sar := &authorizationv1.SelfSubjectAccessReview{ - Spec: authorizationv1.SelfSubjectAccessReviewSpec{ - ResourceAttributes: &authorizationv1.ResourceAttributes{ - Namespace: namespace, - Verb: verb, - Group: "chaos-mesh.org", - Resource: "*", - }, - }, - } - - response, err := authCli.SelfSubjectAccessReviews().Create(sar) - if err != nil { - c.AbortWithError(http.StatusUnauthorized, ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - - if !response.Status.Allowed { - if len(namespace) == 0 { - c.AbortWithError(http.StatusUnauthorized, ErrNoClusterPrivilege.New("can't %s resource in the cluster", verb)) - } else { - c.AbortWithError(http.StatusUnauthorized, ErrNoNamespacePrivilege.New("can't %s resource in namespace %s", verb, namespace)) - } - return - } - - c.Next() -} diff --git a/pkg/apiserver/utils/error.go b/pkg/apiserver/utils/error.go deleted file mode 100644 index 404ca7b9b4..0000000000 --- a/pkg/apiserver/utils/error.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package utils - -import ( - "fmt" - "net/http" - "strings" - - "github.com/gin-gonic/gin" - "github.com/joomcode/errorx" - apierrors "k8s.io/apimachinery/pkg/api/errors" -) - -var ( - ErrNS = errorx.NewNamespace("error.api") - ErrUnknown = ErrNS.NewType("unknown") - ErrInvalidRequest = ErrNS.NewType("invalid_request") - ErrInternalServer = ErrNS.NewType("internal_server_error") - ErrNotFound = ErrNS.NewType("resource_not_found") - ErrNoClusterPrivilege = ErrNS.NewType("no_cluster_privilege") - ErrNoNamespacePrivilege = ErrNS.NewType("no_namespace_privilege") -) - -type APIError struct { - Message string `json:"message"` - Code string `json:"code"` - FullText string `json:"full_text"` - Status string `json:"status"` -} - -// MWHandleErrors creates a middleware that turns (last) error in the context into an APIError json response. -// In handlers, `c.Error(err)` can be used to attach the error to the context. -// When error is attached in the context: -// - The handler can optionally assign the HTTP status code. -// - The handler must not self-generate a response body. -func MWHandleErrors() gin.HandlerFunc { - return func(c *gin.Context) { - c.Next() - - err := c.Errors.Last() - if err == nil { - return - } - - statusCode := c.Writer.Status() - if statusCode == http.StatusOK { - statusCode = http.StatusInternalServerError - } - - innerErr := errorx.Cast(err.Err) - if innerErr == nil { - innerErr = ErrUnknown.WrapWithNoMessage(err.Err) - } - - c.AbortWithStatusJSON(statusCode, APIError{ - Status: "error", - Message: innerErr.Error(), - Code: errorx.GetTypeName(innerErr), - FullText: fmt.Sprintf("%+v", innerErr), - }) - } -} - -func SetErrorForGinCtx(c *gin.Context, err error) { - if apierrors.IsForbidden(err) && strings.Contains(err.Error(), "at the cluster scope") { - _ = c.Error(ErrNoClusterPrivilege.WrapWithNoMessage(err)) - return - } else if apierrors.IsForbidden(err) && strings.Contains(err.Error(), "in the namespace") { - _ = c.Error(ErrNoNamespacePrivilege.WrapWithNoMessage(err)) - return - } else if apierrors.IsNotFound(err) { - _ = c.Error(ErrNotFound.WrapWithNoMessage(err)) - return - } - - _ = c.Error(ErrInternalServer.WrapWithNoMessage(err)) -} diff --git a/pkg/apiserver/workflow/workflow.go b/pkg/apiserver/workflow/workflow.go deleted file mode 100644 index ca961a8732..0000000000 --- a/pkg/apiserver/workflow/workflow.go +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package workflow - -import ( - "encoding/json" - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/chaos-mesh/chaos-mesh/pkg/apiserver/utils" - "github.com/chaos-mesh/chaos-mesh/pkg/clientpool" - "github.com/chaos-mesh/chaos-mesh/pkg/config" - "github.com/chaos-mesh/chaos-mesh/pkg/core" -) - -// StatusResponse defines a common status struct. -type StatusResponse struct { - Status string `json:"status"` -} - -func Register(r *gin.RouterGroup, s *Service) { - endpoint := r.Group("/workflows") - endpoint.GET("", s.listWorkflows) - endpoint.POST("/new", s.createWorkflow) - endpoint.GET("/:namespace/:name", s.getWorkflowDetail) - endpoint.DELETE("/:namespace/:name", s.deleteWorkflow) - endpoint.PUT("/:namespace/:name", s.updateWorkflow) -} - -// Service defines a handler service for workflows. -type Service struct { - conf *config.ChaosDashboardConfig -} - -func NewService(conf *config.ChaosDashboardConfig) *Service { - return &Service{conf: conf} -} - -func NewServiceWithKubeRepo(conf *config.ChaosDashboardConfig) *Service { - return NewService(conf) -} - -// @Summary List workflows from Kubernetes cluster. -// @Description List workflows from Kubernetes cluster. -// @Tags workflows -// @Produce json -// @Param namespace query string false "namespace, given empty string means list from all namespace" -// @Param status query string false "status" Enums(Initializing, Running, Errored, Finished) -// @Success 200 {array} core.Workflow -// @Router /workflows [get] -// @Failure 500 {object} utils.APIError -func (it *Service) listWorkflows(c *gin.Context) { - - namespace := c.Query("namespace") - result := make([]core.Workflow, 0) - - kubeClient, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - repo := core.NewKubeWorkflowRepository(kubeClient) - - if namespace != "" { - workflowFromNs, err := repo.ListWorkflowWithNamespace(c.Request.Context(), namespace) - if err != nil { - utils.SetErrorForGinCtx(c, err) - return - } - result = append(result, workflowFromNs...) - } else { - allWorkflow, err := repo.ListWorkflowFromAllNamespace(c.Request.Context()) - if err != nil { - utils.SetErrorForGinCtx(c, err) - return - } - result = append(result, allWorkflow...) - } - - c.JSON(http.StatusOK, result) -} - -// @Summary Get detailed information about the specified workflow. -// @Description Get detailed information about the specified workflow. -// @Tags workflows -// @Produce json -// @Param namespace path string true "namespace" -// @Param name path string true "name" -// @Router /workflows/{namespace}/{name} [GET] -// @Success 200 {object} core.WorkflowDetail -// @Failure 400 {object} utils.APIError -// @Failure 500 {object} utils.APIError -func (it *Service) getWorkflowDetail(c *gin.Context) { - namespace := c.Param("namespace") - name := c.Param("name") - - kubeClient, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - repo := core.NewKubeWorkflowRepository(kubeClient) - - result, err := repo.GetWorkflowByNamespacedName(c.Request.Context(), namespace, name) - if err != nil { - utils.SetErrorForGinCtx(c, err) - return - } - c.JSON(http.StatusOK, result) -} - -// @Summary Create a new workflow. -// @Description Create a new workflow. -// @Tags workflows -// @Produce json -// @Param request body core.KubeObjectYAMLDescription true "Request body" -// @Success 200 {object} core.KubeObjectYAMLDescription -// @Failure 400 {object} utils.APIError -// @Failure 500 {object} utils.APIError -// @Router /workflows/new [post] -func (it *Service) createWorkflow(c *gin.Context) { - payloadToCreate := core.KubeObjectYAMLDescription{} - err := json.NewDecoder(c.Request.Body).Decode(&payloadToCreate) - if err != nil { - _ = c.Error(utils.ErrInternalServer.Wrap(err, "failed to parse request body")) - return - } - - kubeClient, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - repo := core.NewKubeWorkflowRepository(kubeClient) - - result, err := repo.CreateWorkflowWithRaw(c.Request.Context(), payloadToCreate) - if err != nil { - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - return - } - c.JSON(http.StatusOK, result) -} - -// @Summary Delete the specified workflow. -// @Description Delete the specified workflow. -// @Tags workflows -// @Produce json -// @Param namespace path string true "namespace" -// @Param name path string true "name" -// @Param force query string true "force" Enums(true, false) -// @Success 200 {object} StatusResponse -// @Failure 400 {object} utils.APIError -// @Failure 404 {object} utils.APIError -// @Failure 500 {object} utils.APIError -// @Router /workflows/{namespace}/{name} [delete] -func (it *Service) deleteWorkflow(c *gin.Context) { - namespace := c.Param("namespace") - name := c.Param("name") - - kubeClient, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - repo := core.NewKubeWorkflowRepository(kubeClient) - - err = repo.DeleteWorkflowByNamespacedName(c.Request.Context(), namespace, name) - if err != nil { - utils.SetErrorForGinCtx(c, err) - return - } - c.JSON(http.StatusOK, StatusResponse{Status: "success"}) -} - -// @Summary Update a workflow. -// @Description Update a workflow. -// @Tags workflows -// @Produce json -// @Param request body core.KubeObjectYAMLDescription true "Request body" -// @Success 200 {object} core.KubeObjectYAMLDescription -// @Failure 400 {object} utils.APIError -// @Failure 500 {object} utils.APIError -// @Router /workflows/update [put] -func (it *Service) updateWorkflow(c *gin.Context) { - payloadToUpdate := core.KubeObjectYAMLDescription{} - err := json.NewDecoder(c.Request.Body).Decode(&payloadToUpdate) - if err != nil { - _ = c.Error(utils.ErrInternalServer.Wrap(err, "failed to parse request body")) - return - } - // validate the consistent with path parameter and request body of namespace and name - namespace := c.Param("namespace") - name := c.Param("name") - - if namespace != payloadToUpdate.Metadata.Namespace { - _ = c.Error(utils.ErrInvalidRequest.Wrap(err, - "namespace is not consistent, pathParameter: %s, metaInRaw: %s", - namespace, - payloadToUpdate.Metadata.Namespace), - ) - return - } - if name != payloadToUpdate.Metadata.Name { - _ = c.Error(utils.ErrInvalidRequest.Wrap(err, - "name is not consistent, pathParameter: %s, metaInRaw: %s", - name, - payloadToUpdate.Metadata.Name), - ) - return - } - - kubeClient, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) - if err != nil { - _ = c.Error(utils.ErrInvalidRequest.WrapWithNoMessage(err)) - return - } - repo := core.NewKubeWorkflowRepository(kubeClient) - - result, err := repo.UpdateWorkflowWithRaw(c.Request.Context(), payloadToUpdate) - if err != nil { - _ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err)) - return - } - c.JSON(http.StatusOK, result) - -} diff --git a/pkg/bpm/bpm.go b/pkg/bpm/bpm.go index cb39af1ab7..b84080d72b 100644 --- a/pkg/bpm/bpm.go +++ b/pkg/bpm/bpm.go @@ -1,33 +1,37 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package bpm import ( "context" "fmt" - "os" + "io" "os/exec" "sync" "syscall" + "github.com/go-logr/logr" + "github.com/google/uuid" + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" "github.com/shirou/gopsutil/process" - ctrl "sigs.k8s.io/controller-runtime" + "github.com/chaos-mesh/chaos-mesh/pkg/log" ) -var log = ctrl.Log.WithName("background-process-manager") - type NsType string const ( @@ -60,68 +64,179 @@ const ( ) // ProcessPair is an identifier for process +// Keep compatible with v2.x +// TODO: remove in v3.x +// +// Currently, the bpm locate managed processes by both PID and create time, because the OS may reuse PID, we must check the create time to avoid locating the wrong process. +// +// However, the two-step locating is messy and the create time may be imprecise (we have fixed a [relevant bug](https://github.com/shirou/gopsutil/pull/1204)). +// In future version, we should completely remove the two-step locating and identify managed processes by UID only. type ProcessPair struct { Pid int CreateTime int64 } +type Process struct { + Uid string + + // TODO: remove in v3.x + // store create time, to keep compatible with v2.x + Pair ProcessPair + + Cmd *ManagedCommand + Pipes Pipes + + ctx context.Context + stopped context.CancelFunc +} + +// pipes that will be connected to the command's stdin/stdout +type Pipes struct { + Stdin io.WriteCloser + Stdout io.ReadCloser +} + // BackgroundProcessManager manages all background processes type BackgroundProcessManager struct { - deathSig *sync.Map + // deathChannel is a channel to receive Uid of dead processes + deathChannel chan string + + // wait group to await all processes exit + wg *sync.WaitGroup + + // identifiers is a map to prevent duplicated processes identifiers *sync.Map -} -// NewBackgroundProcessManager creates a background process manager -func NewBackgroundProcessManager() BackgroundProcessManager { - return BackgroundProcessManager{ - deathSig: &sync.Map{}, - identifiers: &sync.Map{}, - } -} + // Uid -> Process + processes *sync.Map -// StartProcess manages a process in manager -func (m *BackgroundProcessManager) StartProcess(cmd *ManagedProcess) error { - var identifierLock *sync.Mutex - if cmd.Identifier != nil { - lock, _ := m.identifiers.LoadOrStore(*cmd.Identifier, &sync.Mutex{}) + // TODO: remove in v3.x + // PidPair -> Uid, to keep compatible with v2.x + pidPairToUid *sync.Map - identifierLock = lock.(*sync.Mutex) + rootLogger logr.Logger - identifierLock.Lock() + metricsCollector *metricsCollector +} + +func startProcess(cmd *ManagedCommand) (*Process, error) { + stdin, err := cmd.StdinPipe() + if err != nil { + return nil, errors.Wrap(err, "create stdin pipe") } - err := cmd.Start() + stdout, err := cmd.StdoutPipe() if err != nil { - log.Error(err, "fail to start process") - return err + return nil, errors.Wrap(err, "create stdout pipe") } + err = cmd.Start() + if err != nil { + return nil, errors.Wrapf(err, "start command `%s`", cmd.String()) + } + + newProcess := &Process{ + Uid: uuid.NewString(), + Cmd: cmd, + Pipes: Pipes{Stdin: stdin, Stdout: stdout}, + } + + newProcess.ctx, newProcess.stopped = context.WithCancel(context.Background()) + + // keep compatible with v2.x + // TODO: remove in v3.x pid := cmd.Process.Pid - procState, err := process.NewProcess(int32(cmd.Process.Pid)) + proc, err := process.NewProcess(int32(cmd.Process.Pid)) if err != nil { - return err + return nil, errors.Wrapf(err, "get process state for pid %d", pid) } - ct, err := procState.CreateTime() + + ct, err := proc.CreateTime() if err != nil { - return err + return nil, errors.Wrapf(err, "get process create time for pid %d", pid) } - pair := ProcessPair{ - Pid: pid, + newProcess.Pair = ProcessPair{ + Pid: int(proc.Pid), CreateTime: ct, } + return newProcess, nil +} + +func (p *Process) Stopped() <-chan struct{} { + return p.ctx.Done() +} + +// StartBackgroundProcessManager creates a background process manager +func StartBackgroundProcessManager(registry prometheus.Registerer, rootLogger logr.Logger) *BackgroundProcessManager { + backgroundProcessManager := &BackgroundProcessManager{ + deathChannel: make(chan string, 1), + wg: &sync.WaitGroup{}, + identifiers: &sync.Map{}, + processes: &sync.Map{}, + pidPairToUid: &sync.Map{}, + rootLogger: rootLogger.WithName("background-process-manager"), + metricsCollector: nil, + } + + go func() { + // return if deathChannel is closed + for uid := range backgroundProcessManager.deathChannel { + process, loaded := backgroundProcessManager.processes.LoadAndDelete(uid) + if loaded { + proc := process.(*Process) + backgroundProcessManager.pidPairToUid.Delete(proc.Pair) + if proc.Cmd.Identifier != nil { + backgroundProcessManager.identifiers.Delete(*proc.Cmd.Identifier) + } + proc.stopped() + } + backgroundProcessManager.wg.Done() + } + }() + + if registry != nil { + backgroundProcessManager.metricsCollector = newMetricsCollector(backgroundProcessManager, registry) + } + + return backgroundProcessManager +} + +func (m *BackgroundProcessManager) recycle(uid string) { + m.deathChannel <- uid +} + +// StartProcess manages a process in manager +func (m *BackgroundProcessManager) StartProcess(ctx context.Context, cmd *ManagedCommand) (*Process, error) { + log := m.getLoggerFromContext(ctx) + if cmd.Identifier != nil { + _, loaded := m.identifiers.LoadOrStore(*cmd.Identifier, true) + if loaded { + return nil, errors.Errorf("process with identifier %s is running", *cmd.Identifier) + } + } + + process, err := startProcess(cmd) + if err != nil { + return nil, err + } - channel, _ := m.deathSig.LoadOrStore(pair, make(chan bool, 1)) - deathChannel := channel.(chan bool) + m.processes.Store(process.Uid, process) + m.pidPairToUid.Store(process.Pair, process.Uid) + // end - log := log.WithValues("pid", pid) + if m.metricsCollector != nil { + m.metricsCollector.bpmControlledProcessTotal.Inc() + } + + m.wg.Add(1) + log = log.WithValues("uid", process.Uid, "pid", process.Pair.Pid) go func() { err := cmd.Wait() if err != nil { - err, ok := err.(*exec.ExitError) - if ok { - status := err.Sys().(syscall.WaitStatus) + if exitErr, ok := err.(*exec.ExitError); ok { + status := exitErr.Sys().(syscall.WaitStatus) if status.Signaled() && status.Signal() == syscall.SIGTERM { log.Info("process stopped with SIGTERM signal") } @@ -129,88 +244,95 @@ func (m *BackgroundProcessManager) StartProcess(cmd *ManagedProcess) error { log.Error(err, "process exited accidentally") } } - log.Info("process stopped") - - deathChannel <- true - m.deathSig.Delete(pair) - - if identifierLock != nil { - identifierLock.Unlock() - m.identifiers.Delete(*cmd.Identifier) - } + m.recycle(process.Uid) }() - return nil + return process, nil } -// KillBackgroundProcess sends SIGTERM to process -func (m *BackgroundProcessManager) KillBackgroundProcess(ctx context.Context, pid int, startTime int64) error { - log := log.WithValues("pid", pid) +func (m *BackgroundProcessManager) Shutdown(ctx context.Context) { + log := m.getLoggerFromContext(ctx) - p, err := os.FindProcess(int(pid)) - if err != nil { - log.Error(err, "unreachable path. `os.FindProcess` will never return an error on unix") - return err - } + m.processes.Range(func(_, value interface{}) bool { + process := value.(*Process) + log := log.WithValues("uid", process.Uid, "pid", process.Pair.Pid) + if err := process.Cmd.Process.Signal(syscall.SIGTERM); err != nil { + log.Error(err, "send SIGTERM to process") + return true + } + return true + }) + m.wg.Wait() + close(m.deathChannel) +} - procState, err := process.NewProcess(int32(pid)) - if err != nil { - // return successfully as the process has exited - return nil - } - ct, err := procState.CreateTime() - if err != nil { - log.Error(err, "fail to read create time") - // return successfully as the process has exited - return nil - } - if startTime != ct { - log.Info("process has already been killed", "startTime", ct, "expectedStartTime", startTime) - // return successfully as the process has exited - return nil +func (m *BackgroundProcessManager) GetUID(pair ProcessPair) (string, bool) { + if uid, loaded := m.pidPairToUid.Load(pair); loaded { + return uid.(string), true } + return "", false +} - ppid, err := procState.Ppid() - if err != nil { - log.Error(err, "fail to read parent id") - // return successfully as the process has exited - return nil +func (m *BackgroundProcessManager) getProc(uid string) (*Process, bool) { + if proc, loaded := m.processes.Load(uid); loaded { + return proc.(*Process), true } - if ppid != int32(os.Getpid()) { - log.Info("process has already been killed", "ppid", ppid) - // return successfully as the process has exited - return nil + return nil, false +} + +func (m *BackgroundProcessManager) GetPipes(uid string) (Pipes, bool) { + proc, ok := m.getProc(uid) + if !ok { + return Pipes{}, false } + return proc.Pipes, true +} - err = p.Signal(syscall.SIGTERM) +// KillBackgroundProcess sends SIGTERM to process +func (m *BackgroundProcessManager) KillBackgroundProcess(ctx context.Context, uid string) error { + log := m.getLoggerFromContext(ctx) + + log = log.WithValues("uid", uid) - if err != nil && err.Error() != "os: process already finished" { - log.Error(err, "error while killing process") - return err + proc, loaded := m.getProc(uid) + if !loaded { + return errors.Errorf("failed to find process with uid %s", uid) } - pair := ProcessPair{ - Pid: pid, - CreateTime: ct, + if err := proc.Cmd.Process.Signal(syscall.SIGTERM); err != nil { + return errors.Wrap(err, "send SIGTERM to process") } - channel, ok := m.deathSig.Load(pair) - if ok { - deathChannel := channel.(chan bool) - select { - case <-deathChannel: - case <-ctx.Done(): - return ctx.Err() + + select { + case <-proc.Stopped(): + log.Info("Successfully killed process") + case <-ctx.Done(): + if err := ctx.Err(); err != nil { + return errors.Wrap(err, "context closed") } } - - log.Info("Successfully killed process") return nil } +// GetIdentifiers finds all identifiers in BPM +func (m *BackgroundProcessManager) GetIdentifiers() []string { + var identifiers []string + m.identifiers.Range(func(key, value interface{}) bool { + identifiers = append(identifiers, key.(string)) + return true + }) + + return identifiers +} + +func (m *BackgroundProcessManager) getLoggerFromContext(ctx context.Context) logr.Logger { + return log.EnrichLoggerWithContext(ctx, m.rootLogger) +} + // DefaultProcessBuilder returns the default process builder -func DefaultProcessBuilder(cmd string, args ...string) *ProcessBuilder { - return &ProcessBuilder{ +func DefaultProcessBuilder(cmd string, args ...string) *CommandBuilder { + return &CommandBuilder{ cmd: cmd, args: args, nsOptions: []nsOption{}, @@ -220,10 +342,11 @@ func DefaultProcessBuilder(cmd string, args ...string) *ProcessBuilder { } } -// ProcessBuilder builds a exec.Cmd for daemon -type ProcessBuilder struct { +// CommandBuilder builds a exec.Cmd for daemon +type CommandBuilder struct { cmd string args []string + env []string nsOptions []nsOption @@ -231,7 +354,14 @@ type ProcessBuilder struct { localMnt bool identifier *string + stdin io.ReadWriteCloser + stdout io.ReadWriteCloser + stderr io.ReadWriteCloser + oomScoreAdj int + + // the context is used to kill the process and will be passed into + // `exec.CommandContext` ctx context.Context } @@ -240,8 +370,14 @@ func GetNsPath(pid uint32, typ NsType) string { return fmt.Sprintf("%s/%d/ns/%s", DefaultProcPrefix, pid, string(typ)) } +// SetEnv sets the environment variables of the process +func (b *CommandBuilder) SetEnv(key, value string) *CommandBuilder { + b.env = append(b.env, fmt.Sprintf("%s=%s", key, value)) + return b +} + // SetNS sets the namespace of the process -func (b *ProcessBuilder) SetNS(pid uint32, typ NsType) *ProcessBuilder { +func (b *CommandBuilder) SetNS(pid uint32, typ NsType) *CommandBuilder { return b.SetNSOpt([]nsOption{{ Typ: typ, Path: GetNsPath(pid, typ), @@ -249,46 +385,84 @@ func (b *ProcessBuilder) SetNS(pid uint32, typ NsType) *ProcessBuilder { } // SetNSOpt sets the namespace of the process -func (b *ProcessBuilder) SetNSOpt(options []nsOption) *ProcessBuilder { +func (b *CommandBuilder) SetNSOpt(options []nsOption) *CommandBuilder { b.nsOptions = append(b.nsOptions, options...) return b } // SetIdentifier sets the identifier of the process -func (b *ProcessBuilder) SetIdentifier(id string) *ProcessBuilder { +// +// The identifier is used to identify the process in BPM, to confirm only one identified process is running. +// If one identified process is already running, new processes with the same identifier will be blocked by lock. +func (b *CommandBuilder) SetIdentifier(id string) *CommandBuilder { b.identifier = &id return b } // EnablePause enables pause for process -func (b *ProcessBuilder) EnablePause() *ProcessBuilder { +func (b *CommandBuilder) EnablePause() *CommandBuilder { b.pause = true return b } -func (b *ProcessBuilder) EnableLocalMnt() *ProcessBuilder { +func (b *CommandBuilder) EnableLocalMnt() *CommandBuilder { b.localMnt = true return b } // SetContext sets context for process -func (b *ProcessBuilder) SetContext(ctx context.Context) *ProcessBuilder { +func (b *CommandBuilder) SetContext(ctx context.Context) *CommandBuilder { b.ctx = ctx return b } +// SetStdin sets stdin for process +func (b *CommandBuilder) SetStdin(stdin io.ReadWriteCloser) *CommandBuilder { + b.stdin = stdin + + return b +} + +// SetStdout sets stdout for process +func (b *CommandBuilder) SetStdout(stdout io.ReadWriteCloser) *CommandBuilder { + b.stdout = stdout + + return b +} + +// SetStderr sets stderr for process +func (b *CommandBuilder) SetStderr(stderr io.ReadWriteCloser) *CommandBuilder { + b.stderr = stderr + + return b +} + +// SetOOMScoreAdj sets the oom_score_adj for a process +// oom_score_adj ranges from -1000 to 1000 +func (b *CommandBuilder) SetOOMScoreAdj(scoreAdj int) *CommandBuilder { + b.oomScoreAdj = scoreAdj + return b +} + +func (b *CommandBuilder) getLoggerFromContext(ctx context.Context) logr.Logger { + // this logger is inherited from the global one + // TODO: replace it with a specific logger by passing in one or creating a new one + logger := log.L().WithName("background-process-manager.process-builder") + return log.EnrichLoggerWithContext(ctx, logger) +} + type nsOption struct { Typ NsType Path string } -// ManagedProcess is a process which can be managed by backgroundProcessManager -type ManagedProcess struct { +// ManagedCommand is a process which can be managed by backgroundProcessManager +type ManagedCommand struct { *exec.Cmd // If the identifier is not nil, process manager should make sure no other diff --git a/pkg/bpm/bpm_test.go b/pkg/bpm/bpm_test.go index 89eaf51d1c..18defbe54b 100644 --- a/pkg/bpm/bpm_test.go +++ b/pkg/bpm/bpm_test.go @@ -1,37 +1,32 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package bpm import ( "context" + "fmt" "math/rand" - "testing" + "strings" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/shirou/gopsutil/process" - "sigs.k8s.io/controller-runtime/pkg/envtest" -) - -func TestBpm(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecsWithDefaultAndCustomReporters(t, - "Background Process Manager Suite", - []Reporter{envtest.NewlineReporter{}}) -} + "github.com/chaos-mesh/chaos-mesh/pkg/log" +) func RandomeIdentifier() string { var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") @@ -43,23 +38,10 @@ func RandomeIdentifier() string { return string(s) } -func WaitProcess(m *BackgroundProcessManager, cmd *ManagedProcess, exceedTime time.Duration) { - pid := cmd.Process.Pid - procState, err := process.NewProcess(int32(pid)) - Expect(err).To(BeNil()) - ct, err := procState.CreateTime() - Expect(err).To(BeNil()) - pair := ProcessPair{ - Pid: pid, - CreateTime: ct, - } - channel, ok := m.deathSig.Load(pair) - Expect(ok).To(BeTrue()) - deathChannel := channel.(chan bool) - +func WaitProcess(m *BackgroundProcessManager, proc *Process, exceedTime time.Duration) { timeExceed := false select { - case <-deathChannel: + case <-proc.Stopped(): case <-time.Tick(exceedTime): timeExceed = true } @@ -67,15 +49,17 @@ func WaitProcess(m *BackgroundProcessManager, cmd *ManagedProcess, exceedTime ti } var _ = Describe("background process manager", func() { - m := NewBackgroundProcessManager() + log, err := log.NewDefaultZapLogger() + Expect(err).To(BeNil()) + m := StartBackgroundProcessManager(nil, log) Context("normally exited process", func() { It("should work", func() { - cmd := DefaultProcessBuilder("sleep", "2").Build() - err := m.StartProcess(cmd) + cmd := DefaultProcessBuilder("sleep", "2").Build(context.Background()) + p, err := m.StartProcess(context.Background(), cmd) Expect(err).To(BeNil()) - WaitProcess(&m, cmd, time.Second*5) + WaitProcess(m, p, time.Second*3) }) It("processes with the same identifier", func() { @@ -83,43 +67,39 @@ var _ = Describe("background process manager", func() { cmd := DefaultProcessBuilder("sleep", "2"). SetIdentifier(identifier). - Build() - err := m.StartProcess(cmd) + Build(context.Background()) + p1, err := m.StartProcess(context.Background(), cmd) Expect(err).To(BeNil()) - startTime := time.Now() + // get error cmd2 := DefaultProcessBuilder("sleep", "2"). SetIdentifier(identifier). - Build() - err = m.StartProcess(cmd2) - costedTime := time.Since(startTime) - Expect(err).To(BeNil()) - Expect(costedTime.Seconds()).Should(BeNumerically(">", 1.9)) + Build(context.Background()) + _, err = m.StartProcess(context.Background(), cmd2) + Expect(err).NotTo(BeNil()) + Expect(strings.Contains(err.Error(), fmt.Sprintf("process with identifier %s is running", identifier))).To(BeTrue()) - _, err = process.NewProcess(int32(cmd.Process.Pid)) - Expect(err).NotTo(BeNil()) // The first process should have exited + WaitProcess(m, p1, time.Second*3) + cmd3 := DefaultProcessBuilder("sleep", "2"). + SetIdentifier(identifier). + Build(context.TODO()) + p3, err := m.StartProcess(context.Background(), cmd3) + Expect(err).To(BeNil()) - WaitProcess(&m, cmd2, time.Second*5) + WaitProcess(m, p3, time.Second*3) }) }) Context("kill process", func() { It("should work", func() { - cmd := DefaultProcessBuilder("sleep", "2").Build() - err := m.StartProcess(cmd) - Expect(err).To(BeNil()) - - pid := cmd.Process.Pid - procState, err := process.NewProcess(int32(pid)) - Expect(err).To(BeNil()) - ct, err := procState.CreateTime() + cmd := DefaultProcessBuilder("sleep", "2").Build(context.Background()) + p, err := m.StartProcess(context.Background(), cmd) Expect(err).To(BeNil()) - err = m.KillBackgroundProcess(context.Background(), pid, ct) + err = m.KillBackgroundProcess(context.Background(), p.Uid) Expect(err).To(BeNil()) - procState, err = process.NewProcess(int32(pid)) - Expect(err).NotTo(BeNil()) + WaitProcess(m, p, time.Second*0) }) It("process with the same identifier", func() { @@ -127,41 +107,84 @@ var _ = Describe("background process manager", func() { cmd := DefaultProcessBuilder("sleep", "2"). SetIdentifier(identifier). - Build() - err := m.StartProcess(cmd) + Build(context.Background()) + p1, err := m.StartProcess(context.Background(), cmd) Expect(err).To(BeNil()) - pid := cmd.Process.Pid - procState, err := process.NewProcess(int32(pid)) + // get error + cmd2 := DefaultProcessBuilder("sleep", "2"). + SetIdentifier(identifier). + Build(context.Background()) + _, err = m.StartProcess(context.Background(), cmd2) + Expect(err).NotTo(BeNil()) + Expect(strings.Contains(err.Error(), fmt.Sprintf("process with identifier %s is running", identifier))).To(BeTrue()) + WaitProcess(m, p1, time.Second*3) + + cmd3 := DefaultProcessBuilder("sleep", "2"). + SetIdentifier(identifier). + Build(context.Background()) + p3, err := m.StartProcess(context.Background(), cmd3) Expect(err).To(BeNil()) - ct, err := procState.CreateTime() + + err = m.KillBackgroundProcess(context.Background(), p3.Uid) Expect(err).To(BeNil()) - cmd2 := DefaultProcessBuilder("sleep", "2"). + cmd4 := DefaultProcessBuilder("sleep", "2"). SetIdentifier(identifier). - Build() - - go func() { - time.Sleep(time.Second) + Build(context.Background()) + p4, err := m.StartProcess(context.Background(), cmd4) + Expect(err).To(BeNil()) + WaitProcess(m, p4, time.Second*3) + }) + }) - err = m.KillBackgroundProcess(context.Background(), pid, ct) - Expect(err).To(BeNil()) - }() + Context("get identifiers", func() { + It("should work", func() { + identifier := RandomeIdentifier() + cmd := DefaultProcessBuilder("sleep", "2"). + SetIdentifier(identifier). + Build(context.Background()) - startTime := time.Now() - err = m.StartProcess(cmd2) - costedTime := time.Since(startTime) + p, err := m.StartProcess(context.Background(), cmd) Expect(err).To(BeNil()) - Expect(costedTime.Seconds()).Should(And(BeNumerically("<", 2), BeNumerically(">", 1))) - pid2 := cmd2.Process.Pid - procState2, err := process.NewProcess(int32(pid2)) + ids := m.GetIdentifiers() + Expect(ids).To(Equal([]string{identifier})) + + WaitProcess(m, p, time.Second*3) + + // wait for deleting identifier + time.Sleep(time.Second * 2) + ids = m.GetIdentifiers() + Expect(len(ids)).To(Equal(0)) + }) + + It("should work with nil identifier", func() { + cmd := DefaultProcessBuilder("sleep", "2").Build(context.Background()) + + p, err := m.StartProcess(context.Background(), cmd) Expect(err).To(BeNil()) - ct2, err := procState2.CreateTime() + + ids := m.GetIdentifiers() + Expect(len(ids)).To(Equal(0)) + + WaitProcess(m, p, time.Second*5) + }) + }) + + Context("get uid", func() { + It("kill process", func() { + cmd := DefaultProcessBuilder("sleep", "2").Build(context.Background()) + p, err := m.StartProcess(context.Background(), cmd) Expect(err).To(BeNil()) - err = m.KillBackgroundProcess(context.Background(), pid2, ct2) + uid, loaded := m.GetUID(p.Pair) + Expect(loaded).To(BeTrue()) + + err = m.KillBackgroundProcess(context.Background(), uid) Expect(err).To(BeNil()) + + WaitProcess(m, p, time.Second*0) }) }) }) diff --git a/pkg/bpm/build_darwin.go b/pkg/bpm/build_darwin.go index 831345d627..927226b60d 100644 --- a/pkg/bpm/build_darwin.go +++ b/pkg/bpm/build_darwin.go @@ -1,19 +1,23 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package bpm -// Build builds the process -func (b *ProcessBuilder) Build() *ManagedProcess { +import "context" + +// Build builds the command +func (b *CommandBuilder) Build(ctx context.Context) *ManagedCommand { panic("unimplemented") } diff --git a/pkg/bpm/build_linux.go b/pkg/bpm/build_linux.go index d8495bf439..961922b098 100644 --- a/pkg/bpm/build_linux.go +++ b/pkg/bpm/build_linux.go @@ -1,29 +1,35 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package bpm import ( "context" "os/exec" + "strconv" "strings" "syscall" "github.com/chaos-mesh/chaos-mesh/pkg/mock" ) -// Build builds the process -func (b *ProcessBuilder) Build() *ManagedProcess { +// Build builds the command +// the ctx argument passes the context information to this function +// e.g. the corresponding resource name. +func (b *CommandBuilder) Build(ctx context.Context) *ManagedCommand { + log := b.getLoggerFromContext(ctx) args := b.args cmd := b.cmd @@ -39,6 +45,16 @@ func (b *ProcessBuilder) Build() *ManagedProcess { cmd = nsexecPath } + if b.oomScoreAdj != 0 { + args = append([]string{"-n", strconv.Itoa(b.oomScoreAdj), "--", cmd}, args...) + cmd = "choom" + } + + // pause should always be the first command to execute because the + // `stress_server` will check whether the /proc/PID/comm is `pause` to + // determine whether it should continue to send `SIGCONT`. If the first + // command is not `pause`, the real `pause` program may not receive the + // command successfully. if b.pause { args = append([]string{cmd}, args...) cmd = pausePath @@ -46,7 +62,7 @@ func (b *ProcessBuilder) Build() *ManagedProcess { if c := mock.On("MockProcessBuild"); c != nil { f := c.(func(context.Context, string, ...string) *exec.Cmd) - return &ManagedProcess{ + return &ManagedCommand{ Cmd: f(b.ctx, cmd, args...), Identifier: b.identifier, } @@ -55,10 +71,23 @@ func (b *ProcessBuilder) Build() *ManagedProcess { log.Info("build command", "command", cmd+" "+strings.Join(args, " ")) command := exec.CommandContext(b.ctx, cmd, args...) + command.Env = b.env command.SysProcAttr = &syscall.SysProcAttr{} command.SysProcAttr.Pdeathsig = syscall.SIGTERM - return &ManagedProcess{ + if b.stdin != nil { + command.Stdin = b.stdin + } + + if b.stdout != nil { + command.Stdout = b.stdout + } + + if b.stderr != nil { + command.Stderr = b.stderr + } + + return &ManagedCommand{ Cmd: command, Identifier: b.identifier, } diff --git a/pkg/bpm/metrics.go b/pkg/bpm/metrics.go new file mode 100644 index 0000000000..3732563b2d --- /dev/null +++ b/pkg/bpm/metrics.go @@ -0,0 +1,59 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package bpm + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +type metricsCollector struct { + backgroundProcessManager *BackgroundProcessManager + bpmControlledProcesses prometheus.Gauge + bpmControlledProcessTotal prometheus.Counter +} + +// newMetricsCollector initializes metrics for each chaos daemon +func newMetricsCollector(backgroundProcessManager *BackgroundProcessManager, register prometheus.Registerer) *metricsCollector { + collector := &metricsCollector{ + backgroundProcessManager: backgroundProcessManager, + bpmControlledProcesses: prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "chaos_daemon_bpm_controlled_processes", + Help: "Current number of bpm controlled processes", + }), + bpmControlledProcessTotal: prometheus.NewCounter(prometheus.CounterOpts{ + Name: "chaos_daemon_bpm_controlled_process_total", + Help: "Total count of bpm controlled processes", + }), + } + register.MustRegister(collector) + return collector +} + +func (collector *metricsCollector) Describe(ch chan<- *prometheus.Desc) { + collector.bpmControlledProcesses.Describe(ch) + collector.bpmControlledProcessTotal.Describe(ch) +} + +func (collector *metricsCollector) Collect(ch chan<- prometheus.Metric) { + collector.collectBpmControlledProcesses() + collector.bpmControlledProcesses.Collect(ch) + collector.bpmControlledProcessTotal.Collect(ch) +} + +func (collector *metricsCollector) collectBpmControlledProcesses() { + ids := collector.backgroundProcessManager.GetIdentifiers() + collector.bpmControlledProcesses.Set(float64(len(ids))) +} diff --git a/pkg/bpm/suit_test.go b/pkg/bpm/suit_test.go new file mode 100644 index 0000000000..ba68c0322c --- /dev/null +++ b/pkg/bpm/suit_test.go @@ -0,0 +1,29 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package bpm + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestSuite(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Background Process Manager Suite") +} diff --git a/pkg/bpm/utils.go b/pkg/bpm/utils.go deleted file mode 100644 index b6a69cb86c..0000000000 --- a/pkg/bpm/utils.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package bpm - -import ( - "bytes" - "io" - "sync" -) - -type blockingBuffer struct { - buf bytes.Buffer - cond *sync.Cond - closed bool -} - -func NewBlockingBuffer() *blockingBuffer { - m := sync.Mutex{} - return &blockingBuffer{ - cond: sync.NewCond(&m), - buf: bytes.Buffer{}, - closed: false, - } -} - -func (br *blockingBuffer) Write(b []byte) (ln int, err error) { - if br.closed { - return 0, nil - } - ln, err = br.buf.Write(b) - br.cond.Broadcast() - return -} - -func (br *blockingBuffer) Read(b []byte) (ln int, err error) { - if br.closed { - return 0, io.EOF - } - ln, err = br.buf.Read(b) - for err == io.EOF { - br.cond.L.Lock() - if br.closed { - return 0, io.EOF - } - br.cond.Wait() - br.cond.L.Unlock() - ln, err = br.buf.Read(b) - } - return -} - -func (br *blockingBuffer) Close() { - br.closed = true - br.cond.Broadcast() -} diff --git a/pkg/cerr/common_errors.go b/pkg/cerr/common_errors.go new file mode 100644 index 0000000000..b0df79a7d7 --- /dev/null +++ b/pkg/cerr/common_errors.go @@ -0,0 +1,86 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package cerr + +import ( + "reflect" + + "github.com/pkg/errors" +) + +type errHelper struct { + inner error +} + +func FromErr(err error) *errHelper { + return &errHelper{inner: err} +} + +func (h *errHelper) Err() error { + return h.inner +} + +func NotType[expected any]() *errHelper { + var exp expected + return &errHelper{inner: errors.Errorf("expected type: %T", exp)} +} + +func NotImpl[expected any]() *errHelper { + var exp *expected + return &errHelper{inner: errors.Errorf("not implement %v", reflect.TypeOf(exp).Elem())} +} + +func NotFoundType[in any]() *errHelper { + var i in + return &errHelper{inner: errors.Errorf("not found type: %T", i)} +} + +func NotInit[in any]() *errHelper { + var i in + return &errHelper{inner: errors.Errorf("not init %T", i)} +} + +func NotFound(name string) *errHelper { + return &errHelper{errors.Errorf("%s not found", name)} +} + +func (h *errHelper) WrapInput(in any) *errHelper { + return &errHelper{inner: errors.Wrapf(h.inner, "input type: %T, input value: %v", in, in)} +} + +func (h *errHelper) WrapValue(in any) *errHelper { + return &errHelper{inner: errors.Wrapf(h.inner, "input value: %v", in)} +} + +func (h *errHelper) WrapName(name string) *errHelper { + return &errHelper{inner: errors.Wrapf(h.inner, "%s", name)} +} + +func (h *errHelper) WrapErr(err error) *errHelper { + return &errHelper{inner: errors.Wrapf(h.inner, "err : %s", err)} +} + +func (h errHelper) Wrapf(format string, args ...interface{}) *errHelper { + return &errHelper{inner: errors.Wrapf(h.inner, format, args...)} +} + +func (h *errHelper) WithStack() *errHelper { + return &errHelper{inner: errors.WithStack(h.inner)} +} + +var ( + ErrDuplicateEntity = errors.New("duplicate entity") +) diff --git a/pkg/chaosctl/README.md b/pkg/chaosctl/README.md index d187117c2a..ef34161900 100644 --- a/pkg/chaosctl/README.md +++ b/pkg/chaosctl/README.md @@ -1,19 +1,23 @@ # chaosctl -Chaostl is a tool (currently) used to print debug info. Maintainers would make use of it to better provide their suggestions for issues. +Chaosctl is a tool (currently) used to print debug info. Maintainers would make use of it to better provide their suggestions for issues. ## How to build + ```shell cd $CHAOSMESH_DIR make chaosctl ./bin/chaosctl --help # to see if build succeeds. ``` + Chaoctl supports shell autocompletion, which could save you some typing. Do `./bin/chaosctl completion -h` for detail. ## How to use + **Debug** `chaoctl debug` is used to print debug info of certain chaos. Currently, it supports **networkchaos**, **stresschaos** and **iochaos**. + ```shell # To print info of each networkchaos ./bin/chaosctl debug networkchaos @@ -26,6 +30,7 @@ Chaoctl supports shell autocompletion, which could save you some typing. Do `./b **Logs** `chaoctl logs` is used to easily print log from all chaos-mesh components, including controller-manager, chaos-daemon and chaos-dashboard. + ```shell # Default print all log of all chaosmesh components ./bin/chaosctl logs @@ -35,7 +40,9 @@ Chaoctl supports shell autocompletion, which could save you some typing. Do `./b ``` ## Detail of `debug` -An example output structure of `debug` would be like: + +An example output structure of `debug` would be like: + ``` CHAOSNAME PODNAME (which the chaos would take effect on) @@ -43,20 +50,24 @@ PODNAME (which the chaos would take effect on) PODNAME DEBUG_INFO ``` + The `DEBUG_INFO` of each supported chaos would be: -​ NetworkChaos: +​ NetworkChaos: + 1. `ipset list` of chaos daemon 2. `tc qdisc list` 3. `iptables list` 4. podnetworkchaos spec -​ StressChaos: +​ StressChaos: + 1. `ps` of target pod 2. `cat /proc/${PID}/cgroup` of each process 3. `cat /proc/${stress-ng_PID}/cgroup` 4. the actual `cpu`/`memory` limit, compared with the set value -​ IoChaos: +​ IOChaos: + 1. `cat /proc/mounts` of target pod 2. `ls -l /proc/${PID}/fd` diff --git a/pkg/chaosctl/cmd/completion.go b/pkg/chaosctl/cmd/completion.go index efaefb252a..f3fcbca357 100644 --- a/pkg/chaosctl/cmd/completion.go +++ b/pkg/chaosctl/cmd/completion.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package cmd diff --git a/pkg/chaosctl/cmd/debug.go b/pkg/chaosctl/cmd/debug.go index 7066c25388..ff246d6439 100644 --- a/pkg/chaosctl/cmd/debug.go +++ b/pkg/chaosctl/cmd/debug.go @@ -1,62 +1,51 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package cmd import ( "context" "fmt" - "strings" "github.com/go-logr/logr" - + "github.com/pkg/errors" "github.com/spf13/cobra" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "sigs.k8s.io/controller-runtime/pkg/client" "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" - cm "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" - "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/debug/iochaos" - "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/debug/networkchaos" - "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/debug/stresschaos" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/debug" ) type DebugOptions struct { - logger logr.Logger - namespace string - CaCertFile string - CertFile string - KeyFile string - Insecure bool + namespace string } const ( networkChaos = "networkchaos" stressChaos = "stresschaos" ioChaos = "iochaos" + httpChaos = "httpchaos" ) -func NewDebugCommand(logger logr.Logger) (*cobra.Command, error) { - o := &DebugOptions{ - logger: logger, - } +func NewDebugCommand(logger logr.Logger, debugs map[string]debug.Debug) (*cobra.Command, error) { + o := &DebugOptions{} debugCmd := &cobra.Command{ Use: `debug (CHAOSTYPE) [-c CHAOSNAME] [-n NAMESPACE]`, Short: `Print the debug information for certain chaos`, Long: `Print the debug information for certain chaos. -Currently support networkchaos, stresschaos and iochaos. +Currently support networkchaos, stresschaos, iochaos and httpchaos. Examples: # Return debug information from all networkchaos in default namespace @@ -67,106 +56,64 @@ Examples: ValidArgsFunction: noCompletions, } - // Need to separately support chaos-level completion, so split each chaos apart - networkCmd := &cobra.Command{ - Use: `networkchaos (CHAOSNAME) [-n NAMESPACE]`, - Short: `Print the debug information for certain network chaos`, - Long: `Print the debug information for certain network chaos`, - RunE: func(cmd *cobra.Command, args []string) error { - clientset, err := cm.InitClientSet() - if err != nil { - return err - } - return o.Run(networkChaos, args, clientset) - }, - SilenceErrors: true, - SilenceUsage: true, - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - clientset, err := cm.InitClientSet() - if err != nil { - return nil, cobra.ShellCompDirectiveDefault - } - if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp - } - return listChaos(networkChaos, o.namespace, toComplete, clientset.CtrlCli) - }, + for chaosType, debug := range debugs { + debugCmd.AddCommand(debugResourceCommand(o, chaosType, debug)) } - stressCmd := &cobra.Command{ - Use: `stresschaos (CHAOSNAME) [-n NAMESPACE]`, - Short: `Print the debug information for certain stress chaos`, - Long: `Print the debug information for certain stress chaos`, + debugCmd.PersistentFlags().StringVarP(&o.namespace, "namespace", "n", "default", "namespace to find chaos") + err := debugCmd.RegisterFlagCompletionFunc("namespace", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + client, cancel, err := common.CreateClient(context.TODO(), managerNamespace, managerSvc) + if err != nil { + logger.Error(err, "fail to create client") + return nil, cobra.ShellCompDirectiveNoFileComp + } + defer cancel() + + completion, err := client.ListNamespace(context.TODO()) + if err != nil { + logger.Error(err, "fail to complete resource") + return nil, cobra.ShellCompDirectiveNoFileComp + } + + return completion, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace + }) + return debugCmd, err +} + +func debugResourceCommand(option *DebugOptions, chaosType string, debug debug.Debug) *cobra.Command { + return &cobra.Command{ + Use: fmt.Sprintf(`%s (CHAOSNAME) [-n NAMESPACE]`, chaosType), + Short: fmt.Sprintf(`Print the debug information for certain %s`, chaosType), + Long: fmt.Sprintf(`Print the debug information for certain %s`, chaosType), RunE: func(cmd *cobra.Command, args []string) error { - clientset, err := cm.InitClientSet() + client, cancel, err := common.CreateClient(context.TODO(), managerNamespace, managerSvc) if err != nil { return err } - return o.Run(stressChaos, args, clientset) + defer cancel() + return option.Run(debug(client), args) }, SilenceErrors: true, SilenceUsage: true, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - clientset, err := cm.InitClientSet() - if err != nil { - return nil, cobra.ShellCompDirectiveDefault - } if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp + return []string{}, cobra.ShellCompDirectiveNoFileComp } - return listChaos(stressChaos, o.namespace, toComplete, clientset.CtrlCli) - }, - } - - ioCmd := &cobra.Command{ - Use: `iochaos (CHAOSNAME) [-n NAMESPACE]`, - Short: `Print the debug information for certain io chaos`, - Long: `Print the debug information for certain io chaos`, - RunE: func(cmd *cobra.Command, args []string) error { - clientset, err := cm.InitClientSet() + client, cancel, err := common.CreateClient(context.TODO(), managerNamespace, managerSvc) if err != nil { - return err - } - return o.Run(ioChaos, args, clientset) - - }, - SilenceErrors: true, - SilenceUsage: true, - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - clientset, err := cm.InitClientSet() - if err != nil { - return nil, cobra.ShellCompDirectiveDefault - } - if len(args) != 0 { + common.PrettyPrint(errors.Wrap(err, "create client").Error(), 0, common.Red) return nil, cobra.ShellCompDirectiveNoFileComp } - return listChaos(ioChaos, o.namespace, toComplete, clientset.CtrlCli) + defer cancel() + return option.List(debug(client)) }, } - - debugCmd.AddCommand(networkCmd) - debugCmd.AddCommand(stressCmd) - debugCmd.AddCommand(ioCmd) - - debugCmd.PersistentFlags().StringVarP(&o.namespace, "namespace", "n", "default", "namespace to find chaos") - debugCmd.PersistentFlags().StringVar(&o.CaCertFile, "cacert", "", "file path to cacert file") - debugCmd.PersistentFlags().StringVar(&o.CertFile, "cert", "", "file path to cert file") - debugCmd.PersistentFlags().StringVar(&o.KeyFile, "key", "", "file path to key file") - debugCmd.PersistentFlags().BoolVarP(&o.Insecure, "insecure", "i", false, "Insecure mode will use unauthorized grpc") - err := debugCmd.RegisterFlagCompletionFunc("namespace", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - clientset, err := cm.InitClientSet() - if err != nil { - return nil, cobra.ShellCompDirectiveDefault - } - return listNamespace(toComplete, clientset.KubeCli) - }) - return debugCmd, err } // Run debug -func (o *DebugOptions) Run(chaosType string, args []string, c *cm.ClientSet) error { +func (o *DebugOptions) Run(debugger debug.Debugger, args []string) error { if len(args) > 1 { - return fmt.Errorf("only one chaos could be specified") + return errors.New("only one chaos could be specified") } ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -176,64 +123,28 @@ func (o *DebugOptions) Run(chaosType string, args []string, c *cm.ClientSet) err chaosName = args[0] } - chaosList, chaosNameList, err := cm.GetChaosList(ctx, chaosType, chaosName, o.namespace, c.CtrlCli) + var result []*common.ChaosResult + var err error + + result, err = debugger.Collect(ctx, o.namespace, chaosName) if err != nil { return err } - var result []cm.ChaosResult - common.TLSFiles = common.TLSFileConfig{CaCert: o.CaCertFile, Cert: o.CertFile, Key: o.KeyFile} - common.Insecure = o.Insecure - for i, chaos := range chaosList { - var chaosResult cm.ChaosResult - chaosResult.Name = chaosNameList[i] - - var err error - switch chaosType { - case networkChaos: - err = networkchaos.Debug(ctx, chaos, c, &chaosResult) - case stressChaos: - err = stresschaos.Debug(ctx, chaos, c, &chaosResult) - case ioChaos: - err = iochaos.Debug(ctx, chaos, c, &chaosResult) - default: - return fmt.Errorf("chaos type not supported") - } - result = append(result, chaosResult) - if err != nil { - cm.PrintResult(result) - return err - } - } - cm.PrintResult(result) - return nil -} -func listNamespace(toComplete string, c *kubernetes.Clientset) ([]string, cobra.ShellCompDirective) { - namespaces, err := c.CoreV1().Namespaces().List(v1.ListOptions{}) - if err != nil { - return nil, cobra.ShellCompDirectiveDefault - } - var ret []string - for _, ns := range namespaces.Items { - if strings.HasPrefix(ns.Name, toComplete) { - ret = append(ret, ns.Name) - } - } - return ret, cobra.ShellCompDirectiveNoFileComp + common.PrintResult(result) + return nil } -func listChaos(chaosType string, namespace string, toComplete string, c client.Client) ([]string, cobra.ShellCompDirective) { +// Run debug +func (o *DebugOptions) List(debugger debug.Debugger) ([]string, cobra.ShellCompDirective) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - _, chaosList, err := cm.GetChaosList(ctx, chaosType, "", namespace, c) + + chaos, err := debugger.List(ctx, o.namespace) if err != nil { - return nil, cobra.ShellCompDirectiveDefault - } - var ret []string - for _, chaos := range chaosList { - if strings.HasPrefix(chaos, toComplete) { - ret = append(ret, chaos) - } + common.PrettyPrint(errors.Wrap(err, "list chaos").Error(), 0, common.Red) + return nil, cobra.ShellCompDirectiveNoFileComp } - return ret, cobra.ShellCompDirectiveNoFileComp + + return chaos, cobra.ShellCompDirectiveNoFileComp } diff --git a/pkg/chaosctl/cmd/forward.go b/pkg/chaosctl/cmd/forward.go new file mode 100644 index 0000000000..d26e4d7d7f --- /dev/null +++ b/pkg/chaosctl/cmd/forward.go @@ -0,0 +1,46 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package cmd + +import ( + "context" + "fmt" + "os" + "os/signal" + + "github.com/spf13/cobra" + + ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client" +) + +// forwardCmd represents the forward command +var forwardCmd = &cobra.Command{ + Use: "forward", + Short: "Forward ctrl api port to local", + RunE: func(cmd *cobra.Command, args []string) error { + // TODO: input ns by args + cancel, port, err := ctrlclient.ForwardCtrlServer(context.Background(), managerNamespace, managerSvc) + if err != nil { + return err + } + fmt.Printf("forward ctrl api to local port(%d)", port) + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + <-c + cancel() + return nil + }, +} diff --git a/pkg/chaosctl/cmd/logs.go b/pkg/chaosctl/cmd/logs.go index 3142808539..11a72dd9a1 100644 --- a/pkg/chaosctl/cmd/logs.go +++ b/pkg/chaosctl/cmd/logs.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package cmd @@ -18,29 +20,31 @@ import ( "fmt" "strings" - "github.com/go-logr/logr" + "github.com/hasura/go-graphql-client" "github.com/pkg/errors" - "github.com/spf13/cobra" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/config" cm "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" ) type logsOptions struct { - logger logr.Logger - tail int64 - node string + tail int64 + node string } -func NewLogsCmd(logger logr.Logger) (*cobra.Command, error) { - o := &logsOptions{ - logger: logger, - } +type Component string + +const ( + Manager Component = "MANAGER" + Daemon Component = "DAEMON" + Dashboard Component = "DASHBOARD" + DnsServer Component = "DNSSERVER" +) + +func NewLogsCmd() (*cobra.Command, error) { + o := &logsOptions{} logsCmd := &cobra.Command{ Use: `logs [-t LINE]`, @@ -61,8 +65,8 @@ Examples: ValidArgsFunction: noCompletions, } - logsCmd.Flags().Int64VarP(&o.tail, "tail", "t", -1, "Number of lines of recent log") - logsCmd.Flags().StringVarP(&o.node, "node", "n", "", "Number of lines of recent log") + logsCmd.Flags().Int64VarP(&o.tail, "tail", "t", -1, "number of lines of recent log") + logsCmd.Flags().StringVarP(&o.node, "node", "n", "", "the node of target pods") err := logsCmd.RegisterFlagCompletionFunc("node", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { clientset, err := cm.InitClientSet() if err != nil { @@ -78,44 +82,63 @@ Examples: // Run logs func (o *logsOptions) Run(args []string) error { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - c, err := cm.InitClientSet() + client, cancel, err := cm.CreateClient(context.TODO(), managerNamespace, managerSvc) if err != nil { - o.logger.V(4).Info("failed to initialize clientset", "err", err) - return err + return errors.Wrap(err, "failed to initialize clientset") } + defer cancel() - componentsNeeded := []string{"controller-manager", "chaos-daemon", "chaos-dashboard"} + componentsNeeded := []Component{Manager, Daemon, Dashboard, DnsServer} for _, name := range componentsNeeded { - selectorSpec := v1alpha1.SelectorSpec{ - LabelSelectors: map[string]string{"app.kubernetes.io/component": name}, + var query struct { + Namespace []struct { + Component []struct { + Name string + Spec struct { + NodeName string + } + Logs string + } `graphql:"component(component: $component)"` + } `graphql:"namespace(ns: $namespace)"` } - if o.node != "" { - selectorSpec.Nodes = []string{o.node} + + variables := map[string]interface{}{ + "namespace": graphql.String(managerNamespace), + "component": name, } - // TODO: just use kubernetes native label selector - components, err := selector.SelectPods(ctx, c.CtrlCli, nil, selectorSpec, config.ControllerCfg.ClusterScoped, config.ControllerCfg.TargetNamespace, config.ControllerCfg.EnableFilterNamespace) + err := client.QueryClient.Query(context.TODO(), &query, variables) if err != nil { - return errors.Wrapf(err, "failed to SelectPods for component %s", name) + return err + } + + if len(query.Namespace) == 0 { + return fmt.Errorf("no namespace %s found", managerNamespace) } - o.logger.V(4).Info("select pods for component", "component", name, "pods", components) - for _, comp := range components { - cm.PrettyPrint(fmt.Sprintf("[%s]", comp.Name), 0, cm.Cyan) - comLog, err := cm.Log(comp, o.tail, c.KubeCli) - if err != nil { - cm.PrettyPrint(err.Error(), 1, cm.Red) - } else { - cm.PrettyPrint(comLog, 1, cm.NoColor) + + for _, component := range query.Namespace[0].Component { + if o.node != "" && component.Spec.NodeName != o.node { + // ignore component on this node + continue } + + logLines := strings.Split(component.Logs, "\n") + if o.tail > 0 { + if len(logLines) > int(o.tail) { + logLines = logLines[len(logLines)-int(o.tail)-1:] + } + } + + cm.PrettyPrint(fmt.Sprintf("[%s]", component.Name), 0, cm.Cyan) + cm.PrettyPrint(strings.Join(logLines, "\n"), 1, cm.NoColor) } } return nil } func listNodes(toComplete string, c *kubernetes.Clientset) ([]string, cobra.ShellCompDirective) { - nodes, err := c.CoreV1().Nodes().List(v1.ListOptions{}) + // FIXME: get context from parameter + nodes, err := c.CoreV1().Nodes().List(context.TODO(), v1.ListOptions{}) if err != nil { return nil, cobra.ShellCompDirectiveDefault } diff --git a/pkg/chaosctl/cmd/physicalmachine.go b/pkg/chaosctl/cmd/physicalmachine.go new file mode 100644 index 0000000000..6d6eedf77c --- /dev/null +++ b/pkg/chaosctl/cmd/physicalmachine.go @@ -0,0 +1,53 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package cmd + +import ( + "github.com/spf13/cobra" + + "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/physicalmachine" +) + +func NewPhysicalMachineCommand() (*cobra.Command, error) { + physicalMachineCmd := &cobra.Command{ + Use: `physical-machine (ACTION)`, + Aliases: []string{"pm"}, + Short: `Helper for generating TLS certs and creating resources for physical machines`, + Long: `Helper for generating TLS certs and creating resources for physical machine`, + ValidArgsFunction: noCompletions, + } + + initCmd, err := physicalmachine.NewPhysicalMachineInitCmd() + if err != nil { + return nil, err + } + + generateCmd, err := physicalmachine.NewPhysicalMachineGenerateCmd() + if err != nil { + return nil, err + } + + createCmd, err := physicalmachine.NewPhysicalMachineCreateCmd() + if err != nil { + return nil, err + } + + physicalMachineCmd.AddCommand(initCmd) + physicalMachineCmd.AddCommand(generateCmd) + physicalMachineCmd.AddCommand(createCmd) + + return physicalMachineCmd, nil +} diff --git a/pkg/chaosctl/cmd/recover.go b/pkg/chaosctl/cmd/recover.go new file mode 100644 index 0000000000..b3f1b40bdc --- /dev/null +++ b/pkg/chaosctl/cmd/recover.go @@ -0,0 +1,183 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package cmd + +import ( + "context" + "fmt" + "strings" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/recover" + ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client" + "github.com/chaos-mesh/chaos-mesh/pkg/label" +) + +type RecoverOptions struct { + namespace string + labels *[]string +} + +func NewRecoverCommand(logger logr.Logger, builders map[string]recover.RecovererBuilder) (*cobra.Command, error) { + o := &RecoverOptions{namespace: "default"} + + recoverCmd := &cobra.Command{ + Use: `recover (CHAOSTYPE) POD[,POD[,POD...]] [-n NAMESPACE]`, + Short: `Recover certain chaos from certain pods`, + Long: `Recover certain chaos from certain pods. +Currently unimplemented. + +Examples: + # Recover network chaos from pods in namespace default + chaosctl recover networkchaos + + # Recover network chaos from certain pods in certain namespace + chaosctl recover networkchaos pod1 pod2 pod3 -n NAMESPACE + + # Recover network chaos from pods with label key=value + chaosctl recover networkchaos -l key=value`, + ValidArgsFunction: noCompletions, + } + + for chaosType, builder := range builders { + recoverCmd.AddCommand(recoverResourceCommand(o, chaosType, builder)) + } + + recoverCmd.PersistentFlags().StringVarP(&o.namespace, "namespace", "n", "default", "namespace to find pods") + o.labels = recoverCmd.PersistentFlags().StringSliceP("label", "l", nil, "labels to select pods") + err := recoverCmd.RegisterFlagCompletionFunc("namespace", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + client, cancel, err := common.CreateClient(context.TODO(), managerNamespace, managerSvc) + if err != nil { + logger.Error(err, "create client") + return nil, cobra.ShellCompDirectiveNoFileComp + } + defer cancel() + + completion, err := client.ListNamespace(context.TODO()) + if err != nil { + logger.Error(err, "complete resource") + return nil, cobra.ShellCompDirectiveNoFileComp + } + + return completion, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace + }) + if err != nil { + return nil, errors.Wrap(err, "register completion func for flag `namespace`") + } + err = recoverCmd.RegisterFlagCompletionFunc("label", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return nil, cobra.ShellCompDirectiveNoFileComp + }) + if err != nil { + return nil, errors.Wrap(err, "register completion func for flag `label`") + } + return recoverCmd, nil +} + +func recoverResourceCommand(option *RecoverOptions, chaosType string, builder recover.RecovererBuilder) *cobra.Command { + return &cobra.Command{ + Use: fmt.Sprintf(`%s POD[,POD[,POD...]] [-n NAMESPACE]`, chaosType), + Short: fmt.Sprintf(`Recover %s from certain pods`, chaosType), + Long: fmt.Sprintf(`Recover %s from certain pods`, chaosType), + RunE: func(cmd *cobra.Command, args []string) error { + client, cancel, err := common.CreateClient(context.TODO(), managerNamespace, managerSvc) + if err != nil { + return err + } + defer cancel() + return option.Run(builder(client), client, args) + }, + SilenceErrors: true, + SilenceUsage: true, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return []string{}, cobra.ShellCompDirectiveNoFileComp + } + client, cancel, err := common.CreateClient(context.TODO(), managerNamespace, managerSvc) + if err != nil { + common.PrettyPrint(errors.Wrap(err, "create client").Error(), 0, common.Red) + return nil, cobra.ShellCompDirectiveNoFileComp + } + defer cancel() + return option.List(client) + }, + } +} + +// Run recover +func (o *RecoverOptions) Run(recover recover.Recoverer, client *ctrlclient.CtrlClient, args []string) error { + pods, err := o.selectPods(client, args) + if err != nil { + return err + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + for _, pod := range pods { + err = recover.Recover(ctx, pod) + if err != nil { + return err + } + } + return nil +} + +// List pods to recover +func (o *RecoverOptions) List(client *ctrlclient.CtrlClient) ([]string, cobra.ShellCompDirective) { + pods, err := o.selectPods(client, []string{}) + if err != nil { + common.PrettyPrint(errors.Wrap(err, "select pods").Error(), 0, common.Red) + return nil, cobra.ShellCompDirectiveNoFileComp + } + + var names []string + for _, pod := range pods { + names = append(names, pod.Name) + } + + return names, cobra.ShellCompDirectiveNoFileComp +} + +func (o *RecoverOptions) selectPods(client *ctrlclient.CtrlClient, names []string) ([]*recover.PartialPod, error) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + selector := v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{o.namespace}, + }, + } + + if len(names) != 0 { + selector.Pods = map[string][]string{o.namespace: names} + } + + if o.labels != nil && len(*o.labels) > 0 { + labels, err := label.ParseLabel(strings.Join(*o.labels, ",")) + if err != nil { + return nil, errors.Wrap(err, "parse labels") + } + if len(labels) != 0 { + selector.LabelSelectors = labels + } + } + + return recover.SelectPods(ctx, client, selector) +} diff --git a/pkg/chaosctl/cmd/root.go b/pkg/chaosctl/cmd/root.go index 5546b2bc57..1c72f5bb99 100644 --- a/pkg/chaosctl/cmd/root.go +++ b/pkg/chaosctl/cmd/root.go @@ -1,28 +1,33 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package cmd import ( - "fmt" - "log" "os" "github.com/spf13/cobra" cm "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/debug" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/recover" + "github.com/chaos-mesh/chaos-mesh/pkg/log" ) +var managerNamespace, managerSvc string + // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "chaosctl [command] [options]", @@ -34,50 +39,93 @@ Interacting with chaos mesh chaosctl debug networkchaos # show logs of all chaos-mesh components - chaosctl logs`, + chaosctl logs + + # forcedly recover chaos from pods + chaosctl recover networkchaos pod1 -n test`, } // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { - err := cm.SetupKlog() + rootLogger, err := log.NewDefaultZapLogger() if err != nil { - log.Fatal("failed to setup klog", err) + cm.PrettyPrint("failed to initialize logger: ", 0, cm.Red) + cm.PrettyPrint(err.Error(), 1, cm.Red) + os.Exit(1) } - rootLogger, flushFunc, err := cm.NewStderrLogger() + + rootCmd.PersistentFlags().StringVarP(&managerNamespace, "manager-namespace", "N", "chaos-mesh", "the namespace chaos-controller-manager in") + rootCmd.PersistentFlags().StringVarP(&managerSvc, "manager-svc", "s", "chaos-mesh-controller-manager", "the service to chaos-controller-manager") + err = rootCmd.RegisterFlagCompletionFunc("manager-namespace", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + // TODO: list namespaces without ctrlserver + return nil, cobra.ShellCompDirectiveNoFileComp + }) if err != nil { - log.Fatal("failed to initialize logger", err) + cm.PrettyPrint("failed to register completion function for flag 'manager-namespace': ", 0, cm.Red) + cm.PrettyPrint(err.Error(), 1, cm.Red) + os.Exit(1) } - if flushFunc != nil { - defer flushFunc() + err = rootCmd.RegisterFlagCompletionFunc("manager-svc", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + // TODO: list svc without ctrlserver + return nil, cobra.ShellCompDirectiveNoFileComp + }) + if err != nil { + cm.PrettyPrint("failed to register completion function for flag 'manager-svc': ", 0, cm.Red) + cm.PrettyPrint(err.Error(), 1, cm.Red) + os.Exit(1) } - cm.SetupGlobalLogger(rootLogger.WithName("global-logger")) - logsCmd, err := NewLogsCmd(rootLogger.WithName("cmd-logs")) + logsCmd, err := NewLogsCmd() if err != nil { - rootLogger.Error(err, "failed to initialize cmd", - "cmd", "logs", - "errorVerbose", fmt.Sprintf("%+v", err), - ) + cm.PrettyPrint("failed to initialize cmd: ", 0, cm.Red) + cm.PrettyPrint("log command: "+err.Error(), 1, cm.Red) os.Exit(1) } + rootCmd.AddCommand(logsCmd) - debugCommand, err := NewDebugCommand(rootLogger.WithName("cmd-debug")) + debugCommand, err := NewDebugCommand(rootLogger.WithName("cmd-debug"), map[string]debug.Debug{ + networkChaos: debug.NetworkDebug, + ioChaos: debug.IODebug, + stressChaos: debug.StressDebug, + httpChaos: debug.HTTPDebug, + }) if err != nil { - rootLogger.Error(err, "failed to initialize cmd", - "cmd", "debug", - "errorVerbose", fmt.Sprintf("%+v", err), - ) + cm.PrettyPrint("failed to initialize cmd: ", 0, cm.Red) + cm.PrettyPrint("debug command: "+err.Error(), 1, cm.Red) + os.Exit(1) + } + + recoverCommand, err := NewRecoverCommand(rootLogger.WithName("cmd-recover"), map[string]recover.RecovererBuilder{ + httpChaos: recover.HTTPRecoverer, + ioChaos: recover.IORecoverer, + stressChaos: recover.StressRecoverer, + networkChaos: recover.NetworkRecoverer, + }) + if err != nil { + cm.PrettyPrint("failed to initialize cmd: ", 0, cm.Red) + cm.PrettyPrint("recover command: "+err.Error(), 1, cm.Red) + os.Exit(1) + } + + physicalMachineCommand, err := NewPhysicalMachineCommand() + if err != nil { + cm.PrettyPrint("failed to initialize cmd: ", 0, cm.Red) + cm.PrettyPrint("physicalmachine command: "+err.Error(), 1, cm.Red) os.Exit(1) } rootCmd.AddCommand(debugCommand) + rootCmd.AddCommand(recoverCommand) rootCmd.AddCommand(completionCmd) + rootCmd.AddCommand(forwardCmd) + rootCmd.AddCommand(physicalMachineCommand) + if err := rootCmd.Execute(); err != nil { - rootLogger.Error(err, "failed to execute cmd", - "errorVerbose", fmt.Sprintf("%+v", err), - ) + cm.PrettyPrint("failed to execute cmd: ", 0, cm.Red) + cm.PrettyPrint(err.Error(), 1, cm.Red) + os.Exit(1) } } diff --git a/pkg/chaosctl/common/client.go b/pkg/chaosctl/common/client.go new file mode 100644 index 0000000000..d6b25fdd78 --- /dev/null +++ b/pkg/chaosctl/common/client.go @@ -0,0 +1,32 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package common + +import ( + "context" + "fmt" + + ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client" +) + +func CreateClient(ctx context.Context, managerNamespace, managerSvc string) (*ctrlclient.CtrlClient, context.CancelFunc, error) { + cancel, port, err := ctrlclient.ForwardCtrlServer(ctx, managerNamespace, managerSvc) + if err != nil { + return nil, nil, err + } + + return ctrlclient.NewCtrlClient(fmt.Sprintf("http://127.0.0.1:%d/query", port)), cancel, nil +} diff --git a/pkg/chaosctl/common/common.go b/pkg/chaosctl/common/common.go index 0bafe6d217..160a98f22c 100644 --- a/pkg/chaosctl/common/common.go +++ b/pkg/chaosctl/common/common.go @@ -1,37 +1,27 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package common import ( - "bytes" - "context" "encoding/json" "fmt" - "io" "regexp" - "strings" - "time" - - "google.golang.org/grpc" - - grpcUtils "github.com/chaos-mesh/chaos-mesh/pkg/grpc" - "github.com/chaos-mesh/chaos-mesh/pkg/mock" "github.com/fatih/color" "github.com/pkg/errors" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes" clientgoscheme "k8s.io/client-go/kubernetes/scheme" @@ -39,11 +29,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/config" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - ctrlconfig "github.com/chaos-mesh/chaos-mesh/controllers/config" - daemonClient "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/client" - "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" - "github.com/chaos-mesh/chaos-mesh/pkg/portforward" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" ) type Color string @@ -87,12 +72,6 @@ const ( ItemFailure ) -const ChaosDaemonClientCert = "chaos-mesh-daemon-client-certs" -const ChaosDaemonNamespace = "chaos-testing" - -var TLSFiles TLSFileConfig -var Insecure bool - type ItemResult struct { Name string Value string @@ -106,11 +85,6 @@ func init() { _ = clientgoscheme.AddToScheme(scheme) } -func upperCaseChaos(str string) string { - parts := regexp.MustCompile("(.*)(chaos)").FindStringSubmatch(str) - return strings.Title(parts[1]) + strings.Title(parts[2]) -} - // PrettyPrint print with tab number and color func PrettyPrint(s string, indentLevel int, color Color) { var tabStr string @@ -130,7 +104,7 @@ func PrettyPrint(s string, indentLevel int, color Color) { } // PrintResult prints result to users in prettier format -func PrintResult(result []ChaosResult) { +func PrintResult(result []*ChaosResult) { for _, chaos := range result { PrettyPrint("[Chaos]: "+chaos.Name, 0, Blue) for _, pod := range chaos.Pods { @@ -156,7 +130,7 @@ func PrintResult(result []ChaosResult) { func MarshalChaos(s interface{}) (string, error) { b, err := json.MarshalIndent(s, "", " ") if err != nil { - return "", errors.Wrapf(err, "failed to marshal indent") + return "", errors.Wrap(err, "failed to marshal indent") } return string(b), nil } @@ -169,7 +143,7 @@ func InitClientSet() (*ClientSet, error) { } ctrlClient, err := client.New(restconfig, client.Options{Scheme: scheme}) if err != nil { - return nil, fmt.Errorf("failed to create client") + return nil, errors.New("failed to create client") } kubeClient, err := kubernetes.NewForConfig(restconfig) if err != nil { @@ -177,303 +151,3 @@ func InitClientSet() (*ClientSet, error) { } return &ClientSet{ctrlClient, kubeClient}, nil } - -// GetPods returns pod list and corresponding chaos daemon -func GetPods(ctx context.Context, chaosName string, status v1alpha1.ChaosStatus, selectorSpec v1alpha1.SelectorSpec, c client.Client) ([]v1.Pod, []v1.Pod, error) { - // get podName - failedMessage := status.FailedMessage - if failedMessage != "" { - PrettyPrint(fmt.Sprintf("chaos %s failed with: %s", chaosName, failedMessage), 0, Red) - } - - phase := status.Experiment.Phase - nextStart := status.Scheduler.NextStart - - if phase == v1alpha1.ExperimentPhaseWaiting { - waitTime := nextStart.Sub(time.Now()) - L().WithName("GetPods").V(1).Info(fmt.Sprintf("Waiting for chaos %s to start, in %s\n", chaosName, waitTime)) - time.Sleep(waitTime) - } - - pods, err := selector.SelectPods(ctx, c, c, selectorSpec, ctrlconfig.ControllerCfg.ClusterScoped, ctrlconfig.ControllerCfg.TargetNamespace, ctrlconfig.ControllerCfg.EnableFilterNamespace) - if err != nil { - return nil, nil, errors.Wrap(err, "failed to SelectPods") - } - L().WithName("GetPods").V(4).Info("select pods for chaos", "chaos", chaosName, "pods", pods) - if len(pods) == 0 { - return nil, nil, fmt.Errorf("no pods found for chaos %s, selector: %s", chaosName, selectorSpec) - } - - // TODO: replace select daemon by - var chaosDaemons []v1.Pod - // get chaos daemon - for _, pod := range pods { - nodeName := pod.Spec.NodeName - daemonSelector := v1alpha1.SelectorSpec{ - Nodes: []string{nodeName}, - LabelSelectors: map[string]string{"app.kubernetes.io/component": "chaos-daemon"}, - } - daemons, err := selector.SelectPods(ctx, c, nil, daemonSelector, ctrlconfig.ControllerCfg.ClusterScoped, ctrlconfig.ControllerCfg.TargetNamespace, ctrlconfig.ControllerCfg.EnableFilterNamespace) - if err != nil { - return nil, nil, errors.Wrap(err, fmt.Sprintf("failed to select daemon pod for pod %s", pod.GetName())) - } - if len(daemons) == 0 { - return nil, nil, fmt.Errorf("no daemons found for pod %s with selector: %s", pod.GetName(), daemonSelector) - } - chaosDaemons = append(chaosDaemons, daemons[0]) - } - - return pods, chaosDaemons, nil -} - -// GetChaosList returns chaos list limited by input -func GetChaosList(ctx context.Context, chaosType string, chaosName string, ns string, c client.Client) ([]runtime.Object, []string, error) { - chaosType = upperCaseChaos(strings.ToLower(chaosType)) - allKinds := v1alpha1.AllKinds() - chaosListInterface := allKinds[chaosType].ChaosList - - if err := c.List(ctx, chaosListInterface, client.InNamespace(ns)); err != nil { - return nil, nil, errors.Wrapf(err, "failed to get chaosList with namespace %s", ns) - } - chaosList := chaosListInterface.ListChaos() - if len(chaosList) == 0 { - return nil, nil, fmt.Errorf("no chaos is found, please check your input") - } - - var retList []runtime.Object - var retNameList []string - for _, ch := range chaosList { - if chaosName == "" || chaosName == ch.Name { - chaos, err := getChaos(ctx, chaosType, ch.Name, ns, c) - if err != nil { - return nil, nil, err - } - retList = append(retList, chaos) - retNameList = append(retNameList, ch.Name) - } - } - if len(retList) == 0 { - return nil, nil, fmt.Errorf("no chaos is found, please check your input") - } - - return retList, retNameList, nil -} - -func getChaos(ctx context.Context, chaosType string, chaosName string, ns string, c client.Client) (runtime.Object, error) { - allKinds := v1alpha1.AllKinds() - chaos := allKinds[chaosType].Chaos - objectKey := client.ObjectKey{ - Namespace: ns, - Name: chaosName, - } - if err := c.Get(ctx, objectKey, chaos); err != nil { - return nil, errors.Wrapf(err, "failed to get chaos %s", chaosName) - } - return chaos, nil -} - -// GetPidFromPS returns pid-command pairs -func GetPidFromPS(ctx context.Context, pod v1.Pod, daemon v1.Pod, c *kubernetes.Clientset) ([]string, []string, error) { - cmd := "ps" - out, err := ExecBypass(ctx, pod, daemon, cmd, c) - if err != nil { - return nil, nil, errors.Wrapf(err, "run command %s failed", cmd) - } - outLines := strings.Split(string(out), "\n") - if len(outLines) < 2 { - return nil, nil, fmt.Errorf("ps returns empty") - } - titles := strings.Fields(outLines[0]) - var pidColumn, cmdColumn int - for i, t := range titles { - if t == "PID" { - pidColumn = i - } - if t == "COMMAND" || t == "CMD" { - cmdColumn = i - } - } - if pidColumn == 0 && cmdColumn == 0 { - return nil, nil, fmt.Errorf("parsing ps error: could not get PID and COMMAND column") - } - var pids, commands []string - for _, line := range outLines[1:] { - item := strings.Fields(line) - // break when got empty line - if len(item) == 0 { - break - } - pids = append(pids, item[pidColumn]) - commands = append(commands, item[cmdColumn]) - } - return pids, commands, nil -} - -// GetPidFromPod returns pid given containerd ID in pod -func GetPidFromPod(ctx context.Context, pod v1.Pod, daemon v1.Pod) (uint32, error) { - pfCancel, localPort, err := forwardPorts(ctx, daemon, uint16(ctrlconfig.ControllerCfg.ChaosDaemonPort)) - if err != nil { - return 0, errors.Wrapf(err, "forward ports for daemon pod %s/%s failed", daemon.Namespace, daemon.Name) - } - L().WithName("GetPidFromPod").V(4).Info(fmt.Sprintf("port forwarding 127.0.0.1:%d -> pod/%s/%s:%d", localPort, daemon.Namespace, daemon.Name, ctrlconfig.ControllerCfg.ChaosDaemonPort)) - - defer func() { - pfCancel() - }() - - daemonClient, err := ConnectToLocalChaosDaemon(int(localPort)) - if err != nil { - return 0, errors.Wrapf(err, "failed to create new chaos daemon client with local port %d", localPort) - } - defer daemonClient.Close() - - if len(pod.Status.ContainerStatuses) == 0 { - return 0, fmt.Errorf("%s %s can't get the state of container", pod.Namespace, pod.Name) - } - - res, err := daemonClient.ContainerGetPid(ctx, &pb.ContainerRequest{ - Action: &pb.ContainerAction{ - Action: pb.ContainerAction_GETPID, - }, - ContainerId: pod.Status.ContainerStatuses[0].ContainerID, - }) - if err != nil { - return 0, errors.Wrapf(err, "failed get pid from pod %s/%s", pod.GetNamespace(), pod.GetName()) - } - return res.Pid, nil -} - -func forwardPorts(ctx context.Context, pod v1.Pod, port uint16) (context.CancelFunc, uint16, error) { - commonRestClientGetter := NewCommonRestClientGetter() - fw, err := portforward.NewPortForwarder(ctx, commonRestClientGetter, false) - if err != nil { - return nil, 0, errors.Wrap(err, "failed to create port forwarder") - } - _, localPort, pfCancel, err := portforward.ForwardOnePort(fw, pod.Namespace, pod.Name, port) - return pfCancel, localPort, err -} - -// Log print log of pod -func Log(pod v1.Pod, tail int64, c *kubernetes.Clientset) (string, error) { - podLogOpts := v1.PodLogOptions{} - //use negative tail to indicate no tail limit is needed - if tail >= 0 { - podLogOpts.TailLines = func(i int64) *int64 { return &i }(tail) - } - - req := c.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &podLogOpts) - podLogs, err := req.Stream() - if err != nil { - return "", errors.Wrapf(err, "failed to open log stream for pod %s/%s", pod.GetNamespace(), pod.GetName()) - } - defer podLogs.Close() - - buf := new(bytes.Buffer) - _, err = io.Copy(buf, podLogs) - if err != nil { - return "", errors.Wrapf(err, "failed to copy information from podLogs to buf") - } - return buf.String(), nil -} - -// CheckFailedMessage provide debug info and suggestions from failed message -func CheckFailedMessage(ctx context.Context, failedMessage string, daemons []v1.Pod, c *ClientSet) error { - if strings.Contains(failedMessage, "rpc error: code = Unavailable desc = connection error") || strings.Contains(failedMessage, "connect: connection refused") { - if err := checkConnForCtrlAndDaemon(ctx, daemons, c); err != nil { - return fmt.Errorf("error occurs when check failed message: %s", err) - } - } - return nil -} - -func checkConnForCtrlAndDaemon(ctx context.Context, daemons []v1.Pod, c *ClientSet) error { - ctrlSelector := v1alpha1.SelectorSpec{ - LabelSelectors: map[string]string{"app.kubernetes.io/component": "controller-manager"}, - } - ctrlMgrs, err := selector.SelectPods(ctx, c.CtrlCli, c.CtrlCli, ctrlSelector, ctrlconfig.ControllerCfg.ClusterScoped, ctrlconfig.ControllerCfg.TargetNamespace, ctrlconfig.ControllerCfg.EnableFilterNamespace) - if err != nil { - return errors.Wrapf(err, "failed to select pod for controller-manager") - } - if len(ctrlMgrs) == 0 { - return fmt.Errorf("could not found controller manager") - } - for _, daemon := range daemons { - daemonIP := daemon.Status.PodIP - cmd := fmt.Sprintf("ping -c 1 %s > /dev/null; echo $?", daemonIP) - out, err := Exec(ctx, ctrlMgrs[0], cmd, c.KubeCli) - if err != nil { - return errors.Wrapf(err, "run command %s failed", cmd) - } - if string(out) == "0" { - PrettyPrint(fmt.Sprintf("Connection between Controller-Manager and Daemon %s (ip address: %s) works well", daemon.Name, daemonIP), 0, Green) - } else { - PrettyPrint(fmt.Sprintf(`Connection between Controller-Manager and Daemon %s (ip address: %s) is blocked. -Please check network policy / firewall, or see FAQ on website`, daemon.Name, daemonIP), 0, Red) - } - - } - return nil -} - -// ConnectToLocalChaosDaemon would connect to ChaosDaemon run in localhost -func ConnectToLocalChaosDaemon(port int) (daemonClient.ChaosDaemonClientInterface, error) { - if cli := mock.On("MockChaosDaemonClient"); cli != nil { - return cli.(daemonClient.ChaosDaemonClientInterface), nil - } - if err := mock.On("NewChaosDaemonClientError"); err != nil { - return nil, err.(error) - } - cc, err := getGrpcClient(port) - - if err != nil { - return nil, err - } - return daemonClient.New(cc), nil -} - -func getGrpcClient(port int) (*grpc.ClientConn, error) { - if Insecure { - return grpcUtils.CreateGrpcConnection("localhost", port, "", "", "") - } - if TLSFiles.CaCert == "" || TLSFiles.Cert == "" || TLSFiles.Key == "" { - PrettyPrint("TLS Files are not complete, fall back to use secrets.", 0, Green) - config, err := getTLSConfigFromSecrets() - if err != nil { - return nil, err - } - return grpcUtils.CreateGrpcConnectionFromRaw("localhost", port, config.caCert, config.cert, config.key) - } - PrettyPrint("Using TLS Files.", 0, Green) - return grpcUtils.CreateGrpcConnection("localhost", port, TLSFiles.CaCert, TLSFiles.Cert, TLSFiles.Key) -} - -func getTLSConfigFromSecrets() (*rawTLSConfig, error) { - var cfg rawTLSConfig - restconfig, err := config.GetConfig() - if err != nil { - return nil, err - } - kubeClient, err := kubernetes.NewForConfig(restconfig) - if err != nil { - return nil, err - } - secret, err := kubeClient.CoreV1().Secrets(ChaosDaemonNamespace).Get(ChaosDaemonClientCert, metav1.GetOptions{}) - if err != nil { - return nil, err - } - cfg.caCert = secret.Data["ca.crt"] - cfg.cert = secret.Data["tls.crt"] - cfg.key = secret.Data["tls.key"] - return &cfg, nil -} - -type rawTLSConfig struct { - caCert []byte - cert []byte - key []byte -} -type TLSFileConfig struct { - CaCert string - Cert string - Key string -} diff --git a/pkg/chaosctl/common/common_rest_client_getter.go b/pkg/chaosctl/common/common_rest_client_getter.go deleted file mode 100644 index df8888d598..0000000000 --- a/pkg/chaosctl/common/common_rest_client_getter.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package common - -import ( - "sigs.k8s.io/controller-runtime/pkg/client/config" - - "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/client-go/rest" -) - -// CommonRestClientGetter is used for non-e2e test environment. -// It's basically do the same thing as genericclioptions.ConfigFlags, but it load rest config from incluster or .kubeconfig file -type CommonRestClientGetter struct { - *genericclioptions.ConfigFlags -} - -func NewCommonRestClientGetter() *CommonRestClientGetter { - innerConfigFlags := genericclioptions.NewConfigFlags(false) - return &CommonRestClientGetter{innerConfigFlags} -} - -func (it *CommonRestClientGetter) ToRESTConfig() (*rest.Config, error) { - return config.GetConfig() -} diff --git a/pkg/chaosctl/common/common_test.go b/pkg/chaosctl/common/common_test.go deleted file mode 100644 index 872b038b78..0000000000 --- a/pkg/chaosctl/common/common_test.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package common - -import ( - "context" - "testing" - "time" - - . "github.com/onsi/gomega" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - kubectlscheme "k8s.io/kubectl/pkg/scheme" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/utils" -) - -func TestGetChaosList(t *testing.T) { - logger, _, _ := NewStderrLogger() - SetupGlobalLogger(logger) - - g := NewWithT(t) - - chaos1 := v1alpha1.NetworkChaos{ - TypeMeta: metav1.TypeMeta{ - Kind: "NetworkChaos", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "fakechaos-1", - }, - } - - chaos2 := v1alpha1.NetworkChaos{ - TypeMeta: metav1.TypeMeta{ - Kind: "NetworkChaos", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "fakechaos-2", - }, - } - - v1alpha1.SchemeBuilder.AddToScheme(kubectlscheme.Scheme) - - client := fake.NewFakeClientWithScheme(kubectlscheme.Scheme, &chaos1, &chaos2) - - tests := []struct { - name string - chaosType string - chaosName string - ns string - expectedNum int - expectedErr bool - }{ - { - name: "Only specify chaosType", - chaosType: "networkchaos", - chaosName: "", - ns: "default", - expectedNum: 2, - expectedErr: false, - }, - { - name: "Specify chaos type, chaos name and namespace", - chaosType: "networkchaos", - chaosName: "fakechaos-1", - ns: "default", - expectedNum: 1, - expectedErr: false, - }, - { - name: "Specify non-exist chaos name", - chaosType: "networkchaos", - chaosName: "fakechaos-oops", - ns: "default", - expectedErr: true, - }, - { - name: "Specify non-exist chaos types", - chaosType: "stresschaos", - chaosName: "fakechaos-1", - ns: "default", - expectedErr: true, - }, - { - name: "Specify non-exist namespace", - chaosType: "networkchaos", - chaosName: "fakechaos-1", - ns: "oops", - expectedErr: true, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - chaos, _, err := GetChaosList(context.Background(), test.chaosType, test.chaosName, test.ns, client) - if test.expectedErr { - g.Expect(err).NotTo(BeNil()) - } else { - g.Expect(err).To(BeNil()) - g.Expect(len(chaos)).To(Equal(test.expectedNum)) - } - }) - } -} - -func TestGetPods(t *testing.T) { - logger, _, _ := NewStderrLogger() - SetupGlobalLogger(logger) - - g := NewWithT(t) - - _ = v1alpha1.ChaosStatus{ - Experiment: v1alpha1.ExperimentStatus{ - Phase: v1alpha1.ExperimentPhaseRunning, - }, - Scheduler: v1alpha1.ScheduleStatus{}, - } - - nodeObjects, _ := utils.GenerateNNodes("node", 2, nil) - podObjects0, _ := utils.GenerateNPods("pod-node0", 1, utils.PodArg{Labels: map[string]string{"app": "pod"}, Nodename: "node0"}) - podObjects1, _ := utils.GenerateNPods("pod-node1", 1, utils.PodArg{Labels: map[string]string{"app": "pod"}, Nodename: "node1"}) - daemonObjects0, _ := utils.GenerateNPods("daemon-node0", 1, utils.PodArg{Labels: map[string]string{"app.kubernetes.io/component": "chaos-daemon"}, Nodename: "node0"}) - daemonObjects1, _ := utils.GenerateNPods("daemon-node1", 1, utils.PodArg{Labels: map[string]string{"app.kubernetes.io/component": "chaos-daemon"}, Nodename: "node1"}) - - allObjects := append(nodeObjects, daemonObjects0[0], podObjects0[0], daemonObjects1[0], podObjects1[0]) - - v1alpha1.SchemeBuilder.AddToScheme(kubectlscheme.Scheme) - client := fake.NewFakeClientWithScheme(kubectlscheme.Scheme, allObjects...) - - tests := []struct { - name string - chaosSelector v1alpha1.SelectorSpec - chaosStatus v1alpha1.ChaosStatus - wait bool - expectedPodNum int - expectedDaemonNum int - expectedErr bool - }{ - { - name: "chaos on two pods", - chaosSelector: v1alpha1.SelectorSpec{LabelSelectors: map[string]string{"app": "pod"}}, - chaosStatus: v1alpha1.ChaosStatus{}, - expectedPodNum: 2, - expectedDaemonNum: 2, - expectedErr: false, - }, - { - name: "chaos on one pod", - chaosSelector: v1alpha1.SelectorSpec{ - Nodes: []string{"node0"}, - LabelSelectors: map[string]string{"app": "pod"}, - }, - chaosStatus: v1alpha1.ChaosStatus{}, - expectedPodNum: 1, - expectedDaemonNum: 1, - expectedErr: false, - }, - { - name: "wait for 100ms for chaos to start", - chaosSelector: v1alpha1.SelectorSpec{LabelSelectors: map[string]string{"app": "pod"}}, - chaosStatus: v1alpha1.ChaosStatus{ - Experiment: v1alpha1.ExperimentStatus{ - Phase: v1alpha1.ExperimentPhaseWaiting, - }, - Scheduler: v1alpha1.ScheduleStatus{ - NextStart: &metav1.Time{Time: time.Now().Add(time.Millisecond * 50)}, - }, - }, - wait: true, - expectedPodNum: 2, - expectedDaemonNum: 2, - expectedErr: false, - }, - { - name: "wrong selector to get pod", - chaosSelector: v1alpha1.SelectorSpec{LabelSelectors: map[string]string{"app": "oops"}}, - chaosStatus: v1alpha1.ChaosStatus{}, - expectedErr: true, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - timeBefore := time.Now() - pods, daemons, err := GetPods(context.Background(), test.name, test.chaosStatus, test.chaosSelector, client) - if test.wait { - g.Expect(time.Now().Add(time.Millisecond * -50).Before(timeBefore)).To(BeTrue()) - } - if test.expectedErr { - g.Expect(err).NotTo(BeNil()) - } else { - g.Expect(err).To(BeNil()) - g.Expect(len(pods)).To(Equal(test.expectedPodNum)) - g.Expect(len(daemons)).To(Equal(test.expectedDaemonNum)) - } - }) - } -} diff --git a/pkg/chaosctl/common/exec.go b/pkg/chaosctl/common/exec.go deleted file mode 100644 index 2ee579cf37..0000000000 --- a/pkg/chaosctl/common/exec.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package common - -import ( - "bytes" - "context" - "fmt" - "io/ioutil" - "strings" - - "github.com/pkg/errors" - - "google.golang.org/grpc/grpclog" - v1 "k8s.io/api/core/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/remotecommand" - kubectlscheme "k8s.io/kubectl/pkg/scheme" - "sigs.k8s.io/controller-runtime/pkg/client/config" - - "github.com/chaos-mesh/chaos-mesh/pkg/bpm" -) - -// Exec executes certain command and returns the result -// Only commands in chaos-mesh components should use this way -// for target pod, use ExecBypass -func Exec(ctx context.Context, pod v1.Pod, cmd string, c *kubernetes.Clientset) (string, error) { - name := pod.GetObjectMeta().GetName() - namespace := pod.GetObjectMeta().GetNamespace() - // TODO: if `containerNames` is set and specific container is injected chaos, - // need to use THE name rather than the first one. - // till 20/11/10 only podchaos and kernelchaos support `containerNames`, so not set it for now - containerName := pod.Spec.Containers[0].Name - - req := c.CoreV1().RESTClient().Post(). - Resource("pods"). - Name(name). - Namespace(namespace). - SubResource("exec") - - req.VersionedParams(&v1.PodExecOptions{ - Container: containerName, - Command: []string{"/bin/sh", "-c", cmd}, - Stdin: false, - Stdout: true, - Stderr: true, - TTY: false, - }, kubectlscheme.ParameterCodec) - - var stdout, stderr bytes.Buffer - exec, err := remotecommand.NewSPDYExecutor(config.GetConfigOrDie(), "POST", req.URL()) - if err != nil { - return "", errors.Wrapf(err, "error in creating NewSPDYExecutor for pod %s/%s", pod.GetNamespace(), pod.GetName()) - } - err = exec.Stream(remotecommand.StreamOptions{ - Stdin: nil, - Stdout: &stdout, - Stderr: &stderr, - }) - if err != nil { - if stderr.String() != "" { - return "", fmt.Errorf("error: %s\npod: %s\ncommand: %s", strings.TrimSuffix(stderr.String(), "\n"), pod.Name, cmd) - } - return "", errors.Wrapf(err, "error in streaming remotecommand: pod: %s/%s, command: %s", pod.GetNamespace(), pod.Name, cmd) - } - if stderr.String() != "" { - return "", fmt.Errorf("error of command %s: %s", cmd, stderr.String()) - } - return stdout.String(), nil -} - -// ExecBypass use chaos-daemon to enter namespace and execute command in target pod -func ExecBypass(ctx context.Context, pod v1.Pod, daemon v1.Pod, cmd string, c *kubernetes.Clientset) (string, error) { - // To disable printing irrelevant log from grpc/clientconn.go - // See grpc/grpc-go#3918 for detail. Could be resolved in the future - grpclog.SetLoggerV2(grpclog.NewLoggerV2(ioutil.Discard, ioutil.Discard, ioutil.Discard)) - pid, err := GetPidFromPod(ctx, pod, daemon) - if err != nil { - return "", err - } - // enter all possible namespaces needed, since there's no bad effect to do so - cmdBuilder := bpm.DefaultProcessBuilder(cmd).SetNS(pid, bpm.MountNS).SetNS(pid, bpm.PidNS).SetContext(ctx) - return Exec(ctx, daemon, cmdBuilder.Build().Cmd.String(), c) -} diff --git a/pkg/chaosctl/common/logger.go b/pkg/chaosctl/common/logger.go deleted file mode 100644 index 4d316ef783..0000000000 --- a/pkg/chaosctl/common/logger.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package common - -import ( - "flag" - - "github.com/go-logr/logr" - "github.com/spf13/pflag" - "k8s.io/klog" - "k8s.io/klog/klogr" -) - -type LoggerFlushFunc func() - -func SetupKlog() error { - // setup klog - klog.InitFlags(flag.CommandLine) - pflag.CommandLine.AddGoFlagSet(flag.CommandLine) - return flag.Set("logtostderr", "true") -} - -func NewStderrLogger() (logr.Logger, LoggerFlushFunc, error) { - logger := klogr.New() - return logger, klog.Flush, nil -} - -var globalLogger logr.Logger - -func SetupGlobalLogger(logger logr.Logger) { - globalLogger = logger -} - -func L() logr.Logger { - if globalLogger == nil { - panic("global logger not initialized") - } - return globalLogger -} diff --git a/pkg/chaosctl/debug/debug.go b/pkg/chaosctl/debug/debug.go new file mode 100644 index 0000000000..e2ae278a61 --- /dev/null +++ b/pkg/chaosctl/debug/debug.go @@ -0,0 +1,33 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package debug + +import ( + "context" + + "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" + ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client" +) + +type Debugger interface { + // Collect collect debug information of chaos + Collect(ctx context.Context, namespace, chaosName string) ([]*common.ChaosResult, error) + + // List chaos names to collect + List(ctx context.Context, namespace string) ([]string, error) +} + +type Debug func(client *ctrlclient.CtrlClient) Debugger diff --git a/pkg/chaosctl/debug/httpchaos.go b/pkg/chaosctl/debug/httpchaos.go new file mode 100644 index 0000000000..30bf0fb342 --- /dev/null +++ b/pkg/chaosctl/debug/httpchaos.go @@ -0,0 +1,147 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package debug + +import ( + "context" + "fmt" + "strings" + + "github.com/hasura/go-graphql-client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" + ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client" +) + +type httpDebugger struct { + client *ctrlclient.CtrlClient +} + +func HTTPDebug(client *ctrlclient.CtrlClient) Debugger { + return &httpDebugger{ + client: client, + } +} + +func (d *httpDebugger) Collect(ctx context.Context, namespace, chaosName string) ([]*common.ChaosResult, error) { + var results []*common.ChaosResult + + var name *graphql.String + if chaosName != "" { + n := graphql.String(chaosName) + name = &n + } + + var query struct { + Namespace []struct { + HTTPChaos []struct { + Name string + Podhttp []struct { + Namespace string + Name string + Spec *v1alpha1.PodHttpChaosSpec + Pod struct { + Iptables []string + Processes []struct { + Pid string + Command string + Fds []struct { + Fd, Target string + } + } + } + } + } `graphql:"httpchaos(name: $name)"` + } `graphql:"namespace(ns: $namespace)"` + } + + variables := map[string]interface{}{ + "namespace": graphql.String(namespace), + "name": name, + } + + err := d.client.QueryClient.Query(ctx, &query, variables) + if err != nil { + return nil, err + } + + if len(query.Namespace) == 0 { + return results, nil + } + + for _, httpChaos := range query.Namespace[0].HTTPChaos { + result := &common.ChaosResult{ + Name: string(httpChaos.Name), + } + + for _, podhttpchaos := range httpChaos.Podhttp { + podResult := common.PodResult{ + Name: string(podhttpchaos.Name), + } + + podResult.Items = append(podResult.Items, common.ItemResult{Name: "iptables list", Value: strings.Join(podhttpchaos.Pod.Iptables, "\n")}) + for _, process := range podhttpchaos.Pod.Processes { + var fds []string + for _, fd := range process.Fds { + fds = append(fds, fmt.Sprintf("%s -> %s", fd.Fd, fd.Target)) + } + podResult.Items = append(podResult.Items, common.ItemResult{ + Name: fmt.Sprintf("file descriptors of PID: %s, COMMAND: %s", process.Pid, process.Command), + Value: strings.Join(fds, "\n"), + }) + } + output, err := common.MarshalChaos(podhttpchaos.Spec) + if err != nil { + return nil, err + } + podResult.Items = append(podResult.Items, common.ItemResult{Name: "podhttpchaos", Value: output}) + result.Pods = append(result.Pods, podResult) + } + + results = append(results, result) + } + return results, nil +} + +func (d *httpDebugger) List(ctx context.Context, namespace string) ([]string, error) { + var query struct { + Namespace []struct { + HTTPChaos []struct { + Name string + } `graphql:"httpchaos"` + } `graphql:"namespace(ns: $namespace)"` + } + + variables := map[string]interface{}{ + "namespace": graphql.String(namespace), + } + + err := d.client.QueryClient.Query(ctx, &query, variables) + if err != nil { + return nil, err + } + + if len(query.Namespace) == 0 { + return nil, nil + } + + var names []string + for _, httpChaos := range query.Namespace[0].HTTPChaos { + names = append(names, string(httpChaos.Name)) + } + return names, nil +} diff --git a/pkg/chaosctl/debug/iochaos.go b/pkg/chaosctl/debug/iochaos.go new file mode 100644 index 0000000000..b560923eb5 --- /dev/null +++ b/pkg/chaosctl/debug/iochaos.go @@ -0,0 +1,172 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package debug + +import ( + "context" + "fmt" + "strings" + + "github.com/hasura/go-graphql-client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" + ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client" +) + +type ioDebugger struct { + client *ctrlclient.CtrlClient +} + +func IODebug(client *ctrlclient.CtrlClient) Debugger { + return &ioDebugger{ + client: client, + } +} + +func (d *ioDebugger) Collect(ctx context.Context, namespace, chaosName string) ([]*common.ChaosResult, error) { + var results []*common.ChaosResult + + var name *graphql.String + if chaosName != "" { + n := graphql.String(chaosName) + name = &n + } + + var query struct { + Namespace []struct { + IOChaos []struct { + Name string + Podios []struct { + Namespace string + Name string + // TODO: fit types with v1alpha1.PodIOChaosSpec + Spec struct { + VolumeMountPath string + Container *string + Actions []struct { + Type v1alpha1.IOChaosType + v1alpha1.Filter `json:",inline"` + Faults []v1alpha1.IoFault + Latency string + Ino *uint64 `json:"ino,omitempty"` + Size *uint64 `json:"size,omitempty"` + Blocks *uint64 `json:"blocks,omitempty"` + Atime *v1alpha1.Timespec `json:"atime,omitempty"` + Mtime *v1alpha1.Timespec `json:"mtime,omitempty"` + Ctime *v1alpha1.Timespec `json:"ctime,omitempty"` + Kind *v1alpha1.FileType `json:"kind,omitempty"` + Perm *uint `json:"perm,omitempty"` + Nlink *uint `json:"nlink,omitempty"` + UID *uint `json:"uid,omitempty"` + GID *uint `json:"gid,omitempty"` + Rdev *uint `json:"rdev,omitempty"` + Filling *v1alpha1.FillingType `json:"filling,omitempty"` + MaxOccurrences *int64 `json:"maxOccurrences,omitempty"` + MaxLength *int64 `json:"maxLength,omitempty"` + } + } + Pod struct { + Mounts []string + Processes []struct { + Pid string + Command string + Fds []struct { + Fd, Target string + } + } + } + } + } `graphql:"iochaos(name: $name)"` + } `graphql:"namespace(ns: $namespace)"` + } + + variables := map[string]interface{}{ + "namespace": graphql.String(namespace), + "name": name, + } + + err := d.client.QueryClient.Query(ctx, &query, variables) + if err != nil { + return nil, err + } + + if len(query.Namespace) == 0 { + return results, nil + } + + for _, ioChaos := range query.Namespace[0].IOChaos { + result := &common.ChaosResult{ + Name: ioChaos.Name, + } + + for _, podiochaos := range ioChaos.Podios { + podResult := common.PodResult{ + Name: podiochaos.Name, + } + + podResult.Items = append(podResult.Items, common.ItemResult{Name: "Mount Information", Value: strings.Join(podiochaos.Pod.Mounts, "\n")}) + for _, process := range podiochaos.Pod.Processes { + var fds []string + for _, fd := range process.Fds { + fds = append(fds, fmt.Sprintf("%s -> %s", fd.Fd, fd.Target)) + } + podResult.Items = append(podResult.Items, common.ItemResult{ + Name: fmt.Sprintf("file descriptors of PID: %s, COMMAND: %s", process.Pid, process.Command), + Value: strings.Join(fds, "\n"), + }) + } + output, err := common.MarshalChaos(podiochaos.Spec) + if err != nil { + return nil, err + } + podResult.Items = append(podResult.Items, common.ItemResult{Name: "podiochaos", Value: output}) + result.Pods = append(result.Pods, podResult) + } + + results = append(results, result) + } + return results, nil +} + +func (d *ioDebugger) List(ctx context.Context, namespace string) ([]string, error) { + var query struct { + Namespace []struct { + IOChaos []struct { + Name string + } `graphql:"iochaos"` + } `graphql:"namespace(ns: $namespace)"` + } + + variables := map[string]interface{}{ + "namespace": graphql.String(namespace), + } + + err := d.client.QueryClient.Query(ctx, &query, variables) + if err != nil { + return nil, err + } + + if len(query.Namespace) == 0 { + return nil, nil + } + + var names []string + for _, ioChaos := range query.Namespace[0].IOChaos { + names = append(names, string(ioChaos.Name)) + } + return names, nil +} diff --git a/pkg/chaosctl/debug/iochaos/iochaos.go b/pkg/chaosctl/debug/iochaos/iochaos.go deleted file mode 100644 index 049091a193..0000000000 --- a/pkg/chaosctl/debug/iochaos/iochaos.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package iochaos - -import ( - "context" - "fmt" - - "github.com/pkg/errors" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - cm "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" -) - -// Debug get chaos debug information -func Debug(ctx context.Context, chaos runtime.Object, c *cm.ClientSet, result *cm.ChaosResult) error { - ioChaos, ok := chaos.(*v1alpha1.IoChaos) - if !ok { - return fmt.Errorf("chaos is not iochaos") - } - chaosStatus := ioChaos.Status.ChaosStatus - chaosSelector := ioChaos.Spec.GetSelector() - - pods, daemons, err := cm.GetPods(ctx, ioChaos.GetName(), chaosStatus, chaosSelector, c.CtrlCli) - if err != nil { - return err - } - - if err := cm.CheckFailedMessage(ctx, chaosStatus.FailedMessage, daemons, c); err != nil { - return err - } - - for i := range pods { - podName := pods[i].Name - podResult := cm.PodResult{Name: podName} - _ = debugEachPod(ctx, pods[i], daemons[i], ioChaos, c, &podResult) - result.Pods = append(result.Pods, podResult) - // TODO: V(4) log when err != nil, wait for #1433 - } - return nil -} - -func debugEachPod(ctx context.Context, pod v1.Pod, daemon v1.Pod, chaos *v1alpha1.IoChaos, c *cm.ClientSet, result *cm.PodResult) error { - // print out debug info - cmd := "cat /proc/mounts" - out, err := cm.ExecBypass(ctx, pod, daemon, cmd, c.KubeCli) - if err != nil { - return errors.Wrapf(err, "run command '%s' failed", cmd) - } - result.Items = append(result.Items, cm.ItemResult{Name: "mount information", Value: string(out)}) - - pids, commands, err := cm.GetPidFromPS(ctx, pod, daemon, c.KubeCli) - if err != nil { - return errors.Wrapf(err, "get pid for pod %s/%s from ps failed", pod.GetNamespace(), pod.GetName()) - } - - for i := range pids { - cmd = fmt.Sprintf("ls -l /proc/%s/fd", pids[i]) - out, err = cm.ExecBypass(ctx, pod, daemon, cmd, c.KubeCli) - - var itemValue string - if err != nil { - itemValue = err.Error() - } else { - itemValue = string(out) - } - result.Items = append(result.Items, cm.ItemResult{Name: fmt.Sprintf("file descriptors of PID: %s, COMMAND: %s", pids[i], commands[i]), Value: itemValue}) - } - - return nil -} diff --git a/pkg/chaosctl/debug/networkchaos.go b/pkg/chaosctl/debug/networkchaos.go new file mode 100644 index 0000000000..d98c1fc351 --- /dev/null +++ b/pkg/chaosctl/debug/networkchaos.go @@ -0,0 +1,133 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package debug + +import ( + "context" + "strings" + + "github.com/hasura/go-graphql-client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" + ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client" +) + +type networkDebugger struct { + client *ctrlclient.CtrlClient +} + +func NetworkDebug(client *ctrlclient.CtrlClient) Debugger { + return &networkDebugger{ + client: client, + } +} + +func (d *networkDebugger) Collect(ctx context.Context, namespace, chaosName string) ([]*common.ChaosResult, error) { + var results []*common.ChaosResult + + var name *graphql.String + if chaosName != "" { + n := graphql.String(chaosName) + name = &n + } + + var query struct { + Namespace []struct { + NetworkChaos []struct { + Name string + Podnetwork []struct { + Spec *v1alpha1.PodNetworkChaosSpec + Namespace string + Name string + Pod struct { + Ipset string + TcQdisc []string + Iptables []string + } + } + } `graphql:"networkchaos(name: $name)"` + } `graphql:"namespace(ns: $namespace)"` + } + + variables := map[string]interface{}{ + "namespace": graphql.String(namespace), + "name": name, + } + + err := d.client.QueryClient.Query(ctx, &query, variables) + if err != nil { + return nil, err + } + + if len(query.Namespace) == 0 { + return results, nil + } + + for _, networkChaos := range query.Namespace[0].NetworkChaos { + result := &common.ChaosResult{ + Name: networkChaos.Name, + } + + for _, podNetworkChaos := range networkChaos.Podnetwork { + podResult := common.PodResult{ + Name: podNetworkChaos.Name, + } + + podResult.Items = append(podResult.Items, common.ItemResult{Name: "ipset list", Value: podNetworkChaos.Pod.Ipset}) + podResult.Items = append(podResult.Items, common.ItemResult{Name: "tc qdisc list", Value: strings.Join(podNetworkChaos.Pod.TcQdisc, "\n")}) + podResult.Items = append(podResult.Items, common.ItemResult{Name: "iptables list", Value: strings.Join(podNetworkChaos.Pod.Iptables, "\n")}) + output, err := common.MarshalChaos(podNetworkChaos.Spec) + if err != nil { + return nil, err + } + podResult.Items = append(podResult.Items, common.ItemResult{Name: "podnetworkchaos", Value: output}) + result.Pods = append(result.Pods, podResult) + } + + results = append(results, result) + } + return results, nil +} + +func (d *networkDebugger) List(ctx context.Context, namespace string) ([]string, error) { + var query struct { + Namespace []struct { + NetworkChaos []struct { + Name string + } `graphql:"networkchaos"` + } `graphql:"namespace(ns: $namespace)"` + } + + variables := map[string]interface{}{ + "namespace": graphql.String(namespace), + } + + err := d.client.QueryClient.Query(ctx, &query, variables) + if err != nil { + return nil, err + } + + if len(query.Namespace) == 0 { + return nil, nil + } + + var names []string + for _, networkChaos := range query.Namespace[0].NetworkChaos { + names = append(names, string(networkChaos.Name)) + } + return names, nil +} diff --git a/pkg/chaosctl/debug/networkchaos/networkchaos.go b/pkg/chaosctl/debug/networkchaos/networkchaos.go deleted file mode 100644 index ae55576b34..0000000000 --- a/pkg/chaosctl/debug/networkchaos/networkchaos.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package networkchaos - -import ( - "context" - "fmt" - "io/ioutil" - "regexp" - "strconv" - "strings" - - "github.com/pkg/errors" - - "google.golang.org/grpc/grpclog" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - cm "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" -) - -// Debug get chaos debug information -func Debug(ctx context.Context, chaos runtime.Object, c *cm.ClientSet, result *cm.ChaosResult) error { - networkChaos, ok := chaos.(*v1alpha1.NetworkChaos) - if !ok { - return fmt.Errorf("chaos is not network") - } - chaosStatus := networkChaos.Status.ChaosStatus - chaosSelector := networkChaos.Spec.GetSelector() - - pods, daemons, err := cm.GetPods(ctx, networkChaos.GetName(), chaosStatus, chaosSelector, c.CtrlCli) - if err != nil { - return err - } - - if err := cm.CheckFailedMessage(ctx, chaosStatus.FailedMessage, daemons, c); err != nil { - return err - } - - for i := range pods { - podName := pods[i].Name - podResult := cm.PodResult{Name: podName} - err = debugEachPod(ctx, pods[i], daemons[i], networkChaos, c, &podResult) - if err != nil { - fmt.Println(err) - } - result.Pods = append(result.Pods, podResult) - // TODO: V(4) log when err != nil, wait for #1433 - } - return nil -} - -func debugEachPod(ctx context.Context, pod v1.Pod, daemon v1.Pod, chaos *v1alpha1.NetworkChaos, c *cm.ClientSet, result *cm.PodResult) error { - // To disable printing irrelevant log from grpc/clientconn.go - // see grpc/grpc-go#3918 for detail. could be resolved in the future - grpclog.SetLoggerV2(grpclog.NewLoggerV2(ioutil.Discard, ioutil.Discard, ioutil.Discard)) - pid, err := cm.GetPidFromPod(ctx, pod, daemon) - if err != nil { - return err - } - nsenterPath := fmt.Sprintf("-n/proc/%d/ns/net", pid) - - // print out debug info - cmd := fmt.Sprintf("/usr/bin/nsenter %s -- ipset list", nsenterPath) - out, err := cm.Exec(ctx, daemon, cmd, c.KubeCli) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("run command '%s' failed", cmd)) - } - result.Items = append(result.Items, cm.ItemResult{Name: "ipset list", Value: string(out)}) - - cmd = fmt.Sprintf("/usr/bin/nsenter %s -- tc qdisc list", nsenterPath) - out, err = cm.Exec(ctx, daemon, cmd, c.KubeCli) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("run command '%s' failed", cmd)) - } - itemResult := cm.ItemResult{Name: "tc qdisc list", Value: string(out)} - - // A demo for comparison with expected. A bit messy actually, don't know if we still need this - action := chaos.Spec.Action - var netemExpect string - switch action { - case "delay": - latency := chaos.Spec.Delay.Latency - jitter := chaos.Spec.Delay.Jitter - correlation := chaos.Spec.Delay.Correlation - netemExpect = fmt.Sprintf("%v %v %v %v%%", action, latency, jitter, correlation) - - netemCurrent := regexp.MustCompile("(?:limit 1000)(.*)").FindStringSubmatch(string(out)) - if len(netemCurrent) == 0 { - return fmt.Errorf("no NetworkChaos is applied") - } - for i, netem := range strings.Fields(netemCurrent[1]) { - itemCurrent := netem - itemExpect := strings.Fields(netemExpect)[i] - if itemCurrent != itemExpect { - r := regexp.MustCompile("([0-9]*[.])?[0-9]+") - // digit could be different, so parse string to float - numCurrent, err := strconv.ParseFloat(r.FindString(itemCurrent), 64) - if err != nil { - return errors.Wrap(err, "parse itemCurrent failed") - } - numExpect, err := strconv.ParseFloat(r.FindString(itemExpect), 64) - if err != nil { - return errors.Wrap(err, "parse itemExpect failed") - } - if numCurrent == numExpect { - continue - } - // alphabetic characters - alpCurrent := regexp.MustCompile("[[:alpha:]]+").FindString(itemCurrent) - alpExpect := regexp.MustCompile("[[:alpha:]]+").FindString(itemExpect) - if alpCurrent == alpExpect { - continue - } - itemResult.Status = cm.ItemFailure - itemResult.ErrInfo = fmt.Sprintf("expect: %s, got: %v", netemExpect, netemCurrent) - } - } - if itemResult.Status != cm.ItemFailure { - itemResult.Status = cm.ItemSuccess - } - } - result.Items = append(result.Items, itemResult) - - cmd = fmt.Sprintf("/usr/bin/nsenter %s -- iptables --list", nsenterPath) - out, err = cm.Exec(ctx, daemon, cmd, c.KubeCli) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd)) - } - result.Items = append(result.Items, cm.ItemResult{Name: "iptables list", Value: string(out)}) - - podNetworkChaos := &v1alpha1.PodNetworkChaos{} - objectKey := client.ObjectKey{ - Namespace: pod.Namespace, - Name: pod.Name, - } - - if err = c.CtrlCli.Get(ctx, objectKey, podNetworkChaos); err != nil { - return errors.Wrap(err, fmt.Sprintf("failed to get network chaos %s/%s", podNetworkChaos.GetNamespace(), podNetworkChaos.GetName())) - } - output, err := cm.MarshalChaos(podNetworkChaos.Spec) - if err != nil { - return err - } - result.Items = append(result.Items, cm.ItemResult{Name: "podnetworkchaos", Value: output}) - - return nil -} diff --git a/pkg/chaosctl/debug/stresschaos.go b/pkg/chaosctl/debug/stresschaos.go new file mode 100644 index 0000000000..5331dfa4bc --- /dev/null +++ b/pkg/chaosctl/debug/stresschaos.go @@ -0,0 +1,161 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package debug + +import ( + "context" + "fmt" + "strconv" + + "code.cloudfoundry.org/bytefmt" + "github.com/hasura/go-graphql-client" + + "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" + ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client" +) + +type stressDebugger struct { + client *ctrlclient.CtrlClient +} + +func StressDebug(client *ctrlclient.CtrlClient) Debugger { + return &stressDebugger{ + client: client, + } +} + +func (d *stressDebugger) Collect(ctx context.Context, namespace, chaosName string) ([]*common.ChaosResult, error) { + var results []*common.ChaosResult + + var name *graphql.String + if chaosName != "" { + n := graphql.String(chaosName) + name = &n + } + + var query struct { + Namespace []struct { + StressChaos []struct { + Name string + Podstress []struct { + Pod struct { + Namespace string + Name string + } + Cgroups struct { + Raw string + Cpu *struct { + Quota int + Period int + } + Memory *struct { + Limit uint64 + } + } + ProcessStress []struct { + Process struct { + Pid string + Command string + } + Cgroup string + } + } + } `graphql:"stresschaos(name: $name)"` + } `graphql:"namespace(ns: $namespace)"` + } + + variables := map[string]interface{}{ + "namespace": graphql.String(namespace), + "name": name, + } + + err := d.client.QueryClient.Query(ctx, &query, variables) + if err != nil { + return nil, err + } + + if len(query.Namespace) == 0 { + return results, nil + } + + for _, stressChaos := range query.Namespace[0].StressChaos { + result := &common.ChaosResult{ + Name: stressChaos.Name, + } + + for _, podStressChaos := range stressChaos.Podstress { + podResult := common.PodResult{ + Name: podStressChaos.Pod.Name, + } + + podResult.Items = append(podResult.Items, common.ItemResult{Name: "cat /proc/cgroups", Value: podStressChaos.Cgroups.Raw}) + for _, process := range podStressChaos.ProcessStress { + podResult.Items = append(podResult.Items, common.ItemResult{ + Name: fmt.Sprintf("/proc/%s/cgroup of %s", process.Process.Pid, process.Process.Command), + Value: process.Cgroup, + }) + } + if podStressChaos.Cgroups.Cpu != nil { + podResult.Items = append(podResult.Items, common.ItemResult{Name: "cpu.cfs_quota_us", Value: strconv.Itoa(podStressChaos.Cgroups.Cpu.Quota)}) + periodItem := common.ItemResult{Name: "cpu.cfs_period_us", Value: strconv.Itoa(podStressChaos.Cgroups.Cpu.Period)} + if podStressChaos.Cgroups.Cpu.Quota == -1 { + periodItem.Status = common.ItemFailure + periodItem.ErrInfo = "no cpu limit is set for now" + } else { + periodItem.Status = common.ItemSuccess + periodItem.SucInfo = fmt.Sprintf("cpu limit is equals to %.2f", float64(podStressChaos.Cgroups.Cpu.Quota)/float64(podStressChaos.Cgroups.Cpu.Period)) + } + podResult.Items = append(podResult.Items, periodItem) + } + + if podStressChaos.Cgroups.Memory != nil { + podResult.Items = append(podResult.Items, common.ItemResult{Name: "memory.limit_in_bytes", Value: bytefmt.ByteSize(podStressChaos.Cgroups.Memory.Limit) + "B"}) + } + result.Pods = append(result.Pods, podResult) + } + results = append(results, result) + } + return results, nil +} + +func (d *stressDebugger) List(ctx context.Context, namespace string) ([]string, error) { + var query struct { + Namespace []struct { + StressChaos []struct { + Name string + } `graphql:"stresschaos"` + } `graphql:"namespace(ns: $namespace)"` + } + + variables := map[string]interface{}{ + "namespace": graphql.String(namespace), + } + + err := d.client.QueryClient.Query(ctx, &query, variables) + if err != nil { + return nil, err + } + + if len(query.Namespace) == 0 { + return nil, nil + } + + var names []string + for _, stressChaos := range query.Namespace[0].StressChaos { + names = append(names, string(stressChaos.Name)) + } + return names, nil +} diff --git a/pkg/chaosctl/debug/stresschaos/stresschaos.go b/pkg/chaosctl/debug/stresschaos/stresschaos.go deleted file mode 100644 index 2dd279f3b2..0000000000 --- a/pkg/chaosctl/debug/stresschaos/stresschaos.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package stresschaos - -import ( - "context" - "fmt" - "regexp" - "strconv" - "strings" - - "github.com/pkg/errors" - - "code.cloudfoundry.org/bytefmt" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - cm "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" -) - -// Debug get chaos debug information -func Debug(ctx context.Context, chaos runtime.Object, c *cm.ClientSet, result *cm.ChaosResult) error { - stressChaos, ok := chaos.(*v1alpha1.StressChaos) - if !ok { - return fmt.Errorf("chaos is not stresschaos") - } - chaosStatus := stressChaos.Status.ChaosStatus - chaosSelector := stressChaos.Spec.GetSelector() - - pods, daemons, err := cm.GetPods(ctx, stressChaos.GetName(), chaosStatus, chaosSelector, c.CtrlCli) - if err != nil { - return err - } - - if err := cm.CheckFailedMessage(ctx, chaosStatus.FailedMessage, daemons, c); err != nil { - return err - } - - for i := range pods { - podName := pods[i].Name - podResult := cm.PodResult{Name: podName} - _ = debugEachPod(ctx, pods[i], daemons[i], stressChaos, c, &podResult) - result.Pods = append(result.Pods, podResult) - // TODO: V(4) log when err != nil, wait for #1433 - } - return nil -} - -func debugEachPod(ctx context.Context, pod v1.Pod, daemon v1.Pod, chaos *v1alpha1.StressChaos, c *cm.ClientSet, result *cm.PodResult) error { - // get process path - cmd := "cat /proc/cgroups" - out, err := cm.ExecBypass(ctx, pod, daemon, cmd, c.KubeCli) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd)) - } - - cmd = "ps" - out, err = cm.ExecBypass(ctx, pod, daemon, cmd, c.KubeCli) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd)) - } - result.Items = append(result.Items, cm.ItemResult{Name: "ps", Value: string(out)}) - stressngLine := regexp.MustCompile("(.*)(stress-ng)").FindStringSubmatch(string(out)) - if len(stressngLine) == 0 { - return fmt.Errorf("could not find stress-ng, StressChaos failed") - } - - pids, commands, err := cm.GetPidFromPS(ctx, pod, daemon, c.KubeCli) - if err != nil { - return errors.Wrap(err, "get pid from ps failed") - } - - for i := range pids { - cmd = fmt.Sprintf("cat /proc/%s/cgroup", pids[i]) - out, err = cm.ExecBypass(ctx, pod, daemon, cmd, c.KubeCli) - if err != nil { - cm.L().WithName("stress-chaos").V(2).Info("failed to fetch cgroup ofr certain process", - "pod", fmt.Sprintf("%s/%s", pod.Namespace, pod.Name), - "pid", i, - ) - result.Items = append(result.Items, cm.ItemResult{Name: fmt.Sprintf("/proc/%s/cgroup of %s", pids[i], commands[i]), Value: "No cgroup found"}) - } else { - result.Items = append(result.Items, cm.ItemResult{Name: fmt.Sprintf("/proc/%s/cgroup of %s", pids[i], commands[i]), Value: string(out)}) - } - } - - // no more info for StressngStressors - if chaos.Spec.StressngStressors != "" { - return nil - } - - isCPU := true - if cpuSpec := chaos.Spec.Stressors.CPUStressor; cpuSpec == nil { - isCPU = false - } - - var expr, cpuMountType string - if isCPU { - if regexp.MustCompile("(cpu,cpuacct)").MatchString(string(out)) { - cpuMountType = "cpu,cpuacct" - } else { - cpuMountType = "cpu" - } - expr = "(?::" + cpuMountType + ":)(.*)" - } else { - expr = "(?::memory:)(.*)" - } - processPath := regexp.MustCompile(expr).FindStringSubmatch(string(out))[1] - - // print out debug info - if isCPU { - cmd = fmt.Sprintf("cat /sys/fs/cgroup/%s/%s/cpu.cfs_quota_us", cpuMountType, processPath) - out, err = cm.Exec(ctx, daemon, cmd, c.KubeCli) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd)) - } - result.Items = append(result.Items, cm.ItemResult{Name: "cpu.cfs_quota_us", Value: string(out)}) - quota, err := strconv.Atoi(strings.TrimSuffix(string(out), "\n")) - if err != nil { - return errors.Wrap(err, "could not get cpu.cfs_quota_us") - } - - cmd = fmt.Sprintf("cat /sys/fs/cgroup/%s/%s/cpu.cfs_period_us", cpuMountType, processPath) - out, err = cm.Exec(ctx, daemon, cmd, c.KubeCli) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd)) - } - period, err := strconv.Atoi(strings.TrimSuffix(string(out), "\n")) - if err != nil { - return errors.Wrap(err, "could not get cpu.cfs_period_us") - } - itemResult := cm.ItemResult{Name: "cpu.cfs_period_us", Value: string(out)} - - if quota == -1 { - itemResult.Status = cm.ItemFailure - itemResult.ErrInfo = "no cpu limit is set for now" - } else { - itemResult.Status = cm.ItemSuccess - itemResult.SucInfo = fmt.Sprintf("cpu limit is equals to %.2f", float64(quota)/float64(period)) - } - result.Items = append(result.Items, itemResult) - } else { - cmd = fmt.Sprintf("cat /sys/fs/cgroup/memory/%s/memory.limit_in_bytes", processPath) - out, err = cm.Exec(ctx, daemon, cmd, c.KubeCli) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd)) - } - limit, err := strconv.ParseUint(strings.TrimSuffix(string(out), "\n"), 10, 64) - if err != nil { - return errors.Wrap(err, "could not get memory.limit_in_bytes") - } - result.Items = append(result.Items, cm.ItemResult{Name: "memory.limit_in_bytes", Value: bytefmt.ByteSize(limit) + "B"}) - } - return nil -} diff --git a/pkg/chaosctl/physicalmachine/create.go b/pkg/chaosctl/physicalmachine/create.go new file mode 100644 index 0000000000..1df85b8a48 --- /dev/null +++ b/pkg/chaosctl/physicalmachine/create.go @@ -0,0 +1,115 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package physicalmachine + +import ( + "context" + "fmt" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" + "github.com/chaos-mesh/chaos-mesh/pkg/label" +) + +type PhysicalMachineCreateOptions struct { + namespace string + labels string + remoteIP string + chaosdPort int + secure bool +} + +func NewPhysicalMachineCreateCmd() (*cobra.Command, error) { + createOption := &PhysicalMachineCreateOptions{} + + createCmd := &cobra.Command{ + Use: `create (PHYSICALMACHINE_NAME) [-n NAMESPACE]`, + Short: `Create PhysicalMachine CustomResource in Kubernetes cluster`, + Long: `Create PhysicalMachine CustomResource in Kubernetes cluster`, + SilenceErrors: true, + SilenceUsage: true, + RunE: func(cmd *cobra.Command, args []string) error { + if err := createOption.Validate(); err != nil { + return err + } + return createOption.Run(args) + }, + } + createCmd.PersistentFlags().StringVarP(&createOption.namespace, "namespace", "n", "default", "namespace of the certain physical machine") + createCmd.PersistentFlags().StringVarP(&createOption.labels, "labels", "l", "", "labels of the certain physical machine (e.g. -l key1=value1,key2=value2)") + createCmd.PersistentFlags().StringVar(&createOption.remoteIP, "ip", "", "ip of the remote physical machine") + createCmd.PersistentFlags().IntVar(&createOption.chaosdPort, "chaosd-port", 31768, "port of the remote chaosd server listen") + createCmd.PersistentFlags().BoolVar(&createOption.secure, "secure", true, "if true, represent that the remote chaosd serve HTTPS") + + return createCmd, nil +} + +func (o *PhysicalMachineCreateOptions) Validate() error { + if len(o.remoteIP) == 0 { + return errors.New("--ip must be specified") + } + return nil +} + +func (o *PhysicalMachineCreateOptions) Run(args []string) error { + if len(args) < 1 { + return errors.New("physical machine name is required") + } + physicalMachineName := args[0] + + labels, err := label.ParseLabel(o.labels) + if err != nil { + return err + } + address := formatAddress(o.remoteIP, o.chaosdPort, o.secure) + + clientset, err := common.InitClientSet() + if err != nil { + return err + } + + ctx := context.Background() + return CreatePhysicalMachine(ctx, clientset.CtrlCli, o.namespace, physicalMachineName, address, labels) +} + +func CreatePhysicalMachine(ctx context.Context, c client.Client, + namespace, name, address string, labels map[string]string) error { + pm := v1alpha1.PhysicalMachine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: name, + Labels: labels, + }, + Spec: v1alpha1.PhysicalMachineSpec{ + Address: address, + }, + } + + return c.Create(ctx, &pm) +} + +func formatAddress(ip string, port int, secure bool) string { + protocol := "http" + if secure { + protocol = "https" + } + return fmt.Sprintf("%s://%s:%d", protocol, ip, port) +} diff --git a/pkg/chaosctl/physicalmachine/generate.go b/pkg/chaosctl/physicalmachine/generate.go new file mode 100644 index 0000000000..9121d7e242 --- /dev/null +++ b/pkg/chaosctl/physicalmachine/generate.go @@ -0,0 +1,90 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package physicalmachine + +import ( + "crypto" + "crypto/x509" + "os" + + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +type PhysicalMachineGenerateOptions struct { + outputPath string + caCertFile string + caKeyFile string +} + +func NewPhysicalMachineGenerateCmd() (*cobra.Command, error) { + generateOption := &PhysicalMachineGenerateOptions{} + + generateCmd := &cobra.Command{ + Use: `generate`, + Short: `Generate TLS certs for certain physical machine`, + Long: `Generate TLS certs for certain physical machine (please execute this command on the certain physical machine)`, + SilenceErrors: true, + SilenceUsage: true, + RunE: func(cmd *cobra.Command, args []string) error { + if err := generateOption.Validate(); err != nil { + return err + } + return generateOption.Run() + }, + } + generateCmd.PersistentFlags().StringVar(&generateOption.outputPath, "path", "/etc/chaosd/pki", "path to save generated certs") + generateCmd.PersistentFlags().StringVar(&generateOption.caCertFile, "cacert", "", "file path to cacert file") + generateCmd.PersistentFlags().StringVar(&generateOption.caKeyFile, "cakey", "", "file path to cakey file") + return generateCmd, nil +} + +func (o *PhysicalMachineGenerateOptions) Validate() error { + if len(o.caCertFile) == 0 { + return errors.New("--cacert must be specified") + } + if len(o.caKeyFile) == 0 { + return errors.New("--cakey must be specified") + } + return nil +} + +func (o *PhysicalMachineGenerateOptions) Run() error { + caCert, caKey, err := GetChaosdCAFileFromFile(o.caCertFile, o.caKeyFile) + if err != nil { + return err + } + + serverCert, serverKey, err := NewCertAndKey(caCert, caKey) + if err != nil { + return err + } + + return WriteCertAndKey(o.outputPath, ChaosdPkiName, serverCert, serverKey) +} + +func GetChaosdCAFileFromFile(caCertFile, caKeyFile string) (*x509.Certificate, crypto.Signer, error) { + certData, err := os.ReadFile(caCertFile) + if err != nil { + return nil, nil, errors.Wrap(err, "cannot read cert file") + } + + keyData, err := os.ReadFile(caKeyFile) + if err != nil { + return nil, nil, errors.Wrap(err, "cannot read private key file") + } + return ParseCertAndKey(certData, keyData) +} diff --git a/pkg/chaosctl/physicalmachine/init.go b/pkg/chaosctl/physicalmachine/init.go new file mode 100644 index 0000000000..ba8dcb465b --- /dev/null +++ b/pkg/chaosctl/physicalmachine/init.go @@ -0,0 +1,176 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package physicalmachine + +import ( + "context" + "crypto" + "crypto/x509" + "os" + "path/filepath" + "strconv" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/keyutil" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common" + "github.com/chaos-mesh/chaos-mesh/pkg/label" +) + +type PhysicalMachineInitOptions struct { + chaosMeshNamespace string + remoteIP string + sshUser string + sshPort int + sshPrivateKeyFile string + chaosdPort int + outputPath string + namespace string + labels string +} + +func NewPhysicalMachineInitCmd() (*cobra.Command, error) { + initOption := &PhysicalMachineInitOptions{} + + initCmd := &cobra.Command{ + Use: `init (PHYSICALMACHINE_NAME) [-n NAMESPACE]`, + Short: `Generate TLS certs for certain physical machine automatically, and create PhysicalMachine CustomResource in Kubernetes cluster`, + Long: `Generate TLS certs for certain physical machine automatically, and create PhysicalMachine CustomResource in Kubernetes cluster + +Examples: + # Generate TLS certs for remote physical machine, and create PhysicalMachine CustomResource in certain namespace + chaosctl pm init PHYSICALMACHINE_NAME -n NAMESPACE --ip REMOTEIP + + # Generate TLS certs for remote physical machine, and create PhysicalMachine CustomResource in certain namespace with specified labels + chaosctl pm init PHYSICALMACHINE_NAME -n NAMESPACE --ip REMOTEIP -l key1=value1,key2=value2 + `, + SilenceErrors: true, + SilenceUsage: true, + RunE: func(cmd *cobra.Command, args []string) error { + if err := initOption.Validate(); err != nil { + return err + } + return initOption.Run(args) + }, + } + initCmd.PersistentFlags().StringVar(&initOption.chaosMeshNamespace, "chaos-mesh-namespace", "chaos-mesh", "namespace where chaos mesh installed") + initCmd.PersistentFlags().StringVar(&initOption.remoteIP, "ip", "", "ip of the remote physical machine") + initCmd.PersistentFlags().StringVar(&initOption.sshUser, "ssh-user", "root", "username for ssh connection") + initCmd.PersistentFlags().StringVar(&initOption.sshPrivateKeyFile, "ssh-key", filepath.Join(os.Getenv("HOME"), ".ssh", "id_rsa"), "private key filepath for ssh connection") + initCmd.PersistentFlags().IntVar(&initOption.sshPort, "ssh-port", 22, "port of ssh connection") + initCmd.PersistentFlags().IntVar(&initOption.chaosdPort, "chaosd-port", 31768, "port of the remote chaosd server listen") + initCmd.PersistentFlags().StringVar(&initOption.outputPath, "path", "/etc/chaosd/pki", "path to save generated certs") + initCmd.PersistentFlags().StringVarP(&initOption.namespace, "namespace", "n", "default", "namespace of the certain physical machine") + initCmd.PersistentFlags().StringVarP(&initOption.labels, "labels", "l", "", "labels of the certain physical machine (e.g. -l key1=value1,key2=value2)") + return initCmd, nil +} + +func (o *PhysicalMachineInitOptions) Validate() error { + if len(o.remoteIP) == 0 { + return errors.New("--ip must be specified") + } + return nil +} + +func (o *PhysicalMachineInitOptions) Run(args []string) error { + if len(args) < 1 { + return errors.New("physical machine name is required") + } + physicalMachineName := args[0] + + labels, err := label.ParseLabel(o.labels) + if err != nil { + return err + } + address := formatAddress(o.remoteIP, o.chaosdPort, true) + + clientset, err := common.InitClientSet() + if err != nil { + return err + } + + ctx := context.Background() + caCert, caKey, err := GetChaosdCAFileFromCluster(ctx, o.chaosMeshNamespace, clientset.CtrlCli) + if err != nil { + return err + } + + // generate chaosd cert and private key + serverCert, serverKey, err := NewCertAndKey(caCert, caKey) + if err != nil { + return err + } + + sshTunnel, err := NewSshTunnel(o.remoteIP, strconv.Itoa(o.sshPort), o.sshUser, o.sshPrivateKeyFile) + if err != nil { + return err + } + if err := sshTunnel.Open(); err != nil { + return err + } + defer sshTunnel.Close() + + if err := writeCertAndKeyToRemote(sshTunnel, o.outputPath, ChaosdPkiName, serverCert, serverKey); err != nil { + return err + } + if err := writeCertToRemote(sshTunnel, o.outputPath, "ca", caCert); err != nil { + return err + } + + return CreatePhysicalMachine(ctx, clientset.CtrlCli, o.namespace, physicalMachineName, address, labels) +} + +func GetChaosdCAFileFromCluster(ctx context.Context, namespace string, c client.Client) (caCert *x509.Certificate, caKey crypto.Signer, err error) { + var secret v1.Secret + if err := c.Get(ctx, types.NamespacedName{ + Namespace: namespace, + Name: "chaos-mesh-chaosd-client-certs", + }, &secret); err != nil { + return nil, nil, errors.Wrapf(err, "could not found secret `chaos-mesh-chaosd-client-certs` in namespace %s", namespace) + } + + var caCertBytes []byte + var ok bool + if caCertBytes, ok = secret.Data["ca.crt"]; !ok { + return nil, nil, errors.New("could not found ca cert file in `chaos-mesh-chaosd-client-certs` secret") + } + + var caKeyBytes []byte + if caKeyBytes, ok = secret.Data["ca.key"]; !ok { + return nil, nil, errors.New("could not found ca key file in `chaos-mesh-chaosd-client-certs` secret") + } + + return ParseCertAndKey(caCertBytes, caKeyBytes) +} + +func writeCertAndKeyToRemote(sshTunnel *SshTunnel, pkiPath, pkiName string, cert *x509.Certificate, key crypto.Signer) error { + keyBytes, err := keyutil.MarshalPrivateKeyToPEM(key) + if err != nil { + return err + } + if err := writeCertToRemote(sshTunnel, pkiPath, pkiName, cert); err != nil { + return err + } + return sshTunnel.SFTP(pathForKey(pkiPath, pkiName), keyBytes) +} + +func writeCertToRemote(sshTunnel *SshTunnel, pkiPath, pkiName string, cert *x509.Certificate) error { + return sshTunnel.SFTP(pathForCert(pkiPath, pkiName), EncodeCertPEM(cert)) +} diff --git a/pkg/chaosctl/physicalmachine/pki.go b/pkg/chaosctl/physicalmachine/pki.go new file mode 100644 index 0000000000..0f80cf1f66 --- /dev/null +++ b/pkg/chaosctl/physicalmachine/pki.go @@ -0,0 +1,199 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package physicalmachine + +import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + cryptorand "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "math" + "math/big" + "path/filepath" + "time" + + "github.com/pkg/errors" + certutil "k8s.io/client-go/util/cert" + "k8s.io/client-go/util/keyutil" +) + +const ( + rsaKeySize = 2048 + ChaosdPkiName = "chaosd" + // CertificateBlockType is a possible value for pem.Block.Type. + CertificateBlockType = "CERTIFICATE" + // CertificateValidity defines the validity for all the signed certificates generated by kubeadm + CertificateValidity = time.Hour * 24 * 1825 +) + +func ParseCertAndKey(certData, keyData []byte) (*x509.Certificate, crypto.Signer, error) { + caCert, err := ParseCert(certData) + if err != nil { + return nil, nil, errors.Wrap(err, "parse certs pem failed") + } + + caKey, err := ParsePrivateKey(keyData) + if err != nil { + return nil, nil, errors.Wrap(err, "parse ca key file failed") + } + return caCert, caKey, nil +} + +func ParsePrivateKey(data []byte) (crypto.Signer, error) { + privKey, err := keyutil.ParsePrivateKeyPEM(data) + if err != nil { + return nil, errors.Errorf("error reading private key file: %v", err) + } + + var key crypto.Signer + // Allow RSA and ECDSA formats only + switch k := privKey.(type) { + case *rsa.PrivateKey: + key = k + case *ecdsa.PrivateKey: + key = k + default: + return nil, errors.New("the private key file is neither in RSA nor ECDSA format") + } + return key, nil +} + +func ParseCert(data []byte) (*x509.Certificate, error) { + caCerts, err := certutil.ParseCertsPEM(data) + if err != nil { + return nil, errors.Wrap(err, "parse certs pem failed") + } + return caCerts[0], nil +} + +// NewCertAndKey creates new certificate and key by passing the certificate authority certificate and key +func NewCertAndKey(caCert *x509.Certificate, caKey crypto.Signer) (*x509.Certificate, crypto.Signer, error) { + key, err := NewPrivateKey(x509.RSA) + if err != nil { + return nil, nil, errors.Wrap(err, "unable to create private key") + } + + cert, err := NewSignedCert(key, caCert, caKey, false) + if err != nil { + return nil, nil, errors.Wrap(err, "unable to sign certificate") + } + + return cert, key, nil +} + +func NewPrivateKey(keyType x509.PublicKeyAlgorithm) (crypto.Signer, error) { + if keyType == x509.ECDSA { + return ecdsa.GenerateKey(elliptic.P256(), cryptorand.Reader) + } + + return rsa.GenerateKey(cryptorand.Reader, rsaKeySize) +} + +// NewSignedCert creates a signed certificate using the given CA certificate and key +func NewSignedCert(key crypto.Signer, caCert *x509.Certificate, caKey crypto.Signer, isCA bool) (*x509.Certificate, error) { + serial, err := cryptorand.Int(cryptorand.Reader, new(big.Int).SetInt64(math.MaxInt64)) + if err != nil { + return nil, err + } + + keyUsage := x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature + if isCA { + keyUsage |= x509.KeyUsageCertSign + } + + notAfter := time.Now().Add(CertificateValidity).UTC() + + certTmpl := x509.Certificate{ + Subject: pkix.Name{ + CommonName: "chaosd.chaos-mesh.org", + }, + DNSNames: []string{"chaosd.chaos-mesh.org", "localhost"}, + SerialNumber: serial, + NotBefore: caCert.NotBefore, + NotAfter: notAfter, + KeyUsage: keyUsage, + BasicConstraintsValid: true, + IsCA: isCA, + } + certDERBytes, err := x509.CreateCertificate(cryptorand.Reader, &certTmpl, caCert, key.Public(), caKey) + if err != nil { + return nil, err + } + return x509.ParseCertificate(certDERBytes) +} + +// WriteCertAndKey stores certificate and key at the specified location +func WriteCertAndKey(pkiPath string, name string, cert *x509.Certificate, key crypto.Signer) error { + if err := WriteKey(pkiPath, name, key); err != nil { + return errors.Wrap(err, "couldn't write key") + } + + return WriteCert(pkiPath, name, cert) +} + +// WriteCert stores the given certificate at the given location +func WriteCert(pkiPath, name string, cert *x509.Certificate) error { + if cert == nil { + return errors.New("certificate cannot be nil when writing to file") + } + + certificatePath := pathForCert(pkiPath, name) + if err := certutil.WriteCert(certificatePath, EncodeCertPEM(cert)); err != nil { + return errors.Wrapf(err, "unable to write certificate to file %s", certificatePath) + } + + return nil +} + +// WriteKey stores the given key at the given location +func WriteKey(pkiPath, name string, key crypto.Signer) error { + if key == nil { + return errors.New("private key cannot be nil when writing to file") + } + + privateKeyPath := pathForKey(pkiPath, name) + encoded, err := keyutil.MarshalPrivateKeyToPEM(key) + if err != nil { + return errors.Wrapf(err, "unable to marshal private key to PEM") + } + if err := keyutil.WriteKey(privateKeyPath, encoded); err != nil { + return errors.Wrapf(err, "unable to write private key to file %s", privateKeyPath) + } + + return nil +} + +// EncodeCertPEM returns PEM-endcoded certificate data +func EncodeCertPEM(cert *x509.Certificate) []byte { + block := pem.Block{ + Type: CertificateBlockType, + Bytes: cert.Raw, + } + return pem.EncodeToMemory(&block) +} + +func pathForCert(pkiPath, name string) string { + return filepath.Join(pkiPath, fmt.Sprintf("%s.crt", name)) +} + +func pathForKey(pkiPath, name string) string { + return filepath.Join(pkiPath, fmt.Sprintf("%s.key", name)) +} diff --git a/pkg/chaosctl/physicalmachine/ssh.go b/pkg/chaosctl/physicalmachine/ssh.go new file mode 100644 index 0000000000..3e79355161 --- /dev/null +++ b/pkg/chaosctl/physicalmachine/ssh.go @@ -0,0 +1,121 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package physicalmachine + +import ( + "fmt" + "net" + "os" + "path/filepath" + "syscall" + "time" + + "github.com/pkg/errors" + "github.com/pkg/sftp" + "golang.org/x/crypto/ssh" + "golang.org/x/crypto/ssh/knownhosts" + "golang.org/x/term" +) + +type SshTunnel struct { + config *ssh.ClientConfig + host string + port string + client *ssh.Client +} + +func NewSshTunnel(ip, port string, user, privateKeyFile string) (*SshTunnel, error) { + hostKeyCallback, err := knownhosts.New(filepath.Join(os.Getenv("HOME"), ".ssh", "known_hosts")) + if err != nil { + return nil, err + } + config := ssh.ClientConfig{ + Timeout: 5 * time.Minute, + User: user, + Auth: []ssh.AuthMethod{ + ssh.PublicKeysCallback(func() ([]ssh.Signer, error) { + key, err := os.ReadFile(privateKeyFile) + if err != nil { + return nil, errors.Wrap(err, "ssh key file read failed") + } + + signer, err := ssh.ParsePrivateKey(key) + if err != nil { + return nil, errors.Wrap(err, "ssh key signer failed") + } + return []ssh.Signer{signer}, nil + }), + ssh.PasswordCallback(func() (secret string, err error) { + fmt.Printf("please input the password: ") + password, err := term.ReadPassword(int(syscall.Stdin)) + if err != nil { + return "", errors.Wrap(err, "read ssh password failed") + } + return string(password), nil + }), + }, + HostKeyCallback: hostKeyCallback, + } + return &SshTunnel{ + config: &config, + host: ip, + port: port, + }, nil +} + +func (s *SshTunnel) Open() error { + conn, err := ssh.Dial("tcp", net.JoinHostPort(s.host, s.port), s.config) + if err != nil { + return errors.Wrap(err, "open ssh tunnel failed") + } + s.client = conn + return nil +} + +func (s *SshTunnel) Close() error { + if s.client == nil { + return nil + } + return s.client.Close() +} + +func (s *SshTunnel) SFTP(filename string, data []byte) error { + if s.client == nil { + return errors.New("tunnel is not opened") + } + + // open an SFTP session over an existing ssh connection. + client, err := sftp.NewClient(s.client) + if err != nil { + return errors.Wrap(err, "create sftp client failed") + } + defer client.Close() + + if err := client.MkdirAll(filepath.Dir(filename)); err != nil { + return errors.Wrapf(err, "make directory %s failed", filepath.Dir(filename)) + } + + f, err := client.Create(filename) + if err != nil { + return errors.Wrapf(err, "create file %s failed", filename) + } + defer f.Close() + + if _, err := f.Write(data); err != nil { + return errors.Wrapf(err, "write file %s failed", filename) + } + return nil +} diff --git a/pkg/chaosctl/recover/httpchaos.go b/pkg/chaosctl/recover/httpchaos.go new file mode 100644 index 0000000000..b00b7f5d8c --- /dev/null +++ b/pkg/chaosctl/recover/httpchaos.go @@ -0,0 +1,43 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recover + +import ( + "context" + + "github.com/pkg/errors" + + ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client" +) + +type httpRecoverer struct { + tproxyCleaner Recoverer +} + +func HTTPRecoverer(client *ctrlclient.CtrlClient) Recoverer { + return &httpRecoverer{ + tproxyCleaner: newCleanProcessRecoverer(client, "tproxy"), + } +} + +func (r *httpRecoverer) Recover(ctx context.Context, pod *PartialPod) error { + // TODO: need hostPath to store rules + err := r.tproxyCleaner.Recover(ctx, pod) + if err != nil { + return errors.Wrap(err, "clean chaos-tproxy processes") + } + return nil +} diff --git a/pkg/chaosctl/recover/iochaos.go b/pkg/chaosctl/recover/iochaos.go new file mode 100644 index 0000000000..7c8ad45f6e --- /dev/null +++ b/pkg/chaosctl/recover/iochaos.go @@ -0,0 +1,43 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recover + +import ( + "context" + + "github.com/pkg/errors" + + ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client" +) + +type ioRecoverer struct { + todaCleaner Recoverer +} + +func IORecoverer(client *ctrlclient.CtrlClient) Recoverer { + return &ioRecoverer{ + todaCleaner: newCleanProcessRecoverer(client, "toda"), + } +} + +func (r *ioRecoverer) Recover(ctx context.Context, pod *PartialPod) error { + // TODO: need hostPath to store replaced fds + err := r.todaCleaner.Recover(ctx, pod) + if err != nil { + return errors.Wrap(err, "clean toda processes") + } + return nil +} diff --git a/pkg/chaosctl/recover/networkchaos.go b/pkg/chaosctl/recover/networkchaos.go new file mode 100644 index 0000000000..d0fc478e80 --- /dev/null +++ b/pkg/chaosctl/recover/networkchaos.go @@ -0,0 +1,160 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recover + +import ( + "context" + "fmt" + "regexp" + "strconv" + "strings" + + "github.com/pingcap/errors" + + ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client" +) + +// match handle number and device in tc qdisc rules +// ### Rules Example: +// We can match handle number `8001` and device `vnet0` in the following rule: +// ``` +// qdisc noqueue 8001: dev vnet0 root refcnt 2 +// ``` +var tcRegexp = regexp.MustCompile(`([0-9]+): dev (\w+)`) + +type tcsRecoverer struct { + client *ctrlclient.CtrlClient +} + +func newTcsRecoverer(client *ctrlclient.CtrlClient) Recoverer { + return &tcsRecoverer{ + client: client, + } +} + +// Recover clean all tc qdisc rules +func (r *tcsRecoverer) Recover(ctx context.Context, pod *PartialPod) error { + deviceSet := map[string]bool{} + for _, rule := range pod.TcQdisc { + matches := tcRegexp.FindStringSubmatch(rule) + if len(matches) != 3 { + continue + } + handle, err := strconv.Atoi(matches[1]) + if err != nil { + return errors.Wrapf(err, "parse tc qdisc handle: `%s`", matches[1]) + } + if handle > 0 { + // if handle is 0, it's unnecessary to clean + deviceSet[matches[2]] = true + } + } + + var devices []string + for dev := range deviceSet { + devices = append(devices, dev) + } + + if len(devices) == 0 { + printStep("all tc rules are cleaned up") + return nil + } + printStep(fmt.Sprintf("cleaning tc rules for device %v", devices)) + + cleanedTcs, err := r.client.CleanTcs(ctx, pod.Namespace, pod.Name, devices) + if err != nil { + return err + } + + if len(cleanedTcs) != 0 { + printStep(fmt.Sprintf("tc rules on device %s are cleaned up", strings.Join(cleanedTcs, ","))) + } + + return nil +} + +type iptablesRecoverer struct { + client *ctrlclient.CtrlClient +} + +func newIptablesRecoverer(client *ctrlclient.CtrlClient) Recoverer { + return &iptablesRecoverer{ + client: client, + } +} + +// Recover clean all tables rules in chains CHAOS-INPUT and CHAOS-OUTPUT +func (r *iptablesRecoverer) Recover(ctx context.Context, pod *PartialPod) error { + chainSet := map[string]bool{ + "CHAOS-INPUT": false, + "CHAOS-OUTPUT": false, + } + for _, rule := range pod.Iptables { + for chain := range chainSet { + if strings.HasPrefix(rule, fmt.Sprintf("Chain %s", chain)) { + chainSet[chain] = true + } + } + } + + var chains []string + for chain, ok := range chainSet { + if ok { + chains = append(chains, chain) + } + } + + if len(chains) == 0 { + printStep("all iptables rules are cleaned up") + return nil + } + printStep(fmt.Sprintf("cleaning iptables rules for chains %v", chains)) + + cleanedChains, err := r.client.CleanIptables(ctx, pod.Namespace, pod.Name, chains) + if err != nil { + return err + } + + if len(cleanedChains) != 0 { + printStep(fmt.Sprintf("iptables rules in chains %s are cleaned up", strings.Join(cleanedChains, ","))) + } + + return nil +} + +type networkRecoverer struct { + tcsRecoverer Recoverer + iptablesRecoverer Recoverer +} + +func NetworkRecoverer(client *ctrlclient.CtrlClient) Recoverer { + return &networkRecoverer{ + tcsRecoverer: newTcsRecoverer(client), + iptablesRecoverer: newIptablesRecoverer(client), + } +} + +func (r *networkRecoverer) Recover(ctx context.Context, pod *PartialPod) error { + err := r.tcsRecoverer.Recover(ctx, pod) + if err != nil { + return errors.Wrap(err, "recover tcs rules") + } + err = r.iptablesRecoverer.Recover(ctx, pod) + if err != nil { + return errors.Wrap(err, "recover iptables rules") + } + return nil +} diff --git a/pkg/chaosctl/recover/print.go b/pkg/chaosctl/recover/print.go new file mode 100644 index 0000000000..0d68e2e114 --- /dev/null +++ b/pkg/chaosctl/recover/print.go @@ -0,0 +1,28 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recover + +import ( + "fmt" + + "github.com/fatih/color" +) + +var step = color.New(color.FgGreen, color.Bold).SprintFunc()(">> ") + +func printStep(line string) { + fmt.Println(step + line) +} diff --git a/pkg/chaosctl/recover/recover.go b/pkg/chaosctl/recover/recover.go new file mode 100644 index 0000000000..985a73a0e0 --- /dev/null +++ b/pkg/chaosctl/recover/recover.go @@ -0,0 +1,82 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recover + +import ( + "context" + "fmt" + "strings" + + "github.com/pkg/errors" + + ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client" +) + +// PartialPod is a subset of the Pod type. +// It contains necessary information for forced recovery. +type PartialPod struct { + Namespace string + Name string + Processes []struct { + Pid, Command string + } + TcQdisc []string + Iptables []string +} + +type Recoverer interface { + // Recover target pod forcedly + Recover(ctx context.Context, pod *PartialPod) error +} + +type RecovererBuilder func(client *ctrlclient.CtrlClient) Recoverer + +type cleanProcessRecoverer struct { + client *ctrlclient.CtrlClient + process string +} + +func newCleanProcessRecoverer(client *ctrlclient.CtrlClient, process string) Recoverer { + return &cleanProcessRecoverer{ + client: client, + process: process, + } +} + +func (r *cleanProcessRecoverer) Recover(ctx context.Context, pod *PartialPod) error { + var pids []string + for _, process := range pod.Processes { + if process.Command == r.process { + pids = append(pids, process.Pid) + } + } + + if len(pids) == 0 { + printStep(fmt.Sprintf("all %s processes are cleaned up", r.process)) + return nil + } + printStep(fmt.Sprintf("cleaning %s processes: %v", r.process, pids)) + + killedPids, err := r.client.KillProcesses(ctx, pod.Namespace, pod.Name, pids) + if err != nil { + return errors.Wrapf(err, "kill %s processes", r.process) + } + if len(killedPids) != 0 { + printStep(fmt.Sprintf("%s processes(%s) are cleaned up", r.process, strings.Join(killedPids, ", "))) + } + + return nil +} diff --git a/pkg/chaosctl/recover/select.go b/pkg/chaosctl/recover/select.go new file mode 100644 index 0000000000..13c9eab91a --- /dev/null +++ b/pkg/chaosctl/recover/select.go @@ -0,0 +1,70 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recover + +import ( + "context" + + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client" + "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/model" +) + +func SelectPods(ctx context.Context, client *ctrlclient.CtrlClient, selector v1alpha1.PodSelectorSpec) ([]*PartialPod, error) { + selectInput := model.PodSelectorInput{ + Pods: map[string]interface{}{}, + NodeSelectors: map[string]interface{}{}, + Nodes: selector.Nodes, + PodPhaseSelectors: selector.PodPhaseSelectors, + Namespaces: selector.Namespaces, + FieldSelectors: map[string]interface{}{}, + LabelSelectors: map[string]interface{}{}, + AnnotationSelectors: map[string]interface{}{}, + } + + for k, v := range selector.Pods { + selectInput.Pods[k] = v + } + + for k, v := range selector.NodeSelectors { + selectInput.NodeSelectors[k] = v + } + + for k, v := range selector.FieldSelectors { + selectInput.FieldSelectors[k] = v + } + + for k, v := range selector.LabelSelectors { + selectInput.LabelSelectors[k] = v + } + + for k, v := range selector.AnnotationSelectors { + selectInput.AnnotationSelectors[k] = v + } + + podsQuery := new(struct { + Pods []*PartialPod `graphql:"pods(selector: $selector)"` + }) + + err := client.QueryClient.Query(ctx, podsQuery, map[string]interface{}{"selector": selectInput}) + if err != nil { + return nil, errors.Wrapf(err, "select pods with selector: %+v", selector) + } + + return podsQuery.Pods, nil +} diff --git a/pkg/chaosctl/recover/stresschaos.go b/pkg/chaosctl/recover/stresschaos.go new file mode 100644 index 0000000000..082fa5b617 --- /dev/null +++ b/pkg/chaosctl/recover/stresschaos.go @@ -0,0 +1,48 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package recover + +import ( + "context" + + "github.com/pkg/errors" + + ctrlclient "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/client" +) + +type stressRecoverer struct { + memStressCleaner Recoverer + stressNGCleaner Recoverer +} + +func StressRecoverer(client *ctrlclient.CtrlClient) Recoverer { + return &stressRecoverer{ + memStressCleaner: newCleanProcessRecoverer(client, "memStress"), + stressNGCleaner: newCleanProcessRecoverer(client, "stress-ng"), + } +} + +func (r *stressRecoverer) Recover(ctx context.Context, pod *PartialPod) error { + err := r.stressNGCleaner.Recover(ctx, pod) + if err != nil { + return errors.Wrap(err, "clean stress-ng processes") + } + err = r.memStressCleaner.Recover(ctx, pod) + if err != nil { + return errors.Wrap(err, "clean memStress processes") + } + return nil +} diff --git a/pkg/chaosdaemon/blockchaos_server_darwin.go b/pkg/chaosdaemon/blockchaos_server_darwin.go new file mode 100644 index 0000000000..e0b1dd49ee --- /dev/null +++ b/pkg/chaosdaemon/blockchaos_server_darwin.go @@ -0,0 +1,44 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Since BlockChaos is not unimplemented in darwin os. This file is only used for debugging, for example if your editor has gopls activated automatically. + +package chaosdaemon + +import ( + "context" + + "github.com/golang/protobuf/ptypes/empty" + + pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" +) + +const chaosDaemonHelperCommand = "cdh" + +func (s *DaemonServer) ApplyBlockChaos(ctx context.Context, req *pb.ApplyBlockChaosRequest) (*pb.ApplyBlockChaosResponse, error) { + return nil, nil +} + +func normalizeVolumeName(ctx context.Context, volumePath string) (string, error) { + return "", nil +} + +func enableIOEMElevator(volumeName string) error { + return nil +} + +func (s *DaemonServer) RecoverBlockChaos(ctx context.Context, req *pb.RecoverBlockChaosRequest) (*empty.Empty, error) { + return &empty.Empty{}, nil +} diff --git a/pkg/chaosdaemon/blockchaos_server_linux.go b/pkg/chaosdaemon/blockchaos_server_linux.go new file mode 100644 index 0000000000..ed4fb81308 --- /dev/null +++ b/pkg/chaosdaemon/blockchaos_server_linux.go @@ -0,0 +1,157 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package chaosdaemon + +import ( + "context" + "os" + "strings" + + "github.com/chaos-mesh/chaos-driver/pkg/client" + "github.com/golang/protobuf/ptypes/empty" + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/pkg/bpm" + pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" +) + +const chaosDaemonHelperCommand = "cdh" + +func (s *DaemonServer) ApplyBlockChaos(ctx context.Context, req *pb.ApplyBlockChaosRequest) (*pb.ApplyBlockChaosResponse, error) { + log := s.getLoggerFromContext(ctx) + + volumeName, err := normalizeVolumeName(ctx, req.VolumePath) + if err != nil { + log.Error(err, "normalize volume name", "volumePath", req.VolumePath) + return nil, err + } + + err = enableIOEMElevator(volumeName) + if err != nil { + log.Error(err, "error while enabling ioem elevator", "volumeName", volumeName) + return nil, errors.Wrapf(err, "enable ioem elevator for volume %s", volumeName) + } + + volumePath := "/dev/" + volumeName + if _, err := os.Stat(volumePath); err != nil { + log.Error(err, "error while getting stat of volume", "volumePath", volumePath) + return nil, errors.Wrapf(err, "volume path %s does not exist", volumePath) + } + + pid, err := s.crClient.GetPidFromContainerID(ctx, req.ContainerId) + if err != nil { + log.Error(err, "error while getting PID") + return nil, err + } + + c, err := client.New() + if err != nil { + log.Error(err, "create chaos-driver client") + return nil, err + } + defer c.Close() + + if req.Action == pb.ApplyBlockChaosRequest_Delay { + log.Info("Injecting IOEM Delay", "delay", req.Delay.Delay, "jitter", req.Delay.Jitter, "corr", req.Delay.Correlation) + + id, err := c.InjectIOEMDelay(volumePath, 0, uint(pid), req.Delay.Delay, req.Delay.Jitter, float64(req.Delay.Correlation)) + if err != nil { + log.Error(err, "inject ioem delay") + return nil, err + } + return &pb.ApplyBlockChaosResponse{ + InjectionId: int32(id), + }, nil + } + + return nil, errors.New("unknown action") +} + +func normalizeVolumeName(ctx context.Context, volumePath string) (string, error) { + volumeName, err := bpm.DefaultProcessBuilder(chaosDaemonHelperCommand, "normalize-volume-name", volumePath). + SetContext(ctx). + SetNS(1, bpm.MountNS). + EnableLocalMnt(). + Build(ctx). + Output() + if err != nil { + return "", errors.Wrapf(err, "normalize volume name %s", volumePath) + } + + return strings.Trim(string(volumeName), "\n\x00"), nil +} + +func enableIOEMElevator(volumeName string) error { + schedulerPath := "/sys/block/" + volumeName + "/queue/scheduler" + rawSchedulers, err := os.ReadFile(schedulerPath) + if err != nil { + return errors.Wrapf(err, "reading schedulers %s", schedulerPath) + } + + schedulers := strings.Split(strings.Trim(string(rawSchedulers), " \x00\n"), " ") + choosenScheduler := "" + for _, scheduler := range schedulers { + // TODO: record the current scheduler, and recover in the future + // Bue it's hard to decide whether a block device is affected by chaos + + // The ioem scheduler without fault injection is only a simple FIFO, + // which is nearly the same with none scheduler. But for HDD, the + // none scheduler is much slower than other schedulers. For NVMe, + // the default scheduler is none, and it's fine to keep ioem without + // significant overhead. + + if strings.Contains(scheduler, "ioem") { + choosenScheduler = scheduler // it's either ioem or ioem-mq + } + } + + if len(choosenScheduler) == 0 { + return errors.New("ioem scheduler not found") + } + + if choosenScheduler[0] == '[' && choosenScheduler[len(choosenScheduler)-1] == ']' { + // it has aleady been enabled + return nil + } + + // it doesn't matter to pass any permission, because the file must exist + err = os.WriteFile(schedulerPath, []byte(choosenScheduler), 0000) + if err != nil { + return errors.Wrapf(err, "writing %s to %s", choosenScheduler, schedulerPath) + } + + return nil +} + +func (s *DaemonServer) RecoverBlockChaos(ctx context.Context, req *pb.RecoverBlockChaosRequest) (*empty.Empty, error) { + log := s.getLoggerFromContext(ctx) + + c, err := client.New() + if err != nil { + log.Error(err, "create chaos-driver client") + return nil, err + } + defer c.Close() + + log.Info("Recovering IOEM", "injectionId", req.InjectionId) + err = c.Recover(int(req.InjectionId)) + if err != nil { + log.Error(err, "recover injection", "id", req.InjectionId) + return nil, err + } + + return &empty.Empty{}, nil +} diff --git a/pkg/chaosdaemon/cgroups/attach_cgroup.go b/pkg/chaosdaemon/cgroups/attach_cgroup.go new file mode 100644 index 0000000000..23161ecb97 --- /dev/null +++ b/pkg/chaosdaemon/cgroups/attach_cgroup.go @@ -0,0 +1,113 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package cgroups + +import ( + "fmt" + "os/exec" + + "github.com/containerd/cgroups" + "github.com/pkg/errors" +) + +type CGroupInfo struct { + CGMode cgroups.CGMode + V1Path cgroups.Path + V2CGroupPath string +} + +type AttachCGroup interface { + TargetCGroup() CGroupInfo + AttachProcess(pid int) error +} + +var _ AttachCGroup = (*AttachCGroupV1)(nil) + +type AttachCGroupV1 struct { + mode cgroups.CGMode + path cgroups.Path +} + +func (a *AttachCGroupV1) TargetCGroup() CGroupInfo { + return CGroupInfo{ + CGMode: a.mode, + V1Path: a.path, + V2CGroupPath: "", + } +} + +func (a *AttachCGroupV1) AttachProcess(pid int) error { + cgroupv1, err := cgroups.Load(V1, a.path) + if err != nil { + cpuCGroupPath, _ := a.path("cpu") + memoryCGroupPath, _ := a.path("memory") + return errors.Wrapf(err, "load cgroup v1 manager, pid %d, cpu path %s, memory path %s", pid, cpuCGroupPath, memoryCGroupPath) + } + err = cgroupv1.Add(cgroups.Process{Pid: pid}) + if err != nil { + cpuCGroupPath, _ := a.path("cpu") + memoryCGroupPath, _ := a.path("memory") + return errors.Wrapf(err, "add process to cgroup, pid %d, cpu path %s, memory path %s", pid, cpuCGroupPath, memoryCGroupPath) + } + return nil +} + +var _ AttachCGroup = (*AttachCGroupV2)(nil) + +type AttachCGroupV2 struct { + mode cgroups.CGMode + path string +} + +func (a *AttachCGroupV2) TargetCGroup() CGroupInfo { + return CGroupInfo{ + CGMode: a.mode, + V1Path: nil, + V2CGroupPath: a.path, + } +} + +func (a *AttachCGroupV2) AttachProcess(pid int) error { + // escape the CGroup Namespace, we could not modify cgroups across different cgroups namespace, + // resolve https://github.com/chaos-mesh/chaos-mesh/pull/2928#issuecomment-1049465242 + targetFile := fmt.Sprintf("/host-sys/fs/cgroup%s/cgroup.procs", a.path) + command := exec.Command("nsenter", "-C", "-t", "1", "--", "sh", "-c", fmt.Sprintf("echo %d >> %s", pid, targetFile)) + output, err := command.CombinedOutput() + if err != nil { + return errors.Wrapf(err, "attach process to cgroup, pid %d, target cgourp file %s, output %s", pid, targetFile, string(output)) + } + return nil +} + +// GetAttacherForPID return a AttachCGroup, which could attach a process to the same cgroup of the target pid +func GetAttacherForPID(targetPID int) (AttachCGroup, error) { + if cgroups.Mode() == cgroups.Unified { + groupPath, err := V2PidGroupPath(targetPID) + if err != nil { + return nil, err + } + return &AttachCGroupV2{ + mode: cgroups.Unified, + path: groupPath, + }, nil + } + + // By default it's cgroup v1 + return &AttachCGroupV1{ + mode: cgroups.Mode(), + path: PidPath(targetPID), + }, nil +} diff --git a/pkg/chaosdaemon/cgroups/pidpath.go b/pkg/chaosdaemon/cgroups/pidpath.go new file mode 100644 index 0000000000..60d6d58fe1 --- /dev/null +++ b/pkg/chaosdaemon/cgroups/pidpath.go @@ -0,0 +1,103 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package cgroups + +import ( + "bufio" + "bytes" + "fmt" + "io" + "os" + "os/exec" + "strings" + + "github.com/containerd/cgroups" + "github.com/pkg/errors" +) + +func V1() ([]cgroups.Subsystem, error) { + subsystems, err := defaults("/host-sys/fs/cgroup") + if err != nil { + return nil, err + } + var enabled []cgroups.Subsystem + for _, s := range pathers(subsystems) { + // check and remove the default groups that do not exist + if _, err := os.Lstat(s.Path("/")); err == nil { + enabled = append(enabled, s) + } + } + return enabled, nil +} + +func PidPath(pid int) cgroups.Path { + p := fmt.Sprintf("/proc/%d/cgroup", pid) + paths, err := cgroups.ParseCgroupFile(p) + if err != nil { + return func(_ cgroups.Name) (string, error) { + return "", errors.Wrapf(err, "parse cgroup file %s", p) + } + } + + return func(name cgroups.Name) (string, error) { + root, ok := paths[string(name)] + if !ok { + if root, ok = paths["name="+string(name)]; !ok { + return "", errors.New("controller is not supported") + } + } + + return root, nil + } +} + +func V2PidGroupPath(pid int) (string, error) { + // escape the CGroup Namespace, resolve https://github.com/chaos-mesh/chaos-mesh/pull/2928#issuecomment-1049465242 + // nsenter -C -t 1 cat /proc/$pid/cgroup + command := exec.Command("nsenter", "-C", "-t", "1", "cat", fmt.Sprintf("/proc/%d/cgroup", pid)) + var buffer bytes.Buffer + command.Stdout = &buffer + + err := command.Run() + if err != nil { + return "", errors.Wrapf(err, "get cgroup path of pid %d", pid) + } + return parseCgroupFromReader(&buffer) +} + +// parseCgroupFromReader is copied from github.com/containerd/cgroups/v2/utils.go +func parseCgroupFromReader(r io.Reader) (string, error) { + var ( + s = bufio.NewScanner(r) + ) + for s.Scan() { + var ( + text = s.Text() + parts = strings.SplitN(text, ":", 3) + ) + if len(parts) < 3 { + return "", fmt.Errorf("invalid cgroup entry: %q", text) + } + // text is like "0::/user.slice/user-1001.slice/session-1.scope" + if parts[0] == "0" && parts[1] == "" { + return parts[2], nil + } + } + if err := s.Err(); err != nil { + return "", err + } + return "", fmt.Errorf("cgroup path not found") +} diff --git a/pkg/chaosdaemon/cgroups/utils.go b/pkg/chaosdaemon/cgroups/utils.go new file mode 100644 index 0000000000..65eb81ac25 --- /dev/null +++ b/pkg/chaosdaemon/cgroups/utils.go @@ -0,0 +1,70 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package cgroups + +import ( + "os" + + "github.com/containerd/cgroups" +) + +// defaults returns all known groups +func defaults(root string) ([]cgroups.Subsystem, error) { + h, err := cgroups.NewHugetlb(root) + if err != nil && !os.IsNotExist(err) { + return nil, err + } + s := []cgroups.Subsystem{ + cgroups.NewNamed(root, "systemd"), + cgroups.NewFreezer(root), + cgroups.NewPids(root), + cgroups.NewNetCls(root), + cgroups.NewNetPrio(root), + cgroups.NewPerfEvent(root), + cgroups.NewCpuset(root), + cgroups.NewCpu(root), + cgroups.NewCpuacct(root), + cgroups.NewMemory(root), + cgroups.NewBlkio(root), + cgroups.NewRdma(root), + } + // only add the devices cgroup if we are not in a user namespace + // because modifications are not allowed + if !cgroups.RunningInUserNS() { + s = append(s, cgroups.NewDevices(root)) + } + // add the hugetlb cgroup if error wasn't due to missing hugetlb + // cgroup support on the host + if err == nil { + s = append(s, h) + } + return s, nil +} + +type pather interface { + cgroups.Subsystem + Path(path string) string +} + +func pathers(subystems []cgroups.Subsystem) []pather { + var out []pather + for _, s := range subystems { + if p, ok := s.(pather); ok { + out = append(out, p) + } + } + return out +} diff --git a/pkg/chaosdaemon/client/utils.go b/pkg/chaosdaemon/client/utils.go index 1f32907639..b35939fef2 100644 --- a/pkg/chaosdaemon/client/utils.go +++ b/pkg/chaosdaemon/client/utils.go @@ -1,27 +1,26 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package client import ( "google.golang.org/grpc" - ctrl "sigs.k8s.io/controller-runtime" chaosdaemon "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" ) -var log = ctrl.Log.WithName("chaos-daemon-client-utils") - // ChaosDaemonClientInterface represents the ChaosDaemonClient, it's used to simply unit test type ChaosDaemonClientInterface interface { chaosdaemon.ChaosDaemonClient diff --git a/pkg/chaosdaemon/container.go b/pkg/chaosdaemon/container.go index f3621dc52a..83f623d771 100644 --- a/pkg/chaosdaemon/container.go +++ b/pkg/chaosdaemon/container.go @@ -1,34 +1,38 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon import ( "context" - "fmt" "github.com/golang/protobuf/ptypes/empty" + "github.com/pkg/errors" pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" ) // ContainerKill kills container according to container id in the req func (s *DaemonServer) ContainerKill(ctx context.Context, req *pb.ContainerRequest) (*empty.Empty, error) { + log := s.getLoggerFromContext(ctx) + log.Info("Container Kill", "request", req) action := req.Action.Action if action != pb.ContainerAction_KILL { - err := fmt.Errorf("container action is %s , not kill", action) + err := errors.Errorf("container action is %s , not kill", action) log.Error(err, "container action is not expected") return nil, err } @@ -43,11 +47,13 @@ func (s *DaemonServer) ContainerKill(ctx context.Context, req *pb.ContainerReque } func (s *DaemonServer) ContainerGetPid(ctx context.Context, req *pb.ContainerRequest) (*pb.ContainerResponse, error) { + log := s.getLoggerFromContext(ctx) + log.Info("container GetPid", "request", req) action := req.Action.Action if action != pb.ContainerAction_GETPID { - err := fmt.Errorf("container action is %s , not getpid", action) + err := errors.Errorf("container action is %s , not getpid", action) log.Error(err, "container action is not expected") return nil, err } diff --git a/pkg/chaosdaemon/container_test.go b/pkg/chaosdaemon/container_test.go index cbde0468df..361a2c2e4a 100644 --- a/pkg/chaosdaemon/container_test.go +++ b/pkg/chaosdaemon/container_test.go @@ -1,34 +1,40 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon import ( "context" - "errors" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/pkg/errors" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients/test" - pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/log" "github.com/chaos-mesh/chaos-mesh/pkg/mock" ) var _ = Describe("container kill", func() { defer mock.With("MockContainerdClient", &test.MockClient{})() - s, _ := newDaemonServer(crclients.ContainerRuntimeContainerd) + logger, err := log.NewDefaultZapLogger() + Expect(err).To(BeNil()) + s, _ := newDaemonServer(&crclients.CrClientConfig{ + Runtime: crclients.ContainerRuntimeContainerd}, nil, logger) Context("ContainerKill", func() { It("should work", func() { diff --git a/pkg/chaosdaemon/crclients/client.go b/pkg/chaosdaemon/crclients/client.go index 8012c86f5a..8a3079da2d 100644 --- a/pkg/chaosdaemon/crclients/client.go +++ b/pkg/chaosdaemon/crclients/client.go @@ -4,18 +4,21 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package crclients import ( "context" - "fmt" + + "github.com/pkg/errors" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients/containerd" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients/crio" @@ -27,45 +30,70 @@ const ( ContainerRuntimeContainerd = "containerd" ContainerRuntimeCrio = "crio" - // TODO(yeya24): make socket and ns configurable defaultDockerSocket = "unix:///var/run/docker.sock" defaultContainerdSocket = "/run/containerd/containerd.sock" defaultCrioSocket = "/var/run/crio/crio.sock" containerdDefaultNS = "k8s.io" ) +// CrClientConfig contains the basic cr client configuration. +type CrClientConfig struct { + // Support docker, containerd, crio for now + Runtime string + SocketPath string + ContainerdNS string +} + // ContainerRuntimeInfoClient represents a struct which can give you information about container runtime type ContainerRuntimeInfoClient interface { GetPidFromContainerID(ctx context.Context, containerID string) (uint32, error) ContainerKillByContainerID(ctx context.Context, containerID string) error FormatContainerID(ctx context.Context, containerID string) (string, error) + ListContainerIDs(ctx context.Context) ([]string, error) + GetLabelsFromContainerID(ctx context.Context, containerID string) (map[string]string, error) } // CreateContainerRuntimeInfoClient creates a container runtime information client. -func CreateContainerRuntimeInfoClient(containerRuntime string) (ContainerRuntimeInfoClient, error) { +func CreateContainerRuntimeInfoClient(clientConfig *CrClientConfig) (ContainerRuntimeInfoClient, error) { // TODO: support more container runtime var cli ContainerRuntimeInfoClient var err error - switch containerRuntime { + socketPath := clientConfig.SocketPath + switch clientConfig.Runtime { case ContainerRuntimeDocker: - cli, err = docker.New(defaultDockerSocket, "", nil, nil) + if socketPath == "" { + socketPath = defaultDockerSocket + } else { + socketPath = "unix://" + socketPath + } + cli, err = docker.New(socketPath, "", nil, nil) if err != nil { return nil, err } case ContainerRuntimeContainerd: // TODO(yeya24): add more options? - cli, err = containerd.New(defaultContainerdSocket, containerd.WithDefaultNamespace(containerdDefaultNS)) + if socketPath == "" { + socketPath = defaultContainerdSocket + } + containerdNS := containerdDefaultNS + if clientConfig.ContainerdNS != "" { + containerdNS = clientConfig.ContainerdNS + } + cli, err = containerd.New(socketPath, containerd.WithDefaultNamespace(containerdNS)) if err != nil { return nil, err } case ContainerRuntimeCrio: - cli, err = crio.New(defaultCrioSocket) + if socketPath == "" { + socketPath = defaultCrioSocket + } + cli, err = crio.New(socketPath) if err != nil { return nil, err } default: - return nil, fmt.Errorf("only docker/containerd/crio is supported, but got %s", containerRuntime) + return nil, errors.Errorf("only docker/containerd/crio is supported, but got %s", clientConfig.Runtime) } return cli, nil diff --git a/pkg/chaosdaemon/crclients/client_test.go b/pkg/chaosdaemon/crclients/client_test.go index 4554e80e93..506a17046a 100644 --- a/pkg/chaosdaemon/crclients/client_test.go +++ b/pkg/chaosdaemon/crclients/client_test.go @@ -4,21 +4,23 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package crclients import ( - "errors" "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/pkg/errors" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients/test" "github.com/chaos-mesh/chaos-mesh/pkg/mock" @@ -26,19 +28,56 @@ import ( var _ = Describe("chaosdaemon util", func() { Context("CreateContainerRuntimeInfoClient", func() { - It("should work", func() { - _, err := CreateContainerRuntimeInfoClient(ContainerRuntimeDocker) + It("should work without socket path", func() { + _, err := CreateContainerRuntimeInfoClient(&CrClientConfig{Runtime: ContainerRuntimeDocker}) + Expect(err).To(BeNil()) + _, err = CreateContainerRuntimeInfoClient(&CrClientConfig{Runtime: ContainerRuntimeDocker}) + Expect(err).To(BeNil()) + defer func() { + err := mock.With("MockContainerdClient", &test.MockClient{})() + Expect(err).To(BeNil()) + }() + _, err = CreateContainerRuntimeInfoClient(&CrClientConfig{Runtime: ContainerRuntimeContainerd}) + Expect(err).To(BeNil()) + }) + + It("should work with socket path", func() { + _, err := CreateContainerRuntimeInfoClient(&CrClientConfig{Runtime: ContainerRuntimeDocker}) + Expect(err).To(BeNil()) + _, err = CreateContainerRuntimeInfoClient(&CrClientConfig{ + Runtime: ContainerRuntimeDocker, + SocketPath: "/foo/bar/docker.socket"}) + Expect(err).To(BeNil()) + defer func() { + err := mock.With("MockContainerdClient", &test.MockClient{})() + Expect(err).To(BeNil()) + }() + _, err = CreateContainerRuntimeInfoClient(&CrClientConfig{ + Runtime: ContainerRuntimeContainerd, + SocketPath: "/foo/bar/containerd.socket"}) Expect(err).To(BeNil()) + }) - defer mock.With("MockContainerdClient", &test.MockClient{})() - _, err = CreateContainerRuntimeInfoClient(ContainerRuntimeContainerd) + It("should work with socket path and ns", func() { + defer func() { + err := mock.With("MockContainerdClient", &test.MockClient{})() + Expect(err).To(BeNil()) + }() + _, err := CreateContainerRuntimeInfoClient(&CrClientConfig{ + Runtime: ContainerRuntimeContainerd, + SocketPath: "/foo/bar/containerd.socket", + ContainerdNS: "chaos-mesh.org"}) Expect(err).To(BeNil()) }) It("should error on newContaineredClient", func() { errorStr := "this is a mocked error" - defer mock.With("NewContainerdClientError", errors.New(errorStr))() - _, err := CreateContainerRuntimeInfoClient(ContainerRuntimeContainerd) + + defer func() { + err := mock.With("NewContainerdClientError", errors.New(errorStr))() + Expect(err).To(BeNil()) + }() + _, err := CreateContainerRuntimeInfoClient(&CrClientConfig{Runtime: ContainerRuntimeContainerd}) Expect(err).ToNot(BeNil()) Expect(fmt.Sprintf("%s", err)).To(Equal(errorStr)) }) diff --git a/pkg/chaosdaemon/crclients/containerd/client.go b/pkg/chaosdaemon/crclients/containerd/client.go index 01f4b56169..4a889a9a40 100644 --- a/pkg/chaosdaemon/crclients/containerd/client.go +++ b/pkg/chaosdaemon/crclients/containerd/client.go @@ -4,12 +4,14 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package containerd @@ -19,17 +21,24 @@ import ( "syscall" "github.com/containerd/containerd" + "github.com/pkg/errors" "github.com/chaos-mesh/chaos-mesh/pkg/mock" ) const ( containerdProtocolPrefix = "containerd://" + + // containerKindLabel is a label key intending to filter sandbox container + // ref: https://github.com/containerd/containerd/blob/main/pkg/cri/server/helpers.go#L74-L80 + containerKindLabel = "io.cri-containerd.kind" + containerKindContainer = "container" ) // ContainerdClientInterface represents the ContainerClient, it's used to simply unit test type ContainerdClientInterface interface { LoadContainer(ctx context.Context, id string) (containerd.Container, error) + Containers(ctx context.Context, filters ...string) ([]containerd.Container, error) } // ContainerdClient can get information from containerd @@ -40,10 +49,10 @@ type ContainerdClient struct { // FormatContainerID strips protocol prefix from the container ID func (c ContainerdClient) FormatContainerID(ctx context.Context, containerID string) (string, error) { if len(containerID) < len(containerdProtocolPrefix) { - return "", fmt.Errorf("container id %s is not a containerd container id", containerID) + return "", errors.Errorf("container id %s is not a containerd container id", containerID) } if containerID[0:len(containerdProtocolPrefix)] != containerdProtocolPrefix { - return "", fmt.Errorf("expected %s but got %s", containerdProtocolPrefix, containerID[0:len(containerdProtocolPrefix)]) + return "", errors.Errorf("expected %s but got %s", containerdProtocolPrefix, containerID[0:len(containerdProtocolPrefix)]) } return containerID[len(containerdProtocolPrefix):], nil } @@ -86,6 +95,44 @@ func (c ContainerdClient) ContainerKillByContainerID(ctx context.Context, contai return err } +// ListContainerIDs lists all container IDs +func (c ContainerdClient) ListContainerIDs(ctx context.Context) ([]string, error) { + // filter sandbox containers + // ref: https://github.com/containerd/containerd/blob/main/pkg/cri/server/helpers.go#L281-L285 + filter := fmt.Sprintf("labels.%q==%q", containerKindLabel, containerKindContainer) + containers, err := c.client.Containers(ctx, filter) + if err != nil { + return nil, err + } + + var ids []string + for _, container := range containers { + id := fmt.Sprintf("%s%s", containerdProtocolPrefix, container.ID()) + ids = append(ids, id) + } + return ids, nil +} + +// GetLabelsFromContainerID returns the labels according to container ID +func (c ContainerdClient) GetLabelsFromContainerID(ctx context.Context, containerID string) (map[string]string, error) { + id, err := c.FormatContainerID(ctx, containerID) + if err != nil { + return nil, err + } + + container, err := c.client.LoadContainer(ctx, id) + if err != nil { + return nil, err + } + + labels, err := container.Labels(ctx) + if err != nil { + return nil, err + } + + return labels, nil +} + func New(address string, opts ...containerd.ClientOpt) (*ContainerdClient, error) { // Mock point to return error in unit test if err := mock.On("NewContainerdClientError"); err != nil { diff --git a/pkg/chaosdaemon/crclients/containerd/client_test.go b/pkg/chaosdaemon/crclients/containerd/client_test.go index 210aea7dde..54306e6e21 100644 --- a/pkg/chaosdaemon/crclients/containerd/client_test.go +++ b/pkg/chaosdaemon/crclients/containerd/client_test.go @@ -4,31 +4,41 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package containerd import ( "context" - "errors" "fmt" + "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/pkg/errors" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients/test" "github.com/chaos-mesh/chaos-mesh/pkg/mock" ) +func TestContainerdClient(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Containerd Container Client Test Suit") +} + var _ = Describe("containerd client", func() { Context("ContainerdClient GetPidFromContainerID", func() { It("should return the magic number 9527", func() { defer mock.With("pid", int(9527))() + m := &test.MockClient{} c := ContainerdClient{client: m} pid, err := c.GetPidFromContainerID(context.TODO(), "containerd://valid-container-id") @@ -101,4 +111,55 @@ var _ = Describe("containerd client", func() { Expect(fmt.Sprintf("%s", err)).To(ContainSubstring("is not a containerd container id")) }) }) + + Context("ContainerdClient ListContainerIDs", func() { + It("should work", func() { + containerID := "valid-container-id" + containerIDWithPrefix := fmt.Sprintf("%s%s", containerdProtocolPrefix, containerID) + defer mock.With("containerID", containerID)() + + m := &test.MockClient{} + c := ContainerdClient{client: m} + containerIDs, err := c.ListContainerIDs(context.Background()) + + Expect(err).To(BeNil()) + Expect(containerIDs).To(Equal([]string{containerIDWithPrefix})) + }) + }) + + Context("ContainerdClient GetLabelsFromContainerID", func() { + It("should work", func() { + sampleLabels := map[string]string{ + "io.kubernetes.pod.namespace": "default", + "io.kubernetes.pod.name": "busybox-5f8dd756dd-6rjzw", + "io.kubernetes.container.name": "busybox", + } + defer mock.With("labels", sampleLabels)() + + m := &test.MockClient{} + c := ContainerdClient{client: m} + labels, err := c.GetLabelsFromContainerID(context.Background(), "containerd://valid-container-id") + + Expect(err).To(BeNil()) + Expect(labels).To(Equal(sampleLabels)) + }) + + It("should error on wrong protocol", func() { + m := &test.MockClient{} + c := ContainerdClient{client: m} + _, err := c.GetLabelsFromContainerID(context.Background(), "docker://this-is-a-wrong-protocol") + + Expect(err).ToNot(BeNil()) + Expect(fmt.Sprintf("%s", err)).To(ContainSubstring(fmt.Sprintf("expected %s but got", containerdProtocolPrefix))) + }) + + It("should error on short protocol", func() { + m := &test.MockClient{} + c := ContainerdClient{client: m} + _, err := c.GetLabelsFromContainerID(context.TODO(), "dock:") + + Expect(err).ToNot(BeNil()) + Expect(fmt.Sprintf("%s", err)).To(ContainSubstring("is not a containerd container id")) + }) + }) }) diff --git a/pkg/chaosdaemon/crclients/crio/client.go b/pkg/chaosdaemon/crclients/crio/client.go index a1f44b39ff..6abce9b6f8 100644 --- a/pkg/chaosdaemon/crclients/crio/client.go +++ b/pkg/chaosdaemon/crclients/crio/client.go @@ -4,24 +4,29 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package crio import ( "context" "encoding/json" - "errors" "fmt" "net" "net/http" "syscall" "time" + + "github.com/pkg/errors" + "google.golang.org/grpc" + v1 "k8s.io/cri-api/pkg/apis/runtime/v1" ) const ( @@ -33,17 +38,18 @@ const ( // CrioClient can get information from docker type CrioClient struct { - client *http.Client - socketPath string + client *http.Client + runtimeClient v1.RuntimeServiceClient + socketPath string } // FormatContainerID strips protocol prefix from the container ID func (c CrioClient) FormatContainerID(ctx context.Context, containerID string) (string, error) { if len(containerID) < len(crioProtocolPrefix) { - return "", fmt.Errorf("container id %s is not a crio container id", containerID) + return "", errors.Errorf("container id %s is not a crio container id", containerID) } if containerID[0:len(crioProtocolPrefix)] != crioProtocolPrefix { - return "", fmt.Errorf("expected %s but got %s", crioProtocolPrefix, containerID[0:len(crioProtocolPrefix)]) + return "", errors.Errorf("expected %s but got %s", crioProtocolPrefix, containerID[0:len(crioProtocolPrefix)]) } return containerID[len(crioProtocolPrefix):], nil } @@ -88,6 +94,49 @@ func (c CrioClient) ContainerKillByContainerID(ctx context.Context, containerID return syscall.Kill(int(pid), syscall.SIGKILL) } +// ListContainerIDs lists all container IDs +func (c CrioClient) ListContainerIDs(ctx context.Context) ([]string, error) { + resp, err := c.runtimeClient.ListContainers(ctx, &v1.ListContainersRequest{}) + if err != nil { + return nil, err + } + + var ids []string + for _, container := range resp.Containers { + id := fmt.Sprintf("%s%s", crioProtocolPrefix, container.Id) + ids = append(ids, id) + } + return ids, nil +} + +// GetLabelsFromContainerID returns the labels according to container ID +func (c CrioClient) GetLabelsFromContainerID(ctx context.Context, containerID string) (map[string]string, error) { + id, err := c.FormatContainerID(ctx, containerID) + if err != nil { + return nil, err + } + + container, err := c.runtimeClient.ContainerStatus(ctx, &v1.ContainerStatusRequest{ + ContainerId: id, + }) + if err != nil { + return nil, err + } + + return container.Status.Labels, nil +} + +func buildRuntimeServiceClient(endpoint string) (v1.RuntimeServiceClient, error) { + addr := fmt.Sprintf("unix://%s", endpoint) + conn, err := grpc.Dial(addr, grpc.WithBlock(), grpc.WithInsecure()) + if err != nil { + return nil, err + } + + client := v1.NewRuntimeServiceClient(conn) + return client, err +} + func New(socketPath string) (*CrioClient, error) { tr := new(http.Transport) if err := configureUnixTransport(tr, "unix", socketPath); err != nil { @@ -96,15 +145,22 @@ func New(socketPath string) (*CrioClient, error) { c := &http.Client{ Transport: tr, } + + runtimeClient, err := buildRuntimeServiceClient(socketPath) + if err != nil { + return nil, err + } + return &CrioClient{ - client: c, - socketPath: socketPath, + client: c, + runtimeClient: runtimeClient, + socketPath: socketPath, }, nil } func configureUnixTransport(tr *http.Transport, proto, addr string) error { if len(addr) > maxUnixSocketPathSize { - return fmt.Errorf("unix socket path %q is too long", addr) + return errors.Errorf("unix socket path %q is too long", addr) } // No need for compression in local communications. tr.DisableCompression = true diff --git a/pkg/chaosdaemon/crclients/docker/client.go b/pkg/chaosdaemon/crclients/docker/client.go index cf83ea4b83..fcb9e64250 100644 --- a/pkg/chaosdaemon/crclients/docker/client.go +++ b/pkg/chaosdaemon/crclients/docker/client.go @@ -4,12 +4,14 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package docker @@ -19,19 +21,27 @@ import ( "net/http" "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" dockerclient "github.com/docker/docker/client" + "github.com/pkg/errors" "github.com/chaos-mesh/chaos-mesh/pkg/mock" ) const ( dockerProtocolPrefix = "docker://" + + // containerKindLabel is a label key intending to filter sandbox container + // ref: https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/dockershim/docker_service.go#L67-L75 + containerKindLabel = "io.kubernetes.docker.type" + containerKindContainer = "container" ) // DockerClientInterface represents the DockerClient, it's used to simply unit test type DockerClientInterface interface { ContainerInspect(ctx context.Context, containerID string) (types.ContainerJSON, error) ContainerKill(ctx context.Context, containerID, signal string) error + ContainerList(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error) } // DockerClient can get information from docker @@ -42,10 +52,10 @@ type DockerClient struct { // FormatContainerID strips protocol prefix from the container ID func (c DockerClient) FormatContainerID(ctx context.Context, containerID string) (string, error) { if len(containerID) < len(dockerProtocolPrefix) { - return "", fmt.Errorf("container id %s is not a docker container id", containerID) + return "", errors.Errorf("container id %s is not a docker container id", containerID) } if containerID[0:len(dockerProtocolPrefix)] != dockerProtocolPrefix { - return "", fmt.Errorf("expected %s but got %s", dockerProtocolPrefix, containerID[0:len(dockerProtocolPrefix)]) + return "", errors.Errorf("expected %s but got %s", dockerProtocolPrefix, containerID[0:len(dockerProtocolPrefix)]) } return containerID[len(dockerProtocolPrefix):], nil } @@ -62,7 +72,7 @@ func (c DockerClient) GetPidFromContainerID(ctx context.Context, containerID str } if container.State.Pid == 0 { - return 0, fmt.Errorf("container is not running, status: %s", container.State.Status) + return 0, errors.Errorf("container is not running, status: %s", container.State.Status) } return uint32(container.State.Pid), nil @@ -79,6 +89,39 @@ func (c DockerClient) ContainerKillByContainerID(ctx context.Context, containerI return err } +// ListContainerIDs lists all container IDs +func (c DockerClient) ListContainerIDs(ctx context.Context) ([]string, error) { + // filter sandbox containers + filterArg := filters.Arg("label", fmt.Sprintf("%s=%s", containerKindLabel, containerKindContainer)) + containers, err := c.client.ContainerList(ctx, types.ContainerListOptions{ + Filters: filters.NewArgs(filterArg), + }) + if err != nil { + return nil, err + } + + var ids []string + for _, container := range containers { + id := fmt.Sprintf("%s%s", dockerProtocolPrefix, container.ID) + ids = append(ids, id) + } + return ids, nil +} + +// GetLabelsFromContainerID returns the labels according to container ID +func (c DockerClient) GetLabelsFromContainerID(ctx context.Context, containerID string) (map[string]string, error) { + id, err := c.FormatContainerID(ctx, containerID) + if err != nil { + return nil, err + } + container, err := c.client.ContainerInspect(ctx, id) + if err != nil { + return nil, err + } + + return container.Config.Labels, nil +} + func New(host string, version string, client *http.Client, httpHeaders map[string]string) (*DockerClient, error) { // Mock point to return error or mock client in unit test if err := mock.On("NewDockerClientError"); err != nil { @@ -91,6 +134,7 @@ func New(host string, version string, client *http.Client, httpHeaders map[strin } c, err := dockerclient.NewClientWithOpts( + dockerclient.FromEnv, dockerclient.WithHost(host), dockerclient.WithVersion(version), dockerclient.WithHTTPClient(client), diff --git a/pkg/chaosdaemon/crclients/docker/client_test.go b/pkg/chaosdaemon/crclients/docker/client_test.go index b523b69d05..efdb69c062 100644 --- a/pkg/chaosdaemon/crclients/docker/client_test.go +++ b/pkg/chaosdaemon/crclients/docker/client_test.go @@ -4,31 +4,41 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package docker import ( "context" - "errors" "fmt" + "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/pkg/errors" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients/test" "github.com/chaos-mesh/chaos-mesh/pkg/mock" ) +func TestDockerClient(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Docker Container Client Test Suit") +} + var _ = Describe("docker client", func() { Context("DockerClient GetPidFromContainerID", func() { It("should return the magic number 9527", func() { defer mock.With("pid", int(9527))() + m := &test.MockClient{} c := DockerClient{client: m} pid, err := c.GetPidFromContainerID(context.TODO(), "docker://valid-container-id") @@ -90,4 +100,61 @@ var _ = Describe("docker client", func() { }) }) + Context("DockerClient ListContainerIDs", func() { + It("should work", func() { + containerID := "valid-container-id" + containerIDWithPrefix := fmt.Sprintf("%s%s", dockerProtocolPrefix, containerID) + defer mock.With("containerID", containerID)() + + m := &test.MockClient{} + c := DockerClient{client: m} + containerIDs, err := c.ListContainerIDs(context.Background()) + + Expect(err).To(BeNil()) + Expect(containerIDs).To(Equal([]string{containerIDWithPrefix})) + }) + }) + + Context("DockerClient GetLabelsFromContainerID", func() { + It("should work", func() { + sampleLabels := map[string]string{ + "io.kubernetes.pod.namespace": "default", + "io.kubernetes.pod.name": "busybox-5f8dd756dd-6rjzw", + "io.kubernetes.container.name": "busybox", + } + defer mock.With("labels", sampleLabels)() + + m := &test.MockClient{} + c := DockerClient{client: m} + labels, err := c.GetLabelsFromContainerID(context.Background(), "docker://valid-container-id") + + Expect(err).To(BeNil()) + Expect(labels).To(Equal(sampleLabels)) + }) + + It("should error on wrong protocol", func() { + sampleLabels := map[string]string{ + "io.kubernetes.pod.namespace": "default", + "io.kubernetes.pod.name": "busybox-5f8dd756dd-6rjzw", + "io.kubernetes.container.name": "busybox", + } + defer mock.With("labels", sampleLabels)() + + m := &test.MockClient{} + c := DockerClient{client: m} + _, err := c.GetLabelsFromContainerID(context.Background(), "containerd://this-is-a-wrong-protocol") + + Expect(err).ToNot(BeNil()) + Expect(fmt.Sprintf("%s", err)).To(ContainSubstring(fmt.Sprintf("expected %s but got", dockerProtocolPrefix))) + }) + + It("should error on short protocol", func() { + m := &test.MockClient{} + c := DockerClient{client: m} + _, err := c.GetLabelsFromContainerID(context.TODO(), "dock:") + + Expect(err).ToNot(BeNil()) + Expect(fmt.Sprintf("%s", err)).To(ContainSubstring("is not a docker container id")) + }) + }) }) diff --git a/pkg/chaosdaemon/crclients/test/mockclient.go b/pkg/chaosdaemon/crclients/test/mockclient.go index b31bfc3e83..c9c3dfe253 100644 --- a/pkg/chaosdaemon/crclients/test/mockclient.go +++ b/pkg/chaosdaemon/crclients/test/mockclient.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package test @@ -20,6 +22,7 @@ import ( "github.com/containerd/containerd" "github.com/containerd/containerd/cio" "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" "github.com/chaos-mesh/chaos-mesh/pkg/mock" ) @@ -31,17 +34,22 @@ func (m *MockClient) ContainerInspect(ctx context.Context, containerID string) ( return types.ContainerJSON{}, err.(error) } - var pid int - if p := mock.On("pid"); p != nil { - pid = p.(int) - } - return types.ContainerJSON{ - ContainerJSONBase: &types.ContainerJSONBase{ + containerJSON := types.ContainerJSON{} + if pid := mock.On("pid"); pid != nil { + containerJSON.ContainerJSONBase = &types.ContainerJSONBase{ State: &types.ContainerState{ - Pid: pid, + Pid: pid.(int), }, - }, - }, nil + } + } + + if labels := mock.On("labels"); labels != nil { + containerJSON.Config = &container.Config{ + Labels: labels.(map[string]string), + } + } + + return containerJSON, nil } func (m *MockClient) ContainerKill(ctx context.Context, containerID, signal string) error { @@ -59,6 +67,27 @@ func (m *MockClient) LoadContainer(ctx context.Context, id string) (containerd.C return &MockContainer{}, nil } +func (m *MockClient) ContainerList(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error) { + if err := mock.On("ContainerListError"); err != nil { + return nil, err.(error) + } + + c := types.Container{} + if id := mock.On("containerID"); id != nil { + c.ID = id.(string) + } + + return []types.Container{c}, nil +} + +func (m *MockClient) Containers(ctx context.Context, filters ...string) ([]containerd.Container, error) { + if err := mock.On("ContainersError"); err != nil { + return nil, err.(error) + } + + return []containerd.Container{&MockContainer{}}, nil +} + type MockContainer struct { containerd.Container } @@ -71,6 +100,28 @@ func (m *MockContainer) Task(context.Context, cio.Attach) (containerd.Task, erro return &MockTask{}, nil } +func (m *MockContainer) ID() string { + if err := mock.On("IDError"); err != nil { + return "" + } + + if id := mock.On("containerID"); id != nil { + return id.(string) + } + return "" +} + +func (m *MockContainer) Labels(ctx context.Context) (map[string]string, error) { + if err := mock.On("LabelsError"); err != nil { + return nil, err.(error) + } + + if labels := mock.On("labels"); labels != nil { + return labels.(map[string]string), nil + } + return nil, nil +} + type MockTask struct { containerd.Task } diff --git a/pkg/chaosdaemon/dns_server.go b/pkg/chaosdaemon/dns_server.go index dcc4f96a39..90f0b6c3ec 100644 --- a/pkg/chaosdaemon/dns_server.go +++ b/pkg/chaosdaemon/dns_server.go @@ -1,26 +1,31 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon import ( "context" "fmt" + "net" "github.com/golang/protobuf/ptypes/empty" + "github.com/pkg/errors" "github.com/chaos-mesh/chaos-mesh/pkg/bpm" pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/util" ) const ( @@ -28,8 +33,12 @@ const ( DNSServerConfFile = "/etc/resolv.conf" ) +var ErrInvalidDNSServer = errors.New("invalid DNS server address") + func (s *DaemonServer) SetDNSServer(ctx context.Context, req *pb.SetDNSServerRequest) (*empty.Empty, error) { + log := s.getLoggerFromContext(ctx) + log.Info("SetDNSServer", "request", req) pid, err := s.crClient.GetPidFromContainerID(ctx, req.ContainerId) if err != nil { @@ -40,8 +49,8 @@ func (s *DaemonServer) SetDNSServer(ctx context.Context, if req.Enable { // set dns server to the chaos dns server's address - if len(req.DnsServer) == 0 { - return &empty.Empty{}, fmt.Errorf("invalid set dns server request %v", req) + if net.ParseIP(req.DnsServer) == nil { + return nil, ErrInvalidDNSServer } // backup the /etc/resolv.conf @@ -50,28 +59,28 @@ func (s *DaemonServer) SetDNSServer(ctx context.Context, processBuilder = processBuilder.SetNS(pid, bpm.MountNS) } - cmd := processBuilder.Build() + cmd := processBuilder.Build(ctx) output, err := cmd.CombinedOutput() if err != nil { log.Error(err, "execute command error", "command", cmd.String(), "output", output) - return nil, err + return nil, util.EncodeOutputToError(output, err) } if len(output) != 0 { log.Info("command output", "output", string(output)) } // add chaos dns server to the first line of /etc/resolv.conf - // Note: can not replace the /etc/resolv.conf like `mv temp resolv.conf`, will execute with error `Device or resource busy` - processBuilder = bpm.DefaultProcessBuilder("sh", "-c", fmt.Sprintf("cp %s temp && sed -i 's/.*nameserver.*/nameserver %s/' temp && cat temp > %s", DNSServerConfFile, req.DnsServer, DNSServerConfFile)).SetContext(ctx) + // Note: can not replace the /etc/resolv.conf like `mv resolv_conf_dnschaos_temp resolv.conf`, will execute with error `Device or resource busy` + processBuilder = bpm.DefaultProcessBuilder("sh", "-c", fmt.Sprintf("cp %s /etc/resolv_conf_dnschaos_temp && sed -i 's/.*nameserver.*/nameserver %s/' /etc/resolv_conf_dnschaos_temp && cat /etc/resolv_conf_dnschaos_temp > %s && rm /etc/resolv_conf_dnschaos_temp", DNSServerConfFile, req.DnsServer, DNSServerConfFile)).SetContext(ctx) if req.EnterNS { processBuilder = processBuilder.SetNS(pid, bpm.MountNS) } - cmd = processBuilder.Build() + cmd = processBuilder.Build(ctx) output, err = cmd.CombinedOutput() if err != nil { log.Error(err, "execute command error", "command", cmd.String(), "output", output) - return nil, err + return nil, util.EncodeOutputToError(output, err) } if len(output) != 0 { log.Info("command output", "output", string(output)) @@ -83,11 +92,11 @@ func (s *DaemonServer) SetDNSServer(ctx context.Context, processBuilder = processBuilder.SetNS(pid, bpm.MountNS) } - cmd := processBuilder.Build() + cmd := processBuilder.Build(ctx) output, err := cmd.CombinedOutput() if err != nil { log.Error(err, "execute command error", "command", cmd.String(), "output", output) - return nil, err + return nil, util.EncodeOutputToError(output, err) } if len(output) != 0 { log.Info("command output", "output", string(output)) diff --git a/pkg/chaosdaemon/dns_server_test.go b/pkg/chaosdaemon/dns_server_test.go new file mode 100644 index 0000000000..6d52e35e79 --- /dev/null +++ b/pkg/chaosdaemon/dns_server_test.go @@ -0,0 +1,137 @@ +// Copyright 2023 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package chaosdaemon_test + +import ( + "context" + "os/exec" + "testing" + + "github.com/go-logr/logr" + . "github.com/onsi/gomega" + + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients/test" + pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/mock" +) + +func Test_SetDNSServer_Enable(t *testing.T) { + g := NewWithT(t) + + type mockCmd struct { + cmd string + args []string + } + var executedCommands []mockCmd + + mock.With("MockProcessBuild", func(ctx context.Context, cmd string, args ...string) *exec.Cmd { + executedCommands = append(executedCommands, mockCmd{cmd, args}) + return exec.Command("echo", "mock command") + }) + + mock.With("MockContainerdClient", &test.MockClient{}) + + crc, err := crclients.CreateContainerRuntimeInfoClient(&crclients.CrClientConfig{ + Runtime: crclients.ContainerRuntimeContainerd, + }) + g.Expect(err).NotTo(HaveOccurred()) + + server := chaosdaemon.NewDaemonServerWithCRClient(crc, nil, logr.Discard()) + + res, err := server.SetDNSServer(context.TODO(), &pb.SetDNSServerRequest{ + ContainerId: "containerd://foo", + DnsServer: "8.6.4.2", + Enable: true, + EnterNS: false, + }) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(res).NotTo(BeNil()) + + g.Expect(executedCommands).To(Equal([]mockCmd{ + {cmd: "sh", args: []string{"-c", "ls /etc/resolv.conf.chaos.bak || cp /etc/resolv.conf /etc/resolv.conf.chaos.bak"}}, + {cmd: "sh", args: []string{"-c", "cp /etc/resolv.conf /etc/resolv_conf_dnschaos_temp && sed -i 's/.*nameserver.*/nameserver 8.6.4.2/' /etc/resolv_conf_dnschaos_temp && cat /etc/resolv_conf_dnschaos_temp > /etc/resolv.conf && rm /etc/resolv_conf_dnschaos_temp"}}, + })) +} + +func Test_SetDNSServer_Enable_InvalidIP(t *testing.T) { + g := NewWithT(t) + + cases := []string{"", "127.0.0.b", " 127.0.0.1", "127.0.0.1 ", ":g:1", "127.0.0.1;"} + + mock.With("MockProcessBuild", func(ctx context.Context, cmd string, args ...string) *exec.Cmd { + g.Fail("no process should be executed") + return exec.Command("echo", "mock command") + }) + + mock.With("MockContainerdClient", &test.MockClient{}) + + crc, err := crclients.CreateContainerRuntimeInfoClient(&crclients.CrClientConfig{ + Runtime: crclients.ContainerRuntimeContainerd, + }) + g.Expect(err).NotTo(HaveOccurred()) + + server := chaosdaemon.NewDaemonServerWithCRClient(crc, nil, logr.Discard()) + + for _, tc := range cases { + res, err := server.SetDNSServer(context.TODO(), &pb.SetDNSServerRequest{ + ContainerId: "containerd://foo", + DnsServer: tc, + Enable: true, + EnterNS: false, + }) + g.Expect(err).To(Equal(chaosdaemon.ErrInvalidDNSServer)) + g.Expect(res).To(BeNil()) + } +} + +func Test_SetDNSServer_Disable(t *testing.T) { + g := NewWithT(t) + + type mockCmd struct { + cmd string + args []string + } + var executedCommands []mockCmd + + mock.With("MockProcessBuild", func(ctx context.Context, cmd string, args ...string) *exec.Cmd { + executedCommands = append(executedCommands, mockCmd{cmd, args}) + return exec.Command("echo", "mock command") + }) + + mock.With("MockContainerdClient", &test.MockClient{}) + + crc, err := crclients.CreateContainerRuntimeInfoClient(&crclients.CrClientConfig{ + Runtime: crclients.ContainerRuntimeContainerd, + }) + g.Expect(err).NotTo(HaveOccurred()) + + server := chaosdaemon.NewDaemonServerWithCRClient(crc, nil, logr.Discard()) + + res, err := server.SetDNSServer(context.TODO(), &pb.SetDNSServerRequest{ + ContainerId: "containerd://foo", + DnsServer: "", + Enable: false, + EnterNS: false, + }) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(res).NotTo(BeNil()) + + g.Expect(executedCommands).To(Equal([]mockCmd{ + {cmd: "sh", args: []string{"-c", "ls /etc/resolv.conf.chaos.bak && cat /etc/resolv.conf.chaos.bak > /etc/resolv.conf || true"}}, + })) +} diff --git a/pkg/chaosdaemon/graph.go b/pkg/chaosdaemon/graph/graph.go similarity index 81% rename from pkg/chaosdaemon/graph.go rename to pkg/chaosdaemon/graph/graph.go index 3d57d63719..5235102b85 100644 --- a/pkg/chaosdaemon/graph.go +++ b/pkg/chaosdaemon/graph/graph.go @@ -1,17 +1,23 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// + +package graph -package chaosdaemon +import ( + "github.com/go-logr/logr" +) // Edge represents an edge in graph type Edge struct { @@ -48,7 +54,7 @@ func (g *Graph) IterFrom(source uint32) *Edge { } // Flatten flattens the subtree from source (without checking whether it's a tree) -func (g *Graph) Flatten(source uint32) []uint32 { +func (g *Graph) Flatten(source uint32, log logr.Logger) []uint32 { current := g.head[source] var flatTree []uint32 @@ -57,7 +63,7 @@ func (g *Graph) Flatten(source uint32) []uint32 { break } - children := g.Flatten(current.Target) + children := g.Flatten(current.Target, log) flatTree = append(flatTree, current.Target) flatTree = append(flatTree, children...) diff --git a/pkg/chaosdaemon/helper/blockchaos.go b/pkg/chaosdaemon/helper/blockchaos.go new file mode 100644 index 0000000000..9266c9b206 --- /dev/null +++ b/pkg/chaosdaemon/helper/blockchaos.go @@ -0,0 +1,115 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package helper + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/moby/sys/mountinfo" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var NormalizeVolumeNameCmd = &cobra.Command{ + Use: "normalize-volume-name [path]", + Short: "get the device name from the path", + Long: `Get the device name from the path. +The path could be a directory, a partition, or a block device. +The block device name will be printed out.`, + Run: func(cmd *cobra.Command, args []string) { + if len(args) != 1 { + cmd.Help() + os.Exit(1) + } + + volumePath := args[0] + deviceName, err := normalizeVolumeName(volumePath) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + fmt.Println(deviceName) + }, +} + +func normalizeVolumeName(volumePath string) (string, error) { + // before resolving the soft link the volumePath inside the request have three possible situations: + // 1. the volumePath is a partition of a block device, e.g. /dev/sda1, or /mnt/disks/ata-CT2000MX500SSD1_2117E599E804-part1 + // 2. the volumePath is a block file path, e.g. /dev/sda, or /mnt/disks/ata-CT2000MX500SSD1_2117E599E804 + // 3. the volumePath is a directory path, e.g. /var/lib/docker/volumes/my-volume + // + // if it's a partition of a block device, we need to convert it to the block file path + // if it's a block device, the client library of chaos-driver can handle it + // if it's a directory, chaos-daemon should automatically convert it to the corresponding block device name + // For example, the return value of this function could be: `sda`, `sdb`, `nvme0n1`, + + volumePath, err := filepath.EvalSymlinks(volumePath) + if err != nil { + return "", errors.Wrapf(err, "resolving symlink %s", volumePath) + } + + stat, err := os.Stat(volumePath) + if err != nil { + return "", errors.Wrapf(err, "getting stat of %s", volumePath) + } + + if stat.IsDir() { + parentMounts, err := mountinfo.GetMounts(mountinfo.ParentsFilter(volumePath)) + if err != nil { + return "", errors.Wrap(err, "read mountinfo") + } + + if len(parentMounts) == 0 { + return "", errors.Errorf("cannot find the mount point which contains the volume path %s", volumePath) + } + + bestMatch := &mountinfo.Info{} + for _, mount := range parentMounts { + mount := mount + if len(mount.Mountpoint) > len(bestMatch.Mountpoint) { + bestMatch = mount + } + } + + if bestMatch.Source == "none" || len(bestMatch.Source) == 0 { + return "", errors.Errorf("unknown source of the mount point %v", bestMatch) + } + volumePath = bestMatch.Source + } + + // now, the `volumePath` is either a partition, or a block device + volumeName := filepath.Base(volumePath) + + // volumeName is either a partition (`sda1`, `nvme0n1p1`), or a block device (`sda`, `nvme0n1`) + if _, err := os.Stat("/sys/block/" + volumeName); errors.Is(err, os.ErrNotExist) { + // the volumeName is a partition, convert it to the block device name + partitionSysPath, err := filepath.EvalSymlinks("/sys/class/block/" + volumeName) + if err != nil { + return "", errors.Wrapf(err, "resolving symlink %s", "/sys/class/block/"+volumeName) + } + + volumeName = filepath.Base(filepath.Dir(partitionSysPath)) + } + return volumeName, nil +} + +// Manually test has been done for the following situations: +// 1. cdh normalize-volume-name /home, where /home is a simple directory +// 2. cdh normalize-volume-name /dev/vda1 +// 3. cdh normalize-volume-name /dev/vda diff --git a/pkg/chaosdaemon/http.go b/pkg/chaosdaemon/http.go index 5931d831f8..6936f52fde 100644 --- a/pkg/chaosdaemon/http.go +++ b/pkg/chaosdaemon/http.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon diff --git a/pkg/chaosdaemon/httpchaos_server.go b/pkg/chaosdaemon/httpchaos_server.go new file mode 100644 index 0000000000..756a0e108b --- /dev/null +++ b/pkg/chaosdaemon/httpchaos_server.go @@ -0,0 +1,202 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package chaosdaemon + +import ( + "bufio" + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "sync" + + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/pkg/bpm" + pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/tproxyconfig" +) + +const ( + tproxyBin = "/usr/local/bin/tproxy" + pathEnv = "PATH" +) + +type stdioTransport struct { + uid string + locker *sync.Map + pipes bpm.Pipes +} + +func (t *stdioTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) { + if _, loaded := t.locker.LoadOrStore(t.uid, true); loaded { + return &http.Response{ + StatusCode: http.StatusLocked, + Status: http.StatusText(http.StatusLocked), + Body: io.NopCloser(bytes.NewBufferString("")), + Request: req, + }, nil + } + defer t.locker.Delete(t.uid) + if t.pipes.Stdin == nil { + return nil, errors.New("fail to get stdin of process") + } + if t.pipes.Stdout == nil { + return nil, errors.New("fail to get stdout of process") + } + + err = req.Write(t.pipes.Stdin) + if err != nil { + return + } + + resp, err = http.ReadResponse(bufio.NewReader(t.pipes.Stdout), req) + return +} + +func (s *DaemonServer) ApplyHttpChaos(ctx context.Context, in *pb.ApplyHttpChaosRequest) (*pb.ApplyHttpChaosResponse, error) { + log := s.getLoggerFromContext(ctx) + log.Info("applying http chaos") + + if in.InstanceUid == "" { + if uid, ok := s.backgroundProcessManager.GetUID(bpm.ProcessPair{Pid: int(in.Instance), CreateTime: in.StartTime}); ok { + in.InstanceUid = uid + } + } + + if _, ok := s.backgroundProcessManager.GetPipes(in.InstanceUid); !ok { + if in.InstanceUid != "" { + // chaos daemon may restart, create another tproxy instance + if err := s.backgroundProcessManager.KillBackgroundProcess(ctx, in.InstanceUid); err != nil { + // ignore this error + log.Error(err, "kill background process", "uid", in.InstanceUid) + } + } + + // set uid internally + if err := s.createHttpChaos(ctx, in); err != nil { + return nil, errors.Wrap(err, "create http chaos") + } + } + + resp, err := s.applyHttpChaos(ctx, in) + if err != nil { + if killError := s.backgroundProcessManager.KillBackgroundProcess(ctx, in.InstanceUid); killError != nil { + log.Error(killError, "kill tproxy", "uid", in.InstanceUid) + } + return nil, errors.Wrap(err, "apply config") + } + return resp, err +} + +func (s *DaemonServer) applyHttpChaos(ctx context.Context, in *pb.ApplyHttpChaosRequest) (*pb.ApplyHttpChaosResponse, error) { + log := s.getLoggerFromContext(ctx) + + pipes, ok := s.backgroundProcessManager.GetPipes(in.InstanceUid) + if !ok { + return nil, errors.Errorf("fail to get process(%s)", in.InstanceUid) + } + + transport := &stdioTransport{ + uid: in.InstanceUid, + locker: s.tproxyLocker, + pipes: pipes, + } + + var rules []tproxyconfig.PodHttpChaosBaseRule + err := json.Unmarshal([]byte(in.Rules), &rules) + if err != nil { + return nil, errors.Wrap(err, "unmarshal rules") + } + + log.Info("the length of actions", "length", len(rules)) + + httpChaosSpec := tproxyconfig.Config{ + ProxyPorts: in.ProxyPorts, + Rules: rules, + } + + if len(in.Tls) != 0 { + httpChaosSpec.TLS = new(tproxyconfig.TLSConfig) + err = json.Unmarshal([]byte(in.Tls), httpChaosSpec.TLS) + if err != nil { + return nil, errors.Wrap(err, "unmarshal tls config") + } + } + + config, err := json.Marshal(&httpChaosSpec) + if err != nil { + return nil, err + } + + log.Info("ready to apply", "config", string(config)) + + req, err := http.NewRequest(http.MethodPut, "/", bytes.NewReader(config)) + if err != nil { + return nil, errors.Wrap(err, "create http request") + } + + resp, err := transport.RoundTrip(req) + if err != nil { + return nil, errors.Wrap(err, "send http request") + } + + log.Info("http chaos applied") + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, errors.Wrap(err, "read response body") + } + + return &pb.ApplyHttpChaosResponse{ + Instance: int64(in.Instance), + InstanceUid: in.InstanceUid, + StartTime: in.StartTime, + StatusCode: int32(resp.StatusCode), + Error: string(body), + }, nil +} + +func (s *DaemonServer) createHttpChaos(ctx context.Context, in *pb.ApplyHttpChaosRequest) error { + pid, err := s.crClient.GetPidFromContainerID(ctx, in.ContainerId) + if err != nil { + return errors.Wrapf(err, "get PID of container(%s)", in.ContainerId) + } + processBuilder := bpm.DefaultProcessBuilder(tproxyBin, "-i", "-vv"). + EnableLocalMnt(). + SetIdentifier(fmt.Sprintf("tproxy-%s", in.ContainerId)). + SetEnv(pathEnv, os.Getenv(pathEnv)) + + if in.EnterNS { + processBuilder = processBuilder.SetNS(pid, bpm.PidNS).SetNS(pid, bpm.NetNS) + } + + cmd := processBuilder.Build(ctx) + cmd.Stderr = os.Stderr + + proc, err := s.backgroundProcessManager.StartProcess(ctx, cmd) + if err != nil { + return errors.Wrapf(err, "execute command(%s)", cmd) + } + + in.Instance = int64(proc.Pair.Pid) + in.StartTime = proc.Pair.CreateTime + in.InstanceUid = proc.Uid + return nil +} diff --git a/pkg/chaosdaemon/iochaos_server.go b/pkg/chaosdaemon/iochaos_server.go index 39494e4c4b..bb6b94de0a 100644 --- a/pkg/chaosdaemon/iochaos_server.go +++ b/pkg/chaosdaemon/iochaos_server.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon @@ -17,14 +19,12 @@ import ( "context" "encoding/json" "fmt" - "io" "os" "strings" "time" - "github.com/shirou/gopsutil/process" - jrpc "github.com/ethereum/go-ethereum/rpc" + "github.com/pkg/errors" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" "github.com/chaos-mesh/chaos-mesh/pkg/bpm" @@ -35,26 +35,32 @@ const ( todaBin = "/usr/local/bin/toda" ) -func (s *DaemonServer) ApplyIoChaos(ctx context.Context, in *pb.ApplyIoChaosRequest) (*pb.ApplyIoChaosResponse, error) { +func (s *DaemonServer) ApplyIOChaos(ctx context.Context, in *pb.ApplyIOChaosRequest) (*pb.ApplyIOChaosResponse, error) { + log := s.getLoggerFromContext(ctx) log.Info("applying io chaos", "Request", in) - if in.Instance != 0 { - err := s.killIoChaos(ctx, in.Instance, in.StartTime) + if in.InstanceUid == "" { + if uid, ok := s.backgroundProcessManager.GetUID(bpm.ProcessPair{Pid: int(in.Instance), CreateTime: in.StartTime}); ok { + in.InstanceUid = uid + } + } + + if in.InstanceUid != "" { + err := s.killIOChaos(ctx, in.InstanceUid) if err != nil { return nil, err } } - actions := []v1alpha1.IoChaosAction{} + actions := []v1alpha1.IOChaosAction{} err := json.Unmarshal([]byte(in.Actions), &actions) if err != nil { - log.Error(err, "error while unmarshal json bytes") - return nil, err + return nil, errors.Wrap(err, "unmarshal json bytes") } log.Info("the length of actions", "length", len(actions)) if len(actions) == 0 { - return &pb.ApplyIoChaosResponse{ + return &pb.ApplyIOChaosResponse{ Instance: 0, StartTime: 0, }, nil @@ -62,8 +68,7 @@ func (s *DaemonServer) ApplyIoChaos(ctx context.Context, in *pb.ApplyIoChaosRequ pid, err := s.crClient.GetPidFromContainerID(ctx, in.ContainerId) if err != nil { - log.Error(err, "error while getting PID") - return nil, err + return nil, errors.Wrap(err, "getting PID") } // TODO: make this log level configurable @@ -72,7 +77,7 @@ func (s *DaemonServer) ApplyIoChaos(ctx context.Context, in *pb.ApplyIoChaosRequ processBuilder := bpm.DefaultProcessBuilder(todaBin, strings.Split(args, " ")...). EnableLocalMnt(). - SetIdentifier(in.ContainerId) + SetIdentifier(fmt.Sprintf("toda-%s", in.ContainerId)) if in.EnterNS { processBuilder = processBuilder.SetNS(pid, bpm.MountNS).SetNS(pid, bpm.PidNS) @@ -80,39 +85,19 @@ func (s *DaemonServer) ApplyIoChaos(ctx context.Context, in *pb.ApplyIoChaosRequ ctx, cancel := context.WithCancel(context.Background()) defer cancel() - caller, receiver := bpm.NewBlockingBuffer(), bpm.NewBlockingBuffer() - defer caller.Close() - defer receiver.Close() - client, err := jrpc.DialIO(ctx, receiver, caller) - if err != nil { - return nil, err - } - - cmd := processBuilder.Build() - cmd.Stdin = caller - cmd.Stdout = io.MultiWriter(receiver, os.Stdout) + cmd := processBuilder.Build(ctx) cmd.Stderr = os.Stderr - err = s.backgroundProcessManager.StartProcess(cmd) + proc, err := s.backgroundProcessManager.StartProcess(ctx, cmd) if err != nil { - log.Error(err, "bpm failed") - return nil, err + return nil, errors.Wrapf(err, "start process `%s`", cmd) } - var ret string - procState, err := process.NewProcess(int32(cmd.Process.Pid)) - if err != nil { - log.Error(err, "new process failed") - return nil, err - } - ct, err := procState.CreateTime() + client, err := jrpc.DialIO(ctx, proc.Pipes.Stdout, proc.Pipes.Stdin) if err != nil { - log.Error(err, "get create time failed") - if kerr := cmd.Process.Kill(); kerr != nil { - log.Error(kerr, "kill toda failed", "request", in) - } - return nil, err + return nil, errors.Wrapf(err, "dialing rpc client") } + var ret string log.Info("Waiting for toda to start") var rpcError error maxWaitTime := time.Millisecond * 2000 @@ -122,27 +107,26 @@ func (s *DaemonServer) ApplyIoChaos(ctx context.Context, in *pb.ApplyIoChaosRequ rpcError = client.CallContext(timeOut, &ret, "get_status", "ping") if rpcError != nil || ret != "ok" { log.Info("Starting toda takes too long or encounter an error") - caller.Close() - receiver.Close() - if kerr := s.killIoChaos(ctx, int64(cmd.Process.Pid), ct); kerr != nil { - log.Error(kerr, "kill toda failed", "request", in) + if kerr := s.killIOChaos(ctx, proc.Uid); kerr != nil { + log.Error(kerr, "kill toda", "request", in) } - return nil, fmt.Errorf("Toda startup takes too long or an error occurs: %s", ret) + return nil, errors.Errorf("toda startup takes too long or an error occurs: %s", ret) } - return &pb.ApplyIoChaosResponse{ - Instance: int64(cmd.Process.Pid), - StartTime: ct, + return &pb.ApplyIOChaosResponse{ + Instance: int64(proc.Pair.Pid), + StartTime: proc.Pair.CreateTime, + InstanceUid: proc.Uid, }, nil } -func (s *DaemonServer) killIoChaos(ctx context.Context, pid int64, startTime int64) error { - log.Info("killing toda", "pid", pid) +func (s *DaemonServer) killIOChaos(ctx context.Context, uid string) error { + log := s.getLoggerFromContext(ctx) - err := s.backgroundProcessManager.KillBackgroundProcess(ctx, int(pid), startTime) + err := s.backgroundProcessManager.KillBackgroundProcess(ctx, uid) if err != nil { - return err + return errors.Wrapf(err, "kill toda %s", uid) } - log.Info("kill toda successfully") + log.Info("kill toda successfully", "uid", uid) return nil } diff --git a/pkg/chaosdaemon/ipset_server.go b/pkg/chaosdaemon/ipset_server.go index 82d10c5ca2..391ecfbaec 100644 --- a/pkg/chaosdaemon/ipset_server.go +++ b/pkg/chaosdaemon/ipset_server.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon @@ -18,10 +20,13 @@ import ( "fmt" "strings" + "github.com/go-logr/logr" "github.com/golang/protobuf/ptypes/empty" + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" "github.com/chaos-mesh/chaos-mesh/pkg/bpm" pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/util" ) const ( @@ -31,6 +36,7 @@ const ( ) func (s *DaemonServer) FlushIPSets(ctx context.Context, req *pb.IPSetsRequest) (*empty.Empty, error) { + log := s.getLoggerFromContext(ctx) log.Info("flush ipset", "request", req) pid, err := s.crClient.GetPidFromContainerID(ctx, req.ContainerId) @@ -50,7 +56,7 @@ func (s *DaemonServer) FlushIPSets(ctx context.Context, req *pb.IPSetsRequest) ( // their linux version to 3.12 :( ipset := ipset s.IPSetLocker.Lock(ipset.Name) - err := flushIPSet(ctx, req.EnterNS, pid, ipset) + err := flushIPSet(ctx, log, req.EnterNS, pid, ipset) s.IPSetLocker.Unlock(ipset.Name) if err != nil { return nil, err @@ -60,42 +66,59 @@ func (s *DaemonServer) FlushIPSets(ctx context.Context, req *pb.IPSetsRequest) ( return &empty.Empty{}, nil } -func flushIPSet(ctx context.Context, enterNS bool, pid uint32, set *pb.IPSet) error { +func flushIPSet(ctx context.Context, log logr.Logger, enterNS bool, pid uint32, set *pb.IPSet) error { name := set.Name - // If the ipset already exists, the ipset will be renamed to this temp name. + // If the IP set already exists, it will be renamed to this temp name. tmpName := fmt.Sprintf("%sold", name) - // the ipset while existing iptables rules are using them can not be deleted,. - // so we creates an temp ipset and swap it with existing one. - if err := createIPSet(ctx, enterNS, pid, tmpName); err != nil { - return err + ipSetType := v1alpha1.IPSetType(set.Type) + var values []string + + switch ipSetType { + case v1alpha1.SetIPSet: + values = set.SetNames + case v1alpha1.NetIPSet: + values = set.Cidrs + case v1alpha1.NetPortIPSet: + for _, cidrAndPort := range set.CidrAndPorts { + values = append(values, fmt.Sprintf("%s,%d", cidrAndPort.Cidr, cidrAndPort.Port)) + } + default: + return fmt.Errorf("unexpected IP set type: %s", ipSetType) } - // add ips to the temp ipset - if err := addCIDRsToIPSet(ctx, enterNS, pid, tmpName, set.Cidrs); err != nil { + // IP sets can't be deleted if there are iptables rules referencing them. + // Therefore, we create new sets and swap them. + if err := createIPSet(ctx, log, enterNS, pid, tmpName, ipSetType); err != nil { return err } - // rename the temp ipset with the target name of ipset if the taget ipset not exists, - // otherwise swap them with each other. - err := renameIPSet(ctx, enterNS, pid, tmpName, name) + // Populate the IP set. + for _, value := range values { + if err := addToIPSet(ctx, log, enterNS, pid, tmpName, value); err != nil { + return err + } + } + + // Finally, rename the IP set to target name. + err := renameIPSet(ctx, log, enterNS, pid, tmpName, name) return err } -func createIPSet(ctx context.Context, enterNS bool, pid uint32, name string) error { +func createIPSet(ctx context.Context, log logr.Logger, enterNS bool, pid uint32, name string, ipSetType v1alpha1.IPSetType) error { // ipset name cannot be longer than 31 bytes if len(name) > 31 { name = name[:31] } - processBuilder := bpm.DefaultProcessBuilder("ipset", "create", name, "hash:net").SetContext(ctx) + processBuilder := bpm.DefaultProcessBuilder("ipset", "create", name, string(ipSetType)).SetContext(ctx) if enterNS { processBuilder = processBuilder.SetNS(pid, bpm.NetNS) } - cmd := processBuilder.Build() + cmd := processBuilder.Build(ctx) log.Info("create ipset", "command", cmd.String()) out, err := cmd.CombinedOutput() @@ -103,7 +126,7 @@ func createIPSet(ctx context.Context, enterNS bool, pid uint32, name string) err output := string(out) if !strings.Contains(output, ipsetExistErr) { log.Error(err, "ipset create error", "command", cmd.String(), "output", output) - return err + return util.EncodeOutputToError(out, err) } processBuilder = bpm.DefaultProcessBuilder("ipset", "flush", name).SetContext(ctx) @@ -111,48 +134,46 @@ func createIPSet(ctx context.Context, enterNS bool, pid uint32, name string) err processBuilder = processBuilder.SetNS(pid, bpm.NetNS) } - cmd = processBuilder.Build() + cmd = processBuilder.Build(ctx) log.Info("flush ipset", "command", cmd.String()) out, err := cmd.CombinedOutput() if err != nil { log.Error(err, "ipset flush error", "command", cmd.String(), "output", string(out)) - return err + return util.EncodeOutputToError(out, err) } } return nil } -func addCIDRsToIPSet(ctx context.Context, enterNS bool, pid uint32, name string, cidrs []string) error { - for _, cidr := range cidrs { - processBuilder := bpm.DefaultProcessBuilder("ipset", "add", name, cidr).SetContext(ctx) - if enterNS { - processBuilder = processBuilder.SetNS(pid, bpm.NetNS) - } - cmd := processBuilder.Build() - log.Info("add CIDR to ipset", "command", cmd.String()) +func addToIPSet(ctx context.Context, log logr.Logger, enterNS bool, pid uint32, name string, value string) error { + processBuilder := bpm.DefaultProcessBuilder("ipset", "add", name, value).SetContext(ctx) + if enterNS { + processBuilder = processBuilder.SetNS(pid, bpm.NetNS) + } + cmd := processBuilder.Build(ctx) + log.Info("add to ipset", "command", cmd.String()) - out, err := cmd.CombinedOutput() - if err != nil { - output := string(out) - if !strings.Contains(output, ipExistErr) { - log.Error(err, "ipset add error", "command", cmd.String(), "output", output) - return err - } + out, err := cmd.CombinedOutput() + if err != nil { + output := string(out) + if !strings.Contains(output, ipExistErr) { + log.Error(err, "ipset add error", "command", cmd.String(), "output", output) + return util.EncodeOutputToError(out, err) } } return nil } -func renameIPSet(ctx context.Context, enterNS bool, pid uint32, oldName string, newName string) error { +func renameIPSet(ctx context.Context, log logr.Logger, enterNS bool, pid uint32, oldName string, newName string) error { processBuilder := bpm.DefaultProcessBuilder("ipset", "rename", oldName, newName).SetContext(ctx) if enterNS { processBuilder = processBuilder.SetNS(pid, bpm.NetNS) } - cmd := processBuilder.Build() + cmd := processBuilder.Build(ctx) log.Info("rename ipset", "command", cmd.String()) out, err := cmd.CombinedOutput() @@ -160,7 +181,7 @@ func renameIPSet(ctx context.Context, enterNS bool, pid uint32, oldName string, output := string(out) if !strings.Contains(output, ipsetNewNameExistErr) { log.Error(err, "rename ipset failed", "command", cmd.String(), "output", output) - return err + return util.EncodeOutputToError(out, err) } // swap the old ipset and the new ipset if the new ipset already exist. @@ -168,13 +189,13 @@ func renameIPSet(ctx context.Context, enterNS bool, pid uint32, oldName string, if enterNS { processBuilder = processBuilder.SetNS(pid, bpm.NetNS) } - cmd := processBuilder.Build() + cmd := processBuilder.Build(ctx) log.Info("swap ipset", "command", cmd.String()) out, err := cmd.CombinedOutput() if err != nil { log.Error(err, "swap ipset failed", "command", cmd.String(), "output", string(out)) - return err + return util.EncodeOutputToError(out, err) } } return nil diff --git a/pkg/chaosdaemon/ipset_server_test.go b/pkg/chaosdaemon/ipset_server_test.go index 303f73dc92..cb02afe9b2 100644 --- a/pkg/chaosdaemon/ipset_server_test.go +++ b/pkg/chaosdaemon/ipset_server_test.go @@ -1,37 +1,43 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon import ( "context" - "errors" - "io/ioutil" "os" "os/exec" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/pkg/errors" + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients/test" - pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/log" "github.com/chaos-mesh/chaos-mesh/pkg/mock" ) var _ = Describe("ipset server", func() { defer mock.With("MockContainerdClient", &test.MockClient{})() - s, _ := newDaemonServer(crclients.ContainerRuntimeContainerd) + logger, err := log.NewDefaultZapLogger() + Expect(err).To(BeNil()) + s, _ := newDaemonServer(&crclients.CrClientConfig{ + Runtime: crclients.ContainerRuntimeContainerd}, nil, logger) Context("createIPSet", func() { It("should work", func() { @@ -46,13 +52,13 @@ var _ = Describe("ipset server", func() { Expect(args[6]).To(Equal("hash:net")) return exec.Command("echo", "mock command") })() - err := createIPSet(context.TODO(), true, 1, "name") + err := createIPSet(context.TODO(), logger, true, 1, "name", v1alpha1.NetIPSet) Expect(err).To(BeNil()) }) It("should work since ipset exist", func() { // The mockfail.sh will fail only once - err := ioutil.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh + err := os.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh echo $1 cat > /tmp/mockfail.sh << EOF #! /bin/sh @@ -65,13 +71,13 @@ exit 1 defer mock.With("MockProcessBuild", func(ctx context.Context, cmd string, args ...string) *exec.Cmd { return exec.Command("/tmp/mockfail.sh", ipsetExistErr) })() - err = createIPSet(context.TODO(), true, 1, "name") + err = createIPSet(context.TODO(), logger, true, 1, "name", v1alpha1.NetIPSet) Expect(err).To(BeNil()) }) It("shoud fail on the first command", func() { // The mockfail.sh will fail - err := ioutil.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh + err := os.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh echo $1 exit 1 `), 0755) @@ -80,13 +86,13 @@ exit 1 defer mock.With("MockProcessBuild", func(context.Context, string, ...string) *exec.Cmd { return exec.Command("/tmp/mockfail.sh", "fail msg") })() - err = createIPSet(context.TODO(), true, 1, "name") + err = createIPSet(context.TODO(), logger, true, 1, "name", v1alpha1.NetIPSet) Expect(err).ToNot(BeNil()) }) It("shoud fail on the second command", func() { // The mockfail.sh will fail - err := ioutil.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh + err := os.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh echo $1 exit 1 `), 0755) @@ -95,23 +101,23 @@ exit 1 defer mock.With("MockProcessBuild", func(context.Context, string, ...string) *exec.Cmd { return exec.Command("/tmp/mockfail.sh", ipsetExistErr) })() - err = createIPSet(context.TODO(), true, 1, "name") + err = createIPSet(context.TODO(), logger, true, 1, "name", v1alpha1.NetIPSet) Expect(err).ToNot(BeNil()) }) }) - Context("addIpsToIPSet", func() { + Context("addToIPSet", func() { It("should work", func() { defer mock.With("MockProcessBuild", func(context.Context, string, ...string) *exec.Cmd { return exec.Command("echo", "mock command") })() - err := addCIDRsToIPSet(context.TODO(), true, 1, "name", []string{"1.1.1.1"}) + err := addToIPSet(context.TODO(), logger, true, 1, "name", "1.1.1.1") Expect(err).To(BeNil()) }) - It("should work since ip exist", func() { + It("should work if ipset exists", func() { // The mockfail.sh will fail - err := ioutil.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh + err := os.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh echo $1 exit 1 `), 0755) @@ -120,13 +126,13 @@ exit 1 defer mock.With("MockProcessBuild", func(context.Context, string, ...string) *exec.Cmd { return exec.Command("/tmp/mockfail.sh", ipExistErr) })() - err = addCIDRsToIPSet(context.TODO(), true, 1, "name", []string{"1.1.1.1"}) + err = addToIPSet(context.TODO(), logger, true, 1, "name", "1.1.1.1") Expect(err).To(BeNil()) }) It("should fail", func() { // The mockfail.sh will fail - err := ioutil.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh + err := os.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh echo $1 exit 1 `), 0755) @@ -135,7 +141,7 @@ exit 1 defer mock.With("MockProcessBuild", func(context.Context, string, ...string) *exec.Cmd { return exec.Command("/tmp/mockfail.sh", "fail msg") })() - err = addCIDRsToIPSet(context.TODO(), true, 1, "name", []string{"1.1.1.1"}) + err = addToIPSet(context.TODO(), logger, true, 1, "name", "1.1.1.1") Expect(err).ToNot(BeNil()) }) }) @@ -145,13 +151,13 @@ exit 1 defer mock.With("MockProcessBuild", func(context.Context, string, ...string) *exec.Cmd { return exec.Command("echo", "mock command") })() - err := renameIPSet(context.TODO(), true, 1, "name", "newname") + err := renameIPSet(context.TODO(), logger, true, 1, "name", "newname") Expect(err).To(BeNil()) }) It("should work since ipset exist", func() { // The mockfail.sh will fail only once - err := ioutil.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh + err := os.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh echo $1 cat > /tmp/mockfail.sh << EOF #! /bin/sh @@ -164,13 +170,13 @@ exit 1 defer mock.With("MockProcessBuild", func(context.Context, string, ...string) *exec.Cmd { return exec.Command("/tmp/mockfail.sh", ipsetNewNameExistErr) })() - err = renameIPSet(context.TODO(), true, 1, "name", "newname") + err = renameIPSet(context.TODO(), logger, true, 1, "name", "newname") Expect(err).To(BeNil()) }) It("shoud fail on the first command", func() { // The mockfail.sh will fail - err := ioutil.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh + err := os.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh echo $1 exit 1 `), 0755) @@ -179,13 +185,13 @@ exit 1 defer mock.With("MockProcessBuild", func(context.Context, string, ...string) *exec.Cmd { return exec.Command("/tmp/mockfail.sh", "fail msg") })() - err = renameIPSet(context.TODO(), true, 1, "name", "newname") + err = renameIPSet(context.TODO(), logger, true, 1, "name", "newname") Expect(err).ToNot(BeNil()) }) It("shoud fail on the second command", func() { // The mockfail.sh will fail - err := ioutil.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh + err := os.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh echo $1 exit 1 `), 0755) @@ -194,7 +200,7 @@ exit 1 defer mock.With("MockProcessBuild", func(context.Context, string, ...string) *exec.Cmd { return exec.Command("/tmp/mockfail.sh", ipsetExistErr) })() - err = renameIPSet(context.TODO(), true, 1, "name", "newname") + err = renameIPSet(context.TODO(), logger, true, 1, "name", "newname") Expect(err).ToNot(BeNil()) }) }) @@ -205,10 +211,26 @@ exit 1 return exec.Command("echo", "mock command") })() _, err := s.FlushIPSets(context.TODO(), &pb.IPSetsRequest{ - Ipsets: []*pb.IPSet{{ - Name: "ipset-name", - Cidrs: []string{"1.1.1.1/32"}, - }}, + Ipsets: []*pb.IPSet{ + { + Name: "ipset-set-name", + Type: "list:set", + SetNames: []string{"set-1", "set-2"}, + }, + { + Name: "ipset-net-name", + Type: "hash:net", + Cidrs: []string{"0.0.0.0/24"}, + }, + { + Name: "ipset-net-port-name", + Type: "hash:net,port", + CidrAndPorts: []*pb.CidrAndPort{{ + Cidr: "1.1.1.1/32", + Port: 80, + }}, + }, + }, ContainerId: "containerd://container-id", EnterNS: true, }) @@ -220,8 +242,8 @@ exit 1 defer mock.With("TaskError", errors.New(errorStr))() _, err := s.FlushIPSets(context.TODO(), &pb.IPSetsRequest{ Ipsets: []*pb.IPSet{{ - Name: "ipset-name", - Cidrs: []string{"1.1.1.1/32"}, + Name: "ipset-name", + SetNames: []string{"set-1", "set-2"}, }}, ContainerId: "containerd://container-id", EnterNS: true, @@ -229,5 +251,18 @@ exit 1 Expect(err).ToNot(BeNil()) Expect(err.Error()).To(Equal(errorStr)) }) + + It("should fail on unknown type", func() { + _, err := s.FlushIPSets(context.TODO(), &pb.IPSetsRequest{ + Ipsets: []*pb.IPSet{{ + Name: "ipset-name", + Type: "foo:bar", + }}, + ContainerId: "containerd://container-id", + EnterNS: true, + }) + Expect(err).ToNot(BeNil()) + Expect(err.Error()).To(Equal("unexpected IP set type: foo:bar")) + }) }) }) diff --git a/pkg/chaosdaemon/iptables_server.go b/pkg/chaosdaemon/iptables_server.go index f7c9da9d8f..7cee2cd696 100644 --- a/pkg/chaosdaemon/iptables_server.go +++ b/pkg/chaosdaemon/iptables_server.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon @@ -19,9 +21,11 @@ import ( "strings" "github.com/golang/protobuf/ptypes/empty" + "github.com/pkg/errors" "github.com/chaos-mesh/chaos-mesh/pkg/bpm" pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/util" ) const ( @@ -31,6 +35,7 @@ const ( ) func (s *DaemonServer) SetIptablesChains(ctx context.Context, req *pb.IptablesChainsRequest) (*empty.Empty, error) { + log := s.getLoggerFromContext(ctx) log.Info("Set iptables chains", "request", req) pid, err := s.crClient.GetPidFromContainerID(ctx, req.ContainerId) @@ -87,34 +92,55 @@ func (iptables *iptablesClient) setIptablesChains(chains []*pb.Chain) error { func (iptables *iptablesClient) setIptablesChain(chain *pb.Chain) error { var matchPart string + var interfaceMatcher string if chain.Direction == pb.Chain_INPUT { - matchPart = "src" + matchPart = "src,dst" + interfaceMatcher = "-i" } else if chain.Direction == pb.Chain_OUTPUT { - matchPart = "dst" + matchPart = "dst,dst" + interfaceMatcher = "-o" } else { - return fmt.Errorf("unknown chain direction %d", chain.Direction) + return errors.Errorf("unknown chain direction %d", chain.Direction) + } + + if chain.Device == "" { + chain.Device = defaultDevice } - protocolAndPort := chain.Protocol - if len(protocolAndPort) > 0 { + protocolAndPort := "" + if len(chain.Protocol) > 0 { + protocolAndPort += fmt.Sprintf("--protocol %s", chain.Protocol) + if len(chain.SourcePorts) > 0 { - protocolAndPort += " " + chain.SourcePorts + if strings.Contains(chain.SourcePorts, ",") { + protocolAndPort += fmt.Sprintf(" -m multiport --source-ports %s", chain.SourcePorts) + } else { + protocolAndPort += fmt.Sprintf(" --source-port %s", chain.SourcePorts) + } } if len(chain.DestinationPorts) > 0 { - protocolAndPort += " " + chain.DestinationPorts + if strings.Contains(chain.DestinationPorts, ",") { + protocolAndPort += fmt.Sprintf(" -m multiport --destination-ports %s", chain.DestinationPorts) + } else { + protocolAndPort += fmt.Sprintf(" --destination-port %s", chain.DestinationPorts) + } + } + + if len(chain.TcpFlags) > 0 { + protocolAndPort += fmt.Sprintf(" --tcp-flags %s", chain.TcpFlags) } } rules := []string{} if len(chain.Ipsets) == 0 { - rules = append(rules, strings.TrimSpace(fmt.Sprintf("-A %s -j %s -w 5 %s", chain.Name, chain.Target, protocolAndPort))) + rules = append(rules, strings.TrimSpace(fmt.Sprintf("-A %s %s %s -j %s -w 5 %s", chain.Name, interfaceMatcher, chain.Device, chain.Target, protocolAndPort))) } for _, ipset := range chain.Ipsets { - rules = append(rules, strings.TrimSpace(fmt.Sprintf("-A %s -m set --match-set %s %s -j %s -w 5 %s", - chain.Name, ipset, matchPart, chain.Target, protocolAndPort))) + rules = append(rules, strings.TrimSpace(fmt.Sprintf("-A %s %s %s -m set --match-set %s %s -j %s -w 5 %s", + chain.Name, interfaceMatcher, chain.Device, ipset, matchPart, chain.Target, protocolAndPort))) } err := iptables.createNewChain(&iptablesChain{ Name: chain.Name, @@ -139,7 +165,7 @@ func (iptables *iptablesClient) setIptablesChain(chain *pb.Chain) error { return err } } else { - return fmt.Errorf("unknown direction %d", chain.Direction) + return errors.Errorf("unknown direction %d", chain.Direction) } return nil } @@ -171,7 +197,7 @@ func (iptables *iptablesClient) createNewChain(chain *iptablesChain) error { if iptables.enterNS { processBuilder = processBuilder.SetNS(iptables.pid, bpm.NetNS) } - cmd := processBuilder.Build() + cmd := processBuilder.Build(iptables.ctx) out, err := cmd.CombinedOutput() if (err == nil && len(out) == 0) || @@ -180,7 +206,7 @@ func (iptables *iptablesClient) createNewChain(chain *iptablesChain) error { return iptables.deleteAndWriteRules(chain) } - return encodeOutputToError(out, err) + return util.EncodeOutputToError(out, err) } // deleteAndWriteRules will remove all existing function in the chain @@ -208,10 +234,10 @@ func (iptables *iptablesClient) ensureRule(chain *iptablesChain, rule string) er if iptables.enterNS { processBuilder = processBuilder.SetNS(iptables.pid, bpm.NetNS) } - cmd := processBuilder.Build() + cmd := processBuilder.Build(iptables.ctx) out, err := cmd.CombinedOutput() if err != nil { - return encodeOutputToError(out, err) + return util.EncodeOutputToError(out, err) } if strings.Contains(string(out), rule) { @@ -224,10 +250,10 @@ func (iptables *iptablesClient) ensureRule(chain *iptablesChain, rule string) er if iptables.enterNS { processBuilder = processBuilder.SetNS(iptables.pid, bpm.NetNS) } - cmd = processBuilder.Build() + cmd = processBuilder.Build(iptables.ctx) out, err = cmd.CombinedOutput() if err != nil { - return encodeOutputToError(out, err) + return util.EncodeOutputToError(out, err) } return nil @@ -238,10 +264,10 @@ func (iptables *iptablesClient) flushIptablesChain(chain *iptablesChain) error { if iptables.enterNS { processBuilder = processBuilder.SetNS(iptables.pid, bpm.NetNS) } - cmd := processBuilder.Build() + cmd := processBuilder.Build(iptables.ctx) out, err := cmd.CombinedOutput() if err != nil { - return encodeOutputToError(out, err) + return util.EncodeOutputToError(out, err) } return nil diff --git a/pkg/chaosdaemon/iptables_server_test.go b/pkg/chaosdaemon/iptables_server_test.go index b268f8324f..10b37562a3 100644 --- a/pkg/chaosdaemon/iptables_server_test.go +++ b/pkg/chaosdaemon/iptables_server_test.go @@ -1,37 +1,42 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon import ( "context" - "errors" - "io/ioutil" "os" "os/exec" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/pkg/errors" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients/test" - pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/log" "github.com/chaos-mesh/chaos-mesh/pkg/mock" ) var _ = Describe("iptables server", func() { defer mock.With("MockContainerdClient", &test.MockClient{})() - s, _ := newDaemonServer(crclients.ContainerRuntimeContainerd) + logger, err := log.NewDefaultZapLogger() + Expect(err).To(BeNil()) + s, _ := newDaemonServer(&crclients.CrClientConfig{ + Runtime: crclients.ContainerRuntimeContainerd}, nil, logger) Context("FlushIptables", func() { It("should work", func() { @@ -98,7 +103,7 @@ var _ = Describe("iptables server", func() { It("should fail on command error", func() { // The mockfail.sh will fail - err := ioutil.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh + err := os.WriteFile("/tmp/mockfail.sh", []byte(`#! /bin/sh exit 1 `), 0755) Expect(err).To(BeNil()) diff --git a/pkg/chaosdaemon/jvm_server.go b/pkg/chaosdaemon/jvm_server.go new file mode 100644 index 0000000000..38170633a8 --- /dev/null +++ b/pkg/chaosdaemon/jvm_server.go @@ -0,0 +1,232 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package chaosdaemon + +import ( + "context" + "fmt" + "os" + "strings" + + "github.com/golang/protobuf/ptypes/empty" + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/pkg/bpm" + pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/util" +) + +const ( + bmInstallCommand = "bminstall.sh -b -Dorg.jboss.byteman.transform.all -Dorg.jboss.byteman.verbose -Dorg.jboss.byteman.compileToBytecode -p %d %d" + bmSubmitCommand = "bmsubmit.sh -p %d -%s %s" +) + +func (s *DaemonServer) InstallJVMRules(ctx context.Context, + req *pb.InstallJVMRulesRequest) (*empty.Empty, error) { + log := s.getLoggerFromContext(ctx) + log.Info("InstallJVMRules", "request", req) + pid, err := s.crClient.GetPidFromContainerID(ctx, req.ContainerId) + if err != nil { + log.Error(err, "GetPidFromContainerID") + return nil, err + } + + containerPids := []uint32{pid} + childPids, err := util.GetChildProcesses(pid, log) + if err != nil { + log.Error(err, "GetChildProcesses") + } + containerPids = append(containerPids, childPids...) + for _, containerPid := range containerPids { + name, err := util.ReadCommName(int(containerPid)) + if err != nil { + log.Error(err, "ReadCommName") + continue + } + if name == "java\n" { + pid = containerPid + break + } + } + + bytemanHome := os.Getenv("BYTEMAN_HOME") + if len(bytemanHome) == 0 { + return nil, errors.New("environment variable BYTEMAN_HOME not set") + } + + // Copy byteman.jar, byteman-helper.jar and chaos-agent.jar into container's namespace. + if req.EnterNS { + processBuilder := bpm.DefaultProcessBuilder("sh", "-c", fmt.Sprintf("mkdir -p %s/lib/", bytemanHome)).SetContext(ctx).SetNS(pid, bpm.MountNS) + output, err := processBuilder.Build(ctx).CombinedOutput() + if err != nil { + return nil, err + } + if len(output) > 0 { + log.Info("mkdir", "output", string(output)) + } + + jars := []string{"byteman.jar", "byteman-helper.jar", "chaos-agent.jar"} + + for _, jar := range jars { + source := fmt.Sprintf("%s/lib/%s", bytemanHome, jar) + dest := fmt.Sprintf("/usr/local/byteman/lib/%s", jar) + + output, err = copyFileAcrossNS(ctx, source, dest, pid) + if err != nil { + return nil, err + } + + log.Info("copy", "jar name", jar, "from source", source, "to destination", dest, "output", string(output)) + } + } + + bmInstallCmd := fmt.Sprintf(bmInstallCommand, req.Port, pid) + processBuilder := bpm.DefaultProcessBuilder("sh", "-c", bmInstallCmd).SetContext(ctx) + if req.EnterNS { + processBuilder = processBuilder.EnableLocalMnt() + } + + cmd := processBuilder.Build(ctx) + output, err := cmd.CombinedOutput() + if err != nil { + // this error will occured when install agent more than once, and will ignore this error and continue to submit rule + errMsg1 := "Agent JAR loaded but agent failed to initialize" + + // these two errors will occured when java version less or euqal to 1.8, and don't know why + // but it can install agent success even with this error, so just ignore it now. + // TODO: Investigate the cause of these two error + errMsg2 := "Provider sun.tools.attach.LinuxAttachProvider not found" + errMsg3 := "install java.io.IOException: Non-numeric value found" + + // this error is caused by the different attach result codes in different java versions. In fact, the agent has attached success, just ignore it here. + // refer to https://stackoverflow.com/questions/54340438/virtualmachine-attach-throws-com-sun-tools-attach-agentloadexception-0-when-usi/54454418#54454418 + errMsg4 := "com.sun.tools.attach.AgentLoadException" + if !strings.Contains(string(output), errMsg1) && !strings.Contains(string(output), errMsg2) && + !strings.Contains(string(output), errMsg3) && !strings.Contains(string(output), errMsg4) { + log.Error(err, string(output)) + return nil, errors.Wrap(err, string(output)) + } + log.Info("exec comamnd", "cmd", cmd.String(), "output", string(output), "error", err.Error()) + } + + // submit helper jar + bmSubmitCmd := fmt.Sprintf(bmSubmitCommand, req.Port, "b", fmt.Sprintf("%s/lib/byteman-helper.jar", os.Getenv("BYTEMAN_HOME"))) + processBuilder = bpm.DefaultProcessBuilder("sh", "-c", bmSubmitCmd).SetContext(ctx) + if req.EnterNS { + processBuilder = processBuilder.SetNS(pid, bpm.NetNS) + } + output, err = processBuilder.Build(ctx).CombinedOutput() + if err != nil { + log.Error(err, string(output)) + return nil, err + } + if len(output) > 0 { + log.Info("submit helper jar", "output", string(output)) + } + + // submit rules + filename, err := writeDataIntoFile(req.Rule, "rule.btm") + if err != nil { + return nil, err + } + + bmSubmitCmd = fmt.Sprintf(bmSubmitCommand, req.Port, "l", filename) + processBuilder = bpm.DefaultProcessBuilder("sh", "-c", bmSubmitCmd).SetContext(ctx) + if req.EnterNS { + processBuilder = processBuilder.SetNS(pid, bpm.NetNS) + } + output, err = processBuilder.Build(ctx).CombinedOutput() + if err != nil { + log.Error(err, string(output)) + return nil, errors.Wrap(err, string(output)) + } + if len(output) > 0 { + log.Info("submit rules", "output", string(output)) + } + + return &empty.Empty{}, nil +} + +func (s *DaemonServer) UninstallJVMRules(ctx context.Context, + req *pb.UninstallJVMRulesRequest) (*empty.Empty, error) { + log := s.getLoggerFromContext(ctx) + log.Info("InstallJVMRules", "request", req) + pid, err := s.crClient.GetPidFromContainerID(ctx, req.ContainerId) + if err != nil { + log.Error(err, "GetPidFromContainerID") + return nil, err + } + + filename, err := writeDataIntoFile(req.Rule, "rule.btm") + if err != nil { + return nil, err + } + log.Info("create btm file", "file", filename) + + bmSubmitCmd := fmt.Sprintf(bmSubmitCommand, req.Port, "u", filename) + processBuilder := bpm.DefaultProcessBuilder("sh", "-c", bmSubmitCmd).SetContext(ctx) + if req.EnterNS { + processBuilder = processBuilder.SetNS(pid, bpm.NetNS) + } + output, err := processBuilder.Build(ctx).CombinedOutput() + if err != nil { + log.Error(err, string(output)) + if strings.Contains(string(output), "No rule scripts to remove") { + return &empty.Empty{}, nil + } + return nil, errors.Wrap(err, string(output)) + } + + if len(output) > 0 { + log.Info(string(output)) + } + + return &empty.Empty{}, nil +} + +func writeDataIntoFile(data string, filename string) (string, error) { + tmpfile, err := os.CreateTemp("", filename) + if err != nil { + return "", err + } + + if _, err := tmpfile.WriteString(data); err != nil { + return "", err + } + + if err := tmpfile.Close(); err != nil { + return "", err + } + + return tmpfile.Name(), err +} + +func copyFileAcrossNS(ctx context.Context, source string, dest string, pid uint32) ([]byte, error) { + sourceFile, err := os.Open(source) + if err != nil { + return nil, err + } + defer sourceFile.Close() + + processBuilder := bpm.DefaultProcessBuilder("sh", "-c", fmt.Sprintf("cat > %s", dest)).SetContext(ctx) + processBuilder = processBuilder.SetNS(pid, bpm.MountNS).SetStdin(sourceFile) + output, err := processBuilder.Build(ctx).CombinedOutput() + if err != nil { + return nil, err + } + + return output, nil +} diff --git a/pkg/chaosdaemon/netem/utils.go b/pkg/chaosdaemon/netem/utils.go index 50f458fd1e..03506ee0be 100644 --- a/pkg/chaosdaemon/netem/utils.go +++ b/pkg/chaosdaemon/netem/utils.go @@ -1,20 +1,24 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package netem import ( "math" + "strconv" + "strings" chaosdaemon "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" ) @@ -51,6 +55,7 @@ func MergeNetem(a, b *chaosdaemon.Netem) *chaosdaemon.Netem { ReorderCorr: maxf32(a.GetReorderCorr(), b.GetReorderCorr()), Corrupt: maxf32(a.GetCorrupt(), b.GetCorrupt()), CorruptCorr: maxf32(a.GetCorruptCorr(), b.GetCorruptCorr()), + Rate: maxRateString(a.GetRate(), b.GetRate()), } } @@ -64,3 +69,58 @@ func maxu32(a, b uint32) uint32 { func maxf32(a, b float32) float32 { return float32(math.Max(float64(a), float64(b))) } + +func parseRate(nu string) uint64 { + // normalize input + s := strings.ToLower(strings.TrimSpace(nu)) + + for i, u := range []string{"tbps", "gbps", "mbps", "kbps", "bps"} { + if strings.HasSuffix(s, u) { + ts := strings.TrimSuffix(s, u) + s := strings.TrimSpace(ts) + + n, err := strconv.ParseUint(s, 10, 64) + + if err != nil { + return 0 + } + + // convert unit to bytes + for j := 4 - i; j > 0; j-- { + n = n * 1024 + } + + return n + } + } + + for i, u := range []string{"tbit", "gbit", "mbit", "kbit", "bit"} { + if strings.HasSuffix(s, u) { + ts := strings.TrimSuffix(s, u) + s := strings.TrimSpace(ts) + + n, err := strconv.ParseUint(s, 10, 64) + + if err != nil { + return 0 + } + + // convert unit to bytes + for j := 4 - i; j > 0; j-- { + n = n * 1000 + } + n = n / 8 + + return n + } + } + + return 0 +} + +func maxRateString(a, b string) string { + if parseRate(a) > parseRate(b) { + return a + } + return b +} diff --git a/pkg/chaosdaemon/netem/utils_test.go b/pkg/chaosdaemon/netem/utils_test.go index 313828a961..f2b9cd4270 100644 --- a/pkg/chaosdaemon/netem/utils_test.go +++ b/pkg/chaosdaemon/netem/utils_test.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package netem @@ -42,6 +44,11 @@ func TestMergeNetem(t *testing.T) { &chaosdaemonpb.Netem{DelayCorr: 90}, &chaosdaemonpb.Netem{Loss: 25, DelayCorr: 100.2}, }, + { + &chaosdaemonpb.Netem{Time: 100}, + &chaosdaemonpb.Netem{Rate: "800kbit"}, + &chaosdaemonpb.Netem{Time: 100, Rate: "800kbit"}, + }, } for _, tc := range cases { diff --git a/pkg/chaosdaemon/pb/chaosdaemon.pb.go b/pkg/chaosdaemon/pb/chaosdaemon.pb.go index bb5d3d2f6d..75642f7c0d 100644 --- a/pkg/chaosdaemon/pb/chaosdaemon.pb.go +++ b/pkg/chaosdaemon/pb/chaosdaemon.pb.go @@ -1,32 +1,35 @@ // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.12.1 // source: chaosdaemon.proto package pb import ( - fmt "fmt" + context "context" + reflect "reflect" + sync "sync" proto "github.com/golang/protobuf/proto" - - math "math" - empty "github.com/golang/protobuf/ptypes/empty" - - context "golang.org/x/net/context" - grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 type Chain_Direction int32 @@ -35,20 +38,43 @@ const ( Chain_OUTPUT Chain_Direction = 1 ) -var Chain_Direction_name = map[int32]string{ - 0: "INPUT", - 1: "OUTPUT", -} -var Chain_Direction_value = map[string]int32{ - "INPUT": 0, - "OUTPUT": 1, +// Enum value maps for Chain_Direction. +var ( + Chain_Direction_name = map[int32]string{ + 0: "INPUT", + 1: "OUTPUT", + } + Chain_Direction_value = map[string]int32{ + "INPUT": 0, + "OUTPUT": 1, + } +) + +func (x Chain_Direction) Enum() *Chain_Direction { + p := new(Chain_Direction) + *p = x + return p } func (x Chain_Direction) String() string { - return proto.EnumName(Chain_Direction_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Chain_Direction) Descriptor() protoreflect.EnumDescriptor { + return file_chaosdaemon_proto_enumTypes[0].Descriptor() +} + +func (Chain_Direction) Type() protoreflect.EnumType { + return &file_chaosdaemon_proto_enumTypes[0] +} + +func (x Chain_Direction) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) } + +// Deprecated: Use Chain_Direction.Descriptor instead. func (Chain_Direction) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{16, 0} + return file_chaosdaemon_proto_rawDescGZIP(), []int{17, 0} } type ContainerAction_Action int32 @@ -58,20 +84,43 @@ const ( ContainerAction_GETPID ContainerAction_Action = 1 ) -var ContainerAction_Action_name = map[int32]string{ - 0: "KILL", - 1: "GETPID", -} -var ContainerAction_Action_value = map[string]int32{ - "KILL": 0, - "GETPID": 1, +// Enum value maps for ContainerAction_Action. +var ( + ContainerAction_Action_name = map[int32]string{ + 0: "KILL", + 1: "GETPID", + } + ContainerAction_Action_value = map[string]int32{ + "KILL": 0, + "GETPID": 1, + } +) + +func (x ContainerAction_Action) Enum() *ContainerAction_Action { + p := new(ContainerAction_Action) + *p = x + return p } func (x ContainerAction_Action) String() string { - return proto.EnumName(ContainerAction_Action_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ContainerAction_Action) Descriptor() protoreflect.EnumDescriptor { + return file_chaosdaemon_proto_enumTypes[1].Descriptor() +} + +func (ContainerAction_Action) Type() protoreflect.EnumType { + return &file_chaosdaemon_proto_enumTypes[1] +} + +func (x ContainerAction_Action) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) } + +// Deprecated: Use ContainerAction_Action.Descriptor instead. func (ContainerAction_Action) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{18, 0} + return file_chaosdaemon_proto_rawDescGZIP(), []int{19, 0} } type ExecStressRequest_Scope int32 @@ -81,20 +130,43 @@ const ( ExecStressRequest_POD ExecStressRequest_Scope = 1 ) -var ExecStressRequest_Scope_name = map[int32]string{ - 0: "CONTAINER", - 1: "POD", -} -var ExecStressRequest_Scope_value = map[string]int32{ - "CONTAINER": 0, - "POD": 1, +// Enum value maps for ExecStressRequest_Scope. +var ( + ExecStressRequest_Scope_name = map[int32]string{ + 0: "CONTAINER", + 1: "POD", + } + ExecStressRequest_Scope_value = map[string]int32{ + "CONTAINER": 0, + "POD": 1, + } +) + +func (x ExecStressRequest_Scope) Enum() *ExecStressRequest_Scope { + p := new(ExecStressRequest_Scope) + *p = x + return p } func (x ExecStressRequest_Scope) String() string { - return proto.EnumName(ExecStressRequest_Scope_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ExecStressRequest_Scope) Descriptor() protoreflect.EnumDescriptor { + return file_chaosdaemon_proto_enumTypes[2].Descriptor() +} + +func (ExecStressRequest_Scope) Type() protoreflect.EnumType { + return &file_chaosdaemon_proto_enumTypes[2] +} + +func (x ExecStressRequest_Scope) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) } + +// Deprecated: Use ExecStressRequest_Scope.Descriptor instead. func (ExecStressRequest_Scope) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{19, 0} + return file_chaosdaemon_proto_rawDescGZIP(), []int{20, 0} } type Tc_Type int32 @@ -104,1641 +176,3768 @@ const ( Tc_BANDWIDTH Tc_Type = 1 ) -var Tc_Type_name = map[int32]string{ - 0: "NETEM", - 1: "BANDWIDTH", -} -var Tc_Type_value = map[string]int32{ - "NETEM": 0, - "BANDWIDTH": 1, +// Enum value maps for Tc_Type. +var ( + Tc_Type_name = map[int32]string{ + 0: "NETEM", + 1: "BANDWIDTH", + } + Tc_Type_value = map[string]int32{ + "NETEM": 0, + "BANDWIDTH": 1, + } +) + +func (x Tc_Type) Enum() *Tc_Type { + p := new(Tc_Type) + *p = x + return p } func (x Tc_Type) String() string { - return proto.EnumName(Tc_Type_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Tc_Type) Descriptor() protoreflect.EnumDescriptor { + return file_chaosdaemon_proto_enumTypes[3].Descriptor() +} + +func (Tc_Type) Type() protoreflect.EnumType { + return &file_chaosdaemon_proto_enumTypes[3] +} + +func (x Tc_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) } + +// Deprecated: Use Tc_Type.Descriptor instead. func (Tc_Type) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{25, 0} + return file_chaosdaemon_proto_rawDescGZIP(), []int{28, 0} } -type TcHandle struct { - Major uint32 `protobuf:"varint,1,opt,name=major,proto3" json:"major,omitempty"` - Minor uint32 `protobuf:"varint,2,opt,name=minor,proto3" json:"minor,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +type ApplyBlockChaosRequest_Action int32 + +const ( + ApplyBlockChaosRequest_Delay ApplyBlockChaosRequest_Action = 0 +) + +// Enum value maps for ApplyBlockChaosRequest_Action. +var ( + ApplyBlockChaosRequest_Action_name = map[int32]string{ + 0: "Delay", + } + ApplyBlockChaosRequest_Action_value = map[string]int32{ + "Delay": 0, + } +) + +func (x ApplyBlockChaosRequest_Action) Enum() *ApplyBlockChaosRequest_Action { + p := new(ApplyBlockChaosRequest_Action) + *p = x + return p } -func (m *TcHandle) Reset() { *m = TcHandle{} } -func (m *TcHandle) String() string { return proto.CompactTextString(m) } -func (*TcHandle) ProtoMessage() {} -func (*TcHandle) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{0} +func (x ApplyBlockChaosRequest_Action) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ApplyBlockChaosRequest_Action) Descriptor() protoreflect.EnumDescriptor { + return file_chaosdaemon_proto_enumTypes[4].Descriptor() +} + +func (ApplyBlockChaosRequest_Action) Type() protoreflect.EnumType { + return &file_chaosdaemon_proto_enumTypes[4] +} + +func (x ApplyBlockChaosRequest_Action) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) } -func (m *TcHandle) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_TcHandle.Unmarshal(m, b) + +// Deprecated: Use ApplyBlockChaosRequest_Action.Descriptor instead. +func (ApplyBlockChaosRequest_Action) EnumDescriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{32, 0} } -func (m *TcHandle) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_TcHandle.Marshal(b, m, deterministic) + +type TcHandle struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Major uint32 `protobuf:"varint,1,opt,name=major,proto3" json:"major,omitempty"` + Minor uint32 `protobuf:"varint,2,opt,name=minor,proto3" json:"minor,omitempty"` } -func (dst *TcHandle) XXX_Merge(src proto.Message) { - xxx_messageInfo_TcHandle.Merge(dst, src) + +func (x *TcHandle) Reset() { + *x = TcHandle{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *TcHandle) XXX_Size() int { - return xxx_messageInfo_TcHandle.Size(m) + +func (x *TcHandle) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *TcHandle) XXX_DiscardUnknown() { - xxx_messageInfo_TcHandle.DiscardUnknown(m) + +func (*TcHandle) ProtoMessage() {} + +func (x *TcHandle) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_TcHandle proto.InternalMessageInfo +// Deprecated: Use TcHandle.ProtoReflect.Descriptor instead. +func (*TcHandle) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{0} +} -func (m *TcHandle) GetMajor() uint32 { - if m != nil { - return m.Major +func (x *TcHandle) GetMajor() uint32 { + if x != nil { + return x.Major } return 0 } -func (m *TcHandle) GetMinor() uint32 { - if m != nil { - return m.Minor +func (x *TcHandle) GetMinor() uint32 { + if x != nil { + return x.Minor } return 0 } type ContainerRequest struct { - Action *ContainerAction `protobuf:"bytes,1,opt,name=action,proto3" json:"action,omitempty"` - ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *ContainerRequest) Reset() { *m = ContainerRequest{} } -func (m *ContainerRequest) String() string { return proto.CompactTextString(m) } -func (*ContainerRequest) ProtoMessage() {} -func (*ContainerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{1} -} -func (m *ContainerRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ContainerRequest.Unmarshal(m, b) -} -func (m *ContainerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ContainerRequest.Marshal(b, m, deterministic) + Action *ContainerAction `protobuf:"bytes,1,opt,name=action,proto3" json:"action,omitempty"` + ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` } -func (dst *ContainerRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ContainerRequest.Merge(dst, src) + +func (x *ContainerRequest) Reset() { + *x = ContainerRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ContainerRequest) XXX_Size() int { - return xxx_messageInfo_ContainerRequest.Size(m) + +func (x *ContainerRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ContainerRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ContainerRequest.DiscardUnknown(m) + +func (*ContainerRequest) ProtoMessage() {} + +func (x *ContainerRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ContainerRequest proto.InternalMessageInfo +// Deprecated: Use ContainerRequest.ProtoReflect.Descriptor instead. +func (*ContainerRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{1} +} -func (m *ContainerRequest) GetAction() *ContainerAction { - if m != nil { - return m.Action +func (x *ContainerRequest) GetAction() *ContainerAction { + if x != nil { + return x.Action } return nil } -func (m *ContainerRequest) GetContainerId() string { - if m != nil { - return m.ContainerId +func (x *ContainerRequest) GetContainerId() string { + if x != nil { + return x.ContainerId } return "" } type ContainerResponse struct { - Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *ContainerResponse) Reset() { *m = ContainerResponse{} } -func (m *ContainerResponse) String() string { return proto.CompactTextString(m) } -func (*ContainerResponse) ProtoMessage() {} -func (*ContainerResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{2} -} -func (m *ContainerResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ContainerResponse.Unmarshal(m, b) -} -func (m *ContainerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ContainerResponse.Marshal(b, m, deterministic) + Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` } -func (dst *ContainerResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ContainerResponse.Merge(dst, src) + +func (x *ContainerResponse) Reset() { + *x = ContainerResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ContainerResponse) XXX_Size() int { - return xxx_messageInfo_ContainerResponse.Size(m) + +func (x *ContainerResponse) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ContainerResponse) XXX_DiscardUnknown() { - xxx_messageInfo_ContainerResponse.DiscardUnknown(m) + +func (*ContainerResponse) ProtoMessage() {} + +func (x *ContainerResponse) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ContainerResponse proto.InternalMessageInfo +// Deprecated: Use ContainerResponse.ProtoReflect.Descriptor instead. +func (*ContainerResponse) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{2} +} -func (m *ContainerResponse) GetPid() uint32 { - if m != nil { - return m.Pid +func (x *ContainerResponse) GetPid() uint32 { + if x != nil { + return x.Pid } return 0 } type NetemRequest struct { - Netem *Netem `protobuf:"bytes,1,opt,name=netem,proto3" json:"netem,omitempty"` - ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - Handle *TcHandle `protobuf:"bytes,3,opt,name=handle,proto3" json:"handle,omitempty"` - Parent *TcHandle `protobuf:"bytes,4,opt,name=parent,proto3" json:"parent,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *NetemRequest) Reset() { *m = NetemRequest{} } -func (m *NetemRequest) String() string { return proto.CompactTextString(m) } -func (*NetemRequest) ProtoMessage() {} -func (*NetemRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{3} -} -func (m *NetemRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_NetemRequest.Unmarshal(m, b) -} -func (m *NetemRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_NetemRequest.Marshal(b, m, deterministic) + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Netem *Netem `protobuf:"bytes,1,opt,name=netem,proto3" json:"netem,omitempty"` + ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + Handle *TcHandle `protobuf:"bytes,3,opt,name=handle,proto3" json:"handle,omitempty"` + Parent *TcHandle `protobuf:"bytes,4,opt,name=parent,proto3" json:"parent,omitempty"` } -func (dst *NetemRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_NetemRequest.Merge(dst, src) + +func (x *NetemRequest) Reset() { + *x = NetemRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *NetemRequest) XXX_Size() int { - return xxx_messageInfo_NetemRequest.Size(m) + +func (x *NetemRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *NetemRequest) XXX_DiscardUnknown() { - xxx_messageInfo_NetemRequest.DiscardUnknown(m) + +func (*NetemRequest) ProtoMessage() {} + +func (x *NetemRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_NetemRequest proto.InternalMessageInfo +// Deprecated: Use NetemRequest.ProtoReflect.Descriptor instead. +func (*NetemRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{3} +} -func (m *NetemRequest) GetNetem() *Netem { - if m != nil { - return m.Netem +func (x *NetemRequest) GetNetem() *Netem { + if x != nil { + return x.Netem } return nil } -func (m *NetemRequest) GetContainerId() string { - if m != nil { - return m.ContainerId +func (x *NetemRequest) GetContainerId() string { + if x != nil { + return x.ContainerId } return "" } -func (m *NetemRequest) GetHandle() *TcHandle { - if m != nil { - return m.Handle +func (x *NetemRequest) GetHandle() *TcHandle { + if x != nil { + return x.Handle } return nil } -func (m *NetemRequest) GetParent() *TcHandle { - if m != nil { - return m.Parent +func (x *NetemRequest) GetParent() *TcHandle { + if x != nil { + return x.Parent } return nil } type Netem struct { - Time uint32 `protobuf:"varint,1,opt,name=time,proto3" json:"time,omitempty"` - Jitter uint32 `protobuf:"varint,2,opt,name=jitter,proto3" json:"jitter,omitempty"` - DelayCorr float32 `protobuf:"fixed32,3,opt,name=delay_corr,json=delayCorr,proto3" json:"delay_corr,omitempty"` - Limit uint32 `protobuf:"varint,4,opt,name=limit,proto3" json:"limit,omitempty"` - Loss float32 `protobuf:"fixed32,5,opt,name=loss,proto3" json:"loss,omitempty"` - LossCorr float32 `protobuf:"fixed32,6,opt,name=loss_corr,json=lossCorr,proto3" json:"loss_corr,omitempty"` - Gap uint32 `protobuf:"varint,7,opt,name=gap,proto3" json:"gap,omitempty"` - Duplicate float32 `protobuf:"fixed32,8,opt,name=duplicate,proto3" json:"duplicate,omitempty"` - DuplicateCorr float32 `protobuf:"fixed32,9,opt,name=duplicate_corr,json=duplicateCorr,proto3" json:"duplicate_corr,omitempty"` - Reorder float32 `protobuf:"fixed32,10,opt,name=reorder,proto3" json:"reorder,omitempty"` - ReorderCorr float32 `protobuf:"fixed32,11,opt,name=reorder_corr,json=reorderCorr,proto3" json:"reorder_corr,omitempty"` - Corrupt float32 `protobuf:"fixed32,12,opt,name=corrupt,proto3" json:"corrupt,omitempty"` - CorruptCorr float32 `protobuf:"fixed32,13,opt,name=corrupt_corr,json=corruptCorr,proto3" json:"corrupt_corr,omitempty"` - Parent *TcHandle `protobuf:"bytes,14,opt,name=parent,proto3" json:"parent,omitempty"` - Handle *TcHandle `protobuf:"bytes,15,opt,name=handle,proto3" json:"handle,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Netem) Reset() { *m = Netem{} } -func (m *Netem) String() string { return proto.CompactTextString(m) } -func (*Netem) ProtoMessage() {} -func (*Netem) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{4} -} -func (m *Netem) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Netem.Unmarshal(m, b) -} -func (m *Netem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Netem.Marshal(b, m, deterministic) + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Time uint32 `protobuf:"varint,1,opt,name=time,proto3" json:"time,omitempty"` + Jitter uint32 `protobuf:"varint,2,opt,name=jitter,proto3" json:"jitter,omitempty"` + DelayCorr float32 `protobuf:"fixed32,3,opt,name=delay_corr,json=delayCorr,proto3" json:"delay_corr,omitempty"` + Limit uint32 `protobuf:"varint,4,opt,name=limit,proto3" json:"limit,omitempty"` + Loss float32 `protobuf:"fixed32,5,opt,name=loss,proto3" json:"loss,omitempty"` + LossCorr float32 `protobuf:"fixed32,6,opt,name=loss_corr,json=lossCorr,proto3" json:"loss_corr,omitempty"` + Gap uint32 `protobuf:"varint,7,opt,name=gap,proto3" json:"gap,omitempty"` + Duplicate float32 `protobuf:"fixed32,8,opt,name=duplicate,proto3" json:"duplicate,omitempty"` + DuplicateCorr float32 `protobuf:"fixed32,9,opt,name=duplicate_corr,json=duplicateCorr,proto3" json:"duplicate_corr,omitempty"` + Reorder float32 `protobuf:"fixed32,10,opt,name=reorder,proto3" json:"reorder,omitempty"` + ReorderCorr float32 `protobuf:"fixed32,11,opt,name=reorder_corr,json=reorderCorr,proto3" json:"reorder_corr,omitempty"` + Corrupt float32 `protobuf:"fixed32,12,opt,name=corrupt,proto3" json:"corrupt,omitempty"` + CorruptCorr float32 `protobuf:"fixed32,13,opt,name=corrupt_corr,json=corruptCorr,proto3" json:"corrupt_corr,omitempty"` + Parent *TcHandle `protobuf:"bytes,14,opt,name=parent,proto3" json:"parent,omitempty"` + Handle *TcHandle `protobuf:"bytes,15,opt,name=handle,proto3" json:"handle,omitempty"` + Rate string `protobuf:"bytes,16,opt,name=rate,proto3" json:"rate,omitempty"` } -func (dst *Netem) XXX_Merge(src proto.Message) { - xxx_messageInfo_Netem.Merge(dst, src) + +func (x *Netem) Reset() { + *x = Netem{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Netem) XXX_Size() int { - return xxx_messageInfo_Netem.Size(m) + +func (x *Netem) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Netem) XXX_DiscardUnknown() { - xxx_messageInfo_Netem.DiscardUnknown(m) + +func (*Netem) ProtoMessage() {} + +func (x *Netem) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Netem proto.InternalMessageInfo +// Deprecated: Use Netem.ProtoReflect.Descriptor instead. +func (*Netem) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{4} +} -func (m *Netem) GetTime() uint32 { - if m != nil { - return m.Time +func (x *Netem) GetTime() uint32 { + if x != nil { + return x.Time } return 0 } -func (m *Netem) GetJitter() uint32 { - if m != nil { - return m.Jitter +func (x *Netem) GetJitter() uint32 { + if x != nil { + return x.Jitter } return 0 } -func (m *Netem) GetDelayCorr() float32 { - if m != nil { - return m.DelayCorr +func (x *Netem) GetDelayCorr() float32 { + if x != nil { + return x.DelayCorr } return 0 } -func (m *Netem) GetLimit() uint32 { - if m != nil { - return m.Limit +func (x *Netem) GetLimit() uint32 { + if x != nil { + return x.Limit } return 0 } -func (m *Netem) GetLoss() float32 { - if m != nil { - return m.Loss +func (x *Netem) GetLoss() float32 { + if x != nil { + return x.Loss } return 0 } -func (m *Netem) GetLossCorr() float32 { - if m != nil { - return m.LossCorr +func (x *Netem) GetLossCorr() float32 { + if x != nil { + return x.LossCorr } return 0 } -func (m *Netem) GetGap() uint32 { - if m != nil { - return m.Gap +func (x *Netem) GetGap() uint32 { + if x != nil { + return x.Gap } return 0 } -func (m *Netem) GetDuplicate() float32 { - if m != nil { - return m.Duplicate +func (x *Netem) GetDuplicate() float32 { + if x != nil { + return x.Duplicate } return 0 } -func (m *Netem) GetDuplicateCorr() float32 { - if m != nil { - return m.DuplicateCorr +func (x *Netem) GetDuplicateCorr() float32 { + if x != nil { + return x.DuplicateCorr } return 0 } -func (m *Netem) GetReorder() float32 { - if m != nil { - return m.Reorder +func (x *Netem) GetReorder() float32 { + if x != nil { + return x.Reorder } return 0 } -func (m *Netem) GetReorderCorr() float32 { - if m != nil { - return m.ReorderCorr +func (x *Netem) GetReorderCorr() float32 { + if x != nil { + return x.ReorderCorr } return 0 } -func (m *Netem) GetCorrupt() float32 { - if m != nil { - return m.Corrupt +func (x *Netem) GetCorrupt() float32 { + if x != nil { + return x.Corrupt } return 0 } -func (m *Netem) GetCorruptCorr() float32 { - if m != nil { - return m.CorruptCorr +func (x *Netem) GetCorruptCorr() float32 { + if x != nil { + return x.CorruptCorr } return 0 } -func (m *Netem) GetParent() *TcHandle { - if m != nil { - return m.Parent +func (x *Netem) GetParent() *TcHandle { + if x != nil { + return x.Parent } return nil } -func (m *Netem) GetHandle() *TcHandle { - if m != nil { - return m.Handle +func (x *Netem) GetHandle() *TcHandle { + if x != nil { + return x.Handle } return nil } -type TbfRequest struct { - Tbf *Tbf `protobuf:"bytes,1,opt,name=tbf,proto3" json:"tbf,omitempty"` - ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +func (x *Netem) GetRate() string { + if x != nil { + return x.Rate + } + return "" } -func (m *TbfRequest) Reset() { *m = TbfRequest{} } -func (m *TbfRequest) String() string { return proto.CompactTextString(m) } -func (*TbfRequest) ProtoMessage() {} -func (*TbfRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{5} -} -func (m *TbfRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_TbfRequest.Unmarshal(m, b) -} -func (m *TbfRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_TbfRequest.Marshal(b, m, deterministic) +type TbfRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Tbf *Tbf `protobuf:"bytes,1,opt,name=tbf,proto3" json:"tbf,omitempty"` + ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` } -func (dst *TbfRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_TbfRequest.Merge(dst, src) + +func (x *TbfRequest) Reset() { + *x = TbfRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *TbfRequest) XXX_Size() int { - return xxx_messageInfo_TbfRequest.Size(m) + +func (x *TbfRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *TbfRequest) XXX_DiscardUnknown() { - xxx_messageInfo_TbfRequest.DiscardUnknown(m) + +func (*TbfRequest) ProtoMessage() {} + +func (x *TbfRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_TbfRequest proto.InternalMessageInfo +// Deprecated: Use TbfRequest.ProtoReflect.Descriptor instead. +func (*TbfRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{5} +} -func (m *TbfRequest) GetTbf() *Tbf { - if m != nil { - return m.Tbf +func (x *TbfRequest) GetTbf() *Tbf { + if x != nil { + return x.Tbf } return nil } -func (m *TbfRequest) GetContainerId() string { - if m != nil { - return m.ContainerId +func (x *TbfRequest) GetContainerId() string { + if x != nil { + return x.ContainerId } return "" } type Tbf struct { - Rate uint64 `protobuf:"varint,1,opt,name=rate,proto3" json:"rate,omitempty"` - Limit uint32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` - Buffer uint32 `protobuf:"varint,3,opt,name=buffer,proto3" json:"buffer,omitempty"` - PeakRate uint64 `protobuf:"varint,4,opt,name=peak_rate,json=peakRate,proto3" json:"peak_rate,omitempty"` - MinBurst uint32 `protobuf:"varint,5,opt,name=min_burst,json=minBurst,proto3" json:"min_burst,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Tbf) Reset() { *m = Tbf{} } -func (m *Tbf) String() string { return proto.CompactTextString(m) } -func (*Tbf) ProtoMessage() {} -func (*Tbf) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{6} -} -func (m *Tbf) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Tbf.Unmarshal(m, b) -} -func (m *Tbf) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Tbf.Marshal(b, m, deterministic) + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Rate string `protobuf:"bytes,1,opt,name=rate,proto3" json:"rate,omitempty"` + Limit uint32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + Buffer uint32 `protobuf:"varint,3,opt,name=buffer,proto3" json:"buffer,omitempty"` + PeakRate uint64 `protobuf:"varint,4,opt,name=peak_rate,json=peakRate,proto3" json:"peak_rate,omitempty"` + MinBurst uint32 `protobuf:"varint,5,opt,name=min_burst,json=minBurst,proto3" json:"min_burst,omitempty"` } -func (dst *Tbf) XXX_Merge(src proto.Message) { - xxx_messageInfo_Tbf.Merge(dst, src) + +func (x *Tbf) Reset() { + *x = Tbf{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Tbf) XXX_Size() int { - return xxx_messageInfo_Tbf.Size(m) + +func (x *Tbf) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Tbf) XXX_DiscardUnknown() { - xxx_messageInfo_Tbf.DiscardUnknown(m) + +func (*Tbf) ProtoMessage() {} + +func (x *Tbf) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Tbf proto.InternalMessageInfo +// Deprecated: Use Tbf.ProtoReflect.Descriptor instead. +func (*Tbf) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{6} +} -func (m *Tbf) GetRate() uint64 { - if m != nil { - return m.Rate +func (x *Tbf) GetRate() string { + if x != nil { + return x.Rate } - return 0 + return "" } -func (m *Tbf) GetLimit() uint32 { - if m != nil { - return m.Limit +func (x *Tbf) GetLimit() uint32 { + if x != nil { + return x.Limit } return 0 } -func (m *Tbf) GetBuffer() uint32 { - if m != nil { - return m.Buffer +func (x *Tbf) GetBuffer() uint32 { + if x != nil { + return x.Buffer } return 0 } -func (m *Tbf) GetPeakRate() uint64 { - if m != nil { - return m.PeakRate +func (x *Tbf) GetPeakRate() uint64 { + if x != nil { + return x.PeakRate } return 0 } -func (m *Tbf) GetMinBurst() uint32 { - if m != nil { - return m.MinBurst +func (x *Tbf) GetMinBurst() uint32 { + if x != nil { + return x.MinBurst } return 0 } type QdiscRequest struct { - Qdisc *Qdisc `protobuf:"bytes,1,opt,name=qdisc,proto3" json:"qdisc,omitempty"` - ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *QdiscRequest) Reset() { *m = QdiscRequest{} } -func (m *QdiscRequest) String() string { return proto.CompactTextString(m) } -func (*QdiscRequest) ProtoMessage() {} -func (*QdiscRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{7} + Qdisc *Qdisc `protobuf:"bytes,1,opt,name=qdisc,proto3" json:"qdisc,omitempty"` + ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` } -func (m *QdiscRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_QdiscRequest.Unmarshal(m, b) -} -func (m *QdiscRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_QdiscRequest.Marshal(b, m, deterministic) -} -func (dst *QdiscRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QdiscRequest.Merge(dst, src) + +func (x *QdiscRequest) Reset() { + *x = QdiscRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *QdiscRequest) XXX_Size() int { - return xxx_messageInfo_QdiscRequest.Size(m) + +func (x *QdiscRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *QdiscRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QdiscRequest.DiscardUnknown(m) + +func (*QdiscRequest) ProtoMessage() {} + +func (x *QdiscRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_QdiscRequest proto.InternalMessageInfo +// Deprecated: Use QdiscRequest.ProtoReflect.Descriptor instead. +func (*QdiscRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{7} +} -func (m *QdiscRequest) GetQdisc() *Qdisc { - if m != nil { - return m.Qdisc +func (x *QdiscRequest) GetQdisc() *Qdisc { + if x != nil { + return x.Qdisc } return nil } -func (m *QdiscRequest) GetContainerId() string { - if m != nil { - return m.ContainerId +func (x *QdiscRequest) GetContainerId() string { + if x != nil { + return x.ContainerId } return "" } type Qdisc struct { - Parent *TcHandle `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"` - Handle *TcHandle `protobuf:"bytes,2,opt,name=handle,proto3" json:"handle,omitempty"` - Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` - Args []string `protobuf:"bytes,4,rep,name=args,proto3" json:"args,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Qdisc) Reset() { *m = Qdisc{} } -func (m *Qdisc) String() string { return proto.CompactTextString(m) } -func (*Qdisc) ProtoMessage() {} -func (*Qdisc) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{8} -} -func (m *Qdisc) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Qdisc.Unmarshal(m, b) -} -func (m *Qdisc) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Qdisc.Marshal(b, m, deterministic) + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Parent *TcHandle `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"` + Handle *TcHandle `protobuf:"bytes,2,opt,name=handle,proto3" json:"handle,omitempty"` + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + Args []string `protobuf:"bytes,4,rep,name=args,proto3" json:"args,omitempty"` } -func (dst *Qdisc) XXX_Merge(src proto.Message) { - xxx_messageInfo_Qdisc.Merge(dst, src) + +func (x *Qdisc) Reset() { + *x = Qdisc{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Qdisc) XXX_Size() int { - return xxx_messageInfo_Qdisc.Size(m) + +func (x *Qdisc) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Qdisc) XXX_DiscardUnknown() { - xxx_messageInfo_Qdisc.DiscardUnknown(m) + +func (*Qdisc) ProtoMessage() {} + +func (x *Qdisc) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Qdisc proto.InternalMessageInfo +// Deprecated: Use Qdisc.ProtoReflect.Descriptor instead. +func (*Qdisc) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{8} +} -func (m *Qdisc) GetParent() *TcHandle { - if m != nil { - return m.Parent +func (x *Qdisc) GetParent() *TcHandle { + if x != nil { + return x.Parent } return nil } -func (m *Qdisc) GetHandle() *TcHandle { - if m != nil { - return m.Handle +func (x *Qdisc) GetHandle() *TcHandle { + if x != nil { + return x.Handle } return nil } -func (m *Qdisc) GetType() string { - if m != nil { - return m.Type +func (x *Qdisc) GetType() string { + if x != nil { + return x.Type } return "" } -func (m *Qdisc) GetArgs() []string { - if m != nil { - return m.Args +func (x *Qdisc) GetArgs() []string { + if x != nil { + return x.Args } return nil } type EmatchFilterRequest struct { - Filter *EmatchFilter `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` - ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *EmatchFilterRequest) Reset() { *m = EmatchFilterRequest{} } -func (m *EmatchFilterRequest) String() string { return proto.CompactTextString(m) } -func (*EmatchFilterRequest) ProtoMessage() {} -func (*EmatchFilterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{9} + Filter *EmatchFilter `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` + ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` } -func (m *EmatchFilterRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EmatchFilterRequest.Unmarshal(m, b) -} -func (m *EmatchFilterRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EmatchFilterRequest.Marshal(b, m, deterministic) -} -func (dst *EmatchFilterRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_EmatchFilterRequest.Merge(dst, src) + +func (x *EmatchFilterRequest) Reset() { + *x = EmatchFilterRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EmatchFilterRequest) XXX_Size() int { - return xxx_messageInfo_EmatchFilterRequest.Size(m) + +func (x *EmatchFilterRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *EmatchFilterRequest) XXX_DiscardUnknown() { - xxx_messageInfo_EmatchFilterRequest.DiscardUnknown(m) + +func (*EmatchFilterRequest) ProtoMessage() {} + +func (x *EmatchFilterRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EmatchFilterRequest proto.InternalMessageInfo +// Deprecated: Use EmatchFilterRequest.ProtoReflect.Descriptor instead. +func (*EmatchFilterRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{9} +} -func (m *EmatchFilterRequest) GetFilter() *EmatchFilter { - if m != nil { - return m.Filter +func (x *EmatchFilterRequest) GetFilter() *EmatchFilter { + if x != nil { + return x.Filter } return nil } -func (m *EmatchFilterRequest) GetContainerId() string { - if m != nil { - return m.ContainerId +func (x *EmatchFilterRequest) GetContainerId() string { + if x != nil { + return x.ContainerId } return "" } type EmatchFilter struct { - Match string `protobuf:"bytes,1,opt,name=match,proto3" json:"match,omitempty"` - Parent *TcHandle `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"` - Classid *TcHandle `protobuf:"bytes,3,opt,name=classid,proto3" json:"classid,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *EmatchFilter) Reset() { *m = EmatchFilter{} } -func (m *EmatchFilter) String() string { return proto.CompactTextString(m) } -func (*EmatchFilter) ProtoMessage() {} -func (*EmatchFilter) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{10} + Match string `protobuf:"bytes,1,opt,name=match,proto3" json:"match,omitempty"` + Parent *TcHandle `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"` + Classid *TcHandle `protobuf:"bytes,3,opt,name=classid,proto3" json:"classid,omitempty"` } -func (m *EmatchFilter) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EmatchFilter.Unmarshal(m, b) -} -func (m *EmatchFilter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EmatchFilter.Marshal(b, m, deterministic) -} -func (dst *EmatchFilter) XXX_Merge(src proto.Message) { - xxx_messageInfo_EmatchFilter.Merge(dst, src) + +func (x *EmatchFilter) Reset() { + *x = EmatchFilter{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EmatchFilter) XXX_Size() int { - return xxx_messageInfo_EmatchFilter.Size(m) + +func (x *EmatchFilter) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *EmatchFilter) XXX_DiscardUnknown() { - xxx_messageInfo_EmatchFilter.DiscardUnknown(m) + +func (*EmatchFilter) ProtoMessage() {} + +func (x *EmatchFilter) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EmatchFilter proto.InternalMessageInfo +// Deprecated: Use EmatchFilter.ProtoReflect.Descriptor instead. +func (*EmatchFilter) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{10} +} -func (m *EmatchFilter) GetMatch() string { - if m != nil { - return m.Match +func (x *EmatchFilter) GetMatch() string { + if x != nil { + return x.Match } return "" } -func (m *EmatchFilter) GetParent() *TcHandle { - if m != nil { - return m.Parent +func (x *EmatchFilter) GetParent() *TcHandle { + if x != nil { + return x.Parent } return nil } -func (m *EmatchFilter) GetClassid() *TcHandle { - if m != nil { - return m.Classid +func (x *EmatchFilter) GetClassid() *TcHandle { + if x != nil { + return x.Classid } return nil } type TcFilterRequest struct { - Filter *TcFilter `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` - ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *TcFilterRequest) Reset() { *m = TcFilterRequest{} } -func (m *TcFilterRequest) String() string { return proto.CompactTextString(m) } -func (*TcFilterRequest) ProtoMessage() {} -func (*TcFilterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{11} + Filter *TcFilter `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` + ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` } -func (m *TcFilterRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_TcFilterRequest.Unmarshal(m, b) -} -func (m *TcFilterRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_TcFilterRequest.Marshal(b, m, deterministic) -} -func (dst *TcFilterRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_TcFilterRequest.Merge(dst, src) + +func (x *TcFilterRequest) Reset() { + *x = TcFilterRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *TcFilterRequest) XXX_Size() int { - return xxx_messageInfo_TcFilterRequest.Size(m) + +func (x *TcFilterRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *TcFilterRequest) XXX_DiscardUnknown() { - xxx_messageInfo_TcFilterRequest.DiscardUnknown(m) + +func (*TcFilterRequest) ProtoMessage() {} + +func (x *TcFilterRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_TcFilterRequest proto.InternalMessageInfo +// Deprecated: Use TcFilterRequest.ProtoReflect.Descriptor instead. +func (*TcFilterRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{11} +} -func (m *TcFilterRequest) GetFilter() *TcFilter { - if m != nil { - return m.Filter +func (x *TcFilterRequest) GetFilter() *TcFilter { + if x != nil { + return x.Filter } return nil } -func (m *TcFilterRequest) GetContainerId() string { - if m != nil { - return m.ContainerId +func (x *TcFilterRequest) GetContainerId() string { + if x != nil { + return x.ContainerId } return "" } type TcFilter struct { - Parent *TcHandle `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *TcFilter) Reset() { *m = TcFilter{} } -func (m *TcFilter) String() string { return proto.CompactTextString(m) } -func (*TcFilter) ProtoMessage() {} -func (*TcFilter) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{12} + Parent *TcHandle `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"` } -func (m *TcFilter) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_TcFilter.Unmarshal(m, b) -} -func (m *TcFilter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_TcFilter.Marshal(b, m, deterministic) -} -func (dst *TcFilter) XXX_Merge(src proto.Message) { - xxx_messageInfo_TcFilter.Merge(dst, src) + +func (x *TcFilter) Reset() { + *x = TcFilter{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *TcFilter) XXX_Size() int { - return xxx_messageInfo_TcFilter.Size(m) + +func (x *TcFilter) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *TcFilter) XXX_DiscardUnknown() { - xxx_messageInfo_TcFilter.DiscardUnknown(m) + +func (*TcFilter) ProtoMessage() {} + +func (x *TcFilter) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_TcFilter proto.InternalMessageInfo +// Deprecated: Use TcFilter.ProtoReflect.Descriptor instead. +func (*TcFilter) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{12} +} -func (m *TcFilter) GetParent() *TcHandle { - if m != nil { - return m.Parent +func (x *TcFilter) GetParent() *TcHandle { + if x != nil { + return x.Parent } return nil } type IPSetsRequest struct { - Ipsets []*IPSet `protobuf:"bytes,1,rep,name=ipsets,proto3" json:"ipsets,omitempty"` - ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - EnterNS bool `protobuf:"varint,3,opt,name=enterNS,proto3" json:"enterNS,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *IPSetsRequest) Reset() { *m = IPSetsRequest{} } -func (m *IPSetsRequest) String() string { return proto.CompactTextString(m) } -func (*IPSetsRequest) ProtoMessage() {} -func (*IPSetsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{13} + Ipsets []*IPSet `protobuf:"bytes,1,rep,name=ipsets,proto3" json:"ipsets,omitempty"` + ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + EnterNS bool `protobuf:"varint,3,opt,name=enterNS,proto3" json:"enterNS,omitempty"` } -func (m *IPSetsRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_IPSetsRequest.Unmarshal(m, b) -} -func (m *IPSetsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_IPSetsRequest.Marshal(b, m, deterministic) -} -func (dst *IPSetsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_IPSetsRequest.Merge(dst, src) + +func (x *IPSetsRequest) Reset() { + *x = IPSetsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *IPSetsRequest) XXX_Size() int { - return xxx_messageInfo_IPSetsRequest.Size(m) + +func (x *IPSetsRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *IPSetsRequest) XXX_DiscardUnknown() { - xxx_messageInfo_IPSetsRequest.DiscardUnknown(m) + +func (*IPSetsRequest) ProtoMessage() {} + +func (x *IPSetsRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_IPSetsRequest proto.InternalMessageInfo +// Deprecated: Use IPSetsRequest.ProtoReflect.Descriptor instead. +func (*IPSetsRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{13} +} -func (m *IPSetsRequest) GetIpsets() []*IPSet { - if m != nil { - return m.Ipsets +func (x *IPSetsRequest) GetIpsets() []*IPSet { + if x != nil { + return x.Ipsets } return nil } -func (m *IPSetsRequest) GetContainerId() string { - if m != nil { - return m.ContainerId +func (x *IPSetsRequest) GetContainerId() string { + if x != nil { + return x.ContainerId } return "" } -func (m *IPSetsRequest) GetEnterNS() bool { - if m != nil { - return m.EnterNS +func (x *IPSetsRequest) GetEnterNS() bool { + if x != nil { + return x.EnterNS } return false } type IPSet struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Cidrs []string `protobuf:"bytes,2,rep,name=cidrs,proto3" json:"cidrs,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *IPSet) Reset() { *m = IPSet{} } -func (m *IPSet) String() string { return proto.CompactTextString(m) } -func (*IPSet) ProtoMessage() {} -func (*IPSet) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{14} + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Cidrs []string `protobuf:"bytes,2,rep,name=cidrs,proto3" json:"cidrs,omitempty"` + CidrAndPorts []*CidrAndPort `protobuf:"bytes,3,rep,name=cidr_and_ports,json=cidrAndPorts,proto3" json:"cidr_and_ports,omitempty"` + SetNames []string `protobuf:"bytes,4,rep,name=set_names,json=setNames,proto3" json:"set_names,omitempty"` + Type string `protobuf:"bytes,5,opt,name=type,proto3" json:"type,omitempty"` } -func (m *IPSet) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_IPSet.Unmarshal(m, b) -} -func (m *IPSet) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_IPSet.Marshal(b, m, deterministic) -} -func (dst *IPSet) XXX_Merge(src proto.Message) { - xxx_messageInfo_IPSet.Merge(dst, src) -} -func (m *IPSet) XXX_Size() int { - return xxx_messageInfo_IPSet.Size(m) + +func (x *IPSet) Reset() { + *x = IPSet{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *IPSet) XXX_DiscardUnknown() { - xxx_messageInfo_IPSet.DiscardUnknown(m) + +func (x *IPSet) String() string { + return protoimpl.X.MessageStringOf(x) } -var xxx_messageInfo_IPSet proto.InternalMessageInfo +func (*IPSet) ProtoMessage() {} -func (m *IPSet) GetName() string { - if m != nil { - return m.Name +func (x *IPSet) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return "" + return mi.MessageOf(x) } -func (m *IPSet) GetCidrs() []string { - if m != nil { - return m.Cidrs - } +// Deprecated: Use IPSet.ProtoReflect.Descriptor instead. +func (*IPSet) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{14} +} + +func (x *IPSet) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *IPSet) GetCidrs() []string { + if x != nil { + return x.Cidrs + } return nil } -type IptablesChainsRequest struct { - Chains []*Chain `protobuf:"bytes,1,rep,name=chains,proto3" json:"chains,omitempty"` - ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - EnterNS bool `protobuf:"varint,3,opt,name=enterNS,proto3" json:"enterNS,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +func (x *IPSet) GetCidrAndPorts() []*CidrAndPort { + if x != nil { + return x.CidrAndPorts + } + return nil } -func (m *IptablesChainsRequest) Reset() { *m = IptablesChainsRequest{} } -func (m *IptablesChainsRequest) String() string { return proto.CompactTextString(m) } -func (*IptablesChainsRequest) ProtoMessage() {} -func (*IptablesChainsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{15} +func (x *IPSet) GetSetNames() []string { + if x != nil { + return x.SetNames + } + return nil +} + +func (x *IPSet) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +type CidrAndPort struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cidr string `protobuf:"bytes,1,opt,name=cidr,proto3" json:"cidr,omitempty"` + Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` +} + +func (x *CidrAndPort) Reset() { + *x = CidrAndPort{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CidrAndPort) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CidrAndPort) ProtoMessage() {} + +func (x *CidrAndPort) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CidrAndPort.ProtoReflect.Descriptor instead. +func (*CidrAndPort) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{15} +} + +func (x *CidrAndPort) GetCidr() string { + if x != nil { + return x.Cidr + } + return "" } -func (m *IptablesChainsRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_IptablesChainsRequest.Unmarshal(m, b) + +func (x *CidrAndPort) GetPort() uint32 { + if x != nil { + return x.Port + } + return 0 } -func (m *IptablesChainsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_IptablesChainsRequest.Marshal(b, m, deterministic) + +type IptablesChainsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Chains []*Chain `protobuf:"bytes,1,rep,name=chains,proto3" json:"chains,omitempty"` + ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + EnterNS bool `protobuf:"varint,3,opt,name=enterNS,proto3" json:"enterNS,omitempty"` } -func (dst *IptablesChainsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_IptablesChainsRequest.Merge(dst, src) + +func (x *IptablesChainsRequest) Reset() { + *x = IptablesChainsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *IptablesChainsRequest) XXX_Size() int { - return xxx_messageInfo_IptablesChainsRequest.Size(m) + +func (x *IptablesChainsRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *IptablesChainsRequest) XXX_DiscardUnknown() { - xxx_messageInfo_IptablesChainsRequest.DiscardUnknown(m) + +func (*IptablesChainsRequest) ProtoMessage() {} + +func (x *IptablesChainsRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_IptablesChainsRequest proto.InternalMessageInfo +// Deprecated: Use IptablesChainsRequest.ProtoReflect.Descriptor instead. +func (*IptablesChainsRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{16} +} -func (m *IptablesChainsRequest) GetChains() []*Chain { - if m != nil { - return m.Chains +func (x *IptablesChainsRequest) GetChains() []*Chain { + if x != nil { + return x.Chains } return nil } -func (m *IptablesChainsRequest) GetContainerId() string { - if m != nil { - return m.ContainerId +func (x *IptablesChainsRequest) GetContainerId() string { + if x != nil { + return x.ContainerId } return "" } -func (m *IptablesChainsRequest) GetEnterNS() bool { - if m != nil { - return m.EnterNS +func (x *IptablesChainsRequest) GetEnterNS() bool { + if x != nil { + return x.EnterNS } return false } type Chain struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Direction Chain_Direction `protobuf:"varint,2,opt,name=direction,proto3,enum=pb.Chain_Direction" json:"direction,omitempty"` - Ipsets []string `protobuf:"bytes,3,rep,name=ipsets,proto3" json:"ipsets,omitempty"` - Target string `protobuf:"bytes,4,opt,name=target,proto3" json:"target,omitempty"` - Protocol string `protobuf:"bytes,5,opt,name=protocol,proto3" json:"protocol,omitempty"` - SourcePorts string `protobuf:"bytes,6,opt,name=source_ports,json=sourcePorts,proto3" json:"source_ports,omitempty"` - DestinationPorts string `protobuf:"bytes,7,opt,name=destination_ports,json=destinationPorts,proto3" json:"destination_ports,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Chain) Reset() { *m = Chain{} } -func (m *Chain) String() string { return proto.CompactTextString(m) } -func (*Chain) ProtoMessage() {} -func (*Chain) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{16} -} -func (m *Chain) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Chain.Unmarshal(m, b) -} -func (m *Chain) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Chain.Marshal(b, m, deterministic) + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Direction Chain_Direction `protobuf:"varint,2,opt,name=direction,proto3,enum=pb.Chain_Direction" json:"direction,omitempty"` + Ipsets []string `protobuf:"bytes,3,rep,name=ipsets,proto3" json:"ipsets,omitempty"` + Target string `protobuf:"bytes,4,opt,name=target,proto3" json:"target,omitempty"` + Protocol string `protobuf:"bytes,5,opt,name=protocol,proto3" json:"protocol,omitempty"` + SourcePorts string `protobuf:"bytes,6,opt,name=source_ports,json=sourcePorts,proto3" json:"source_ports,omitempty"` + DestinationPorts string `protobuf:"bytes,7,opt,name=destination_ports,json=destinationPorts,proto3" json:"destination_ports,omitempty"` + TcpFlags string `protobuf:"bytes,8,opt,name=tcp_flags,json=tcpFlags,proto3" json:"tcp_flags,omitempty"` + Device string `protobuf:"bytes,9,opt,name=device,proto3" json:"device,omitempty"` } -func (dst *Chain) XXX_Merge(src proto.Message) { - xxx_messageInfo_Chain.Merge(dst, src) + +func (x *Chain) Reset() { + *x = Chain{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Chain) XXX_Size() int { - return xxx_messageInfo_Chain.Size(m) + +func (x *Chain) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Chain) XXX_DiscardUnknown() { - xxx_messageInfo_Chain.DiscardUnknown(m) + +func (*Chain) ProtoMessage() {} + +func (x *Chain) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Chain proto.InternalMessageInfo +// Deprecated: Use Chain.ProtoReflect.Descriptor instead. +func (*Chain) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{17} +} -func (m *Chain) GetName() string { - if m != nil { - return m.Name +func (x *Chain) GetName() string { + if x != nil { + return x.Name } return "" } -func (m *Chain) GetDirection() Chain_Direction { - if m != nil { - return m.Direction +func (x *Chain) GetDirection() Chain_Direction { + if x != nil { + return x.Direction } return Chain_INPUT } -func (m *Chain) GetIpsets() []string { - if m != nil { - return m.Ipsets +func (x *Chain) GetIpsets() []string { + if x != nil { + return x.Ipsets } return nil } -func (m *Chain) GetTarget() string { - if m != nil { - return m.Target +func (x *Chain) GetTarget() string { + if x != nil { + return x.Target } return "" } -func (m *Chain) GetProtocol() string { - if m != nil { - return m.Protocol +func (x *Chain) GetProtocol() string { + if x != nil { + return x.Protocol } return "" } -func (m *Chain) GetSourcePorts() string { - if m != nil { - return m.SourcePorts +func (x *Chain) GetSourcePorts() string { + if x != nil { + return x.SourcePorts } return "" } -func (m *Chain) GetDestinationPorts() string { - if m != nil { - return m.DestinationPorts +func (x *Chain) GetDestinationPorts() string { + if x != nil { + return x.DestinationPorts } return "" } -type TimeRequest struct { - ContainerId string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - Sec int64 `protobuf:"varint,2,opt,name=sec,proto3" json:"sec,omitempty"` - Nsec int64 `protobuf:"varint,3,opt,name=nsec,proto3" json:"nsec,omitempty"` - ClkIdsMask uint64 `protobuf:"varint,4,opt,name=clk_ids_mask,json=clkIdsMask,proto3" json:"clk_ids_mask,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *TimeRequest) Reset() { *m = TimeRequest{} } -func (m *TimeRequest) String() string { return proto.CompactTextString(m) } -func (*TimeRequest) ProtoMessage() {} -func (*TimeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{17} +func (x *Chain) GetTcpFlags() string { + if x != nil { + return x.TcpFlags + } + return "" } -func (m *TimeRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_TimeRequest.Unmarshal(m, b) + +func (x *Chain) GetDevice() string { + if x != nil { + return x.Device + } + return "" } -func (m *TimeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_TimeRequest.Marshal(b, m, deterministic) + +type TimeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ContainerId string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + Sec int64 `protobuf:"varint,2,opt,name=sec,proto3" json:"sec,omitempty"` + Nsec int64 `protobuf:"varint,3,opt,name=nsec,proto3" json:"nsec,omitempty"` + ClkIdsMask uint64 `protobuf:"varint,4,opt,name=clk_ids_mask,json=clkIdsMask,proto3" json:"clk_ids_mask,omitempty"` + Uid string `protobuf:"bytes,5,opt,name=uid,proto3" json:"uid,omitempty"` + PodContainerName string `protobuf:"bytes,6,opt,name=pod_container_name,json=podContainerName,proto3" json:"pod_container_name,omitempty"` } -func (dst *TimeRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_TimeRequest.Merge(dst, src) + +func (x *TimeRequest) Reset() { + *x = TimeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *TimeRequest) XXX_Size() int { - return xxx_messageInfo_TimeRequest.Size(m) + +func (x *TimeRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *TimeRequest) XXX_DiscardUnknown() { - xxx_messageInfo_TimeRequest.DiscardUnknown(m) + +func (*TimeRequest) ProtoMessage() {} + +func (x *TimeRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_TimeRequest proto.InternalMessageInfo +// Deprecated: Use TimeRequest.ProtoReflect.Descriptor instead. +func (*TimeRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{18} +} -func (m *TimeRequest) GetContainerId() string { - if m != nil { - return m.ContainerId +func (x *TimeRequest) GetContainerId() string { + if x != nil { + return x.ContainerId } return "" } -func (m *TimeRequest) GetSec() int64 { - if m != nil { - return m.Sec +func (x *TimeRequest) GetSec() int64 { + if x != nil { + return x.Sec } return 0 } -func (m *TimeRequest) GetNsec() int64 { - if m != nil { - return m.Nsec +func (x *TimeRequest) GetNsec() int64 { + if x != nil { + return x.Nsec } return 0 } -func (m *TimeRequest) GetClkIdsMask() uint64 { - if m != nil { - return m.ClkIdsMask +func (x *TimeRequest) GetClkIdsMask() uint64 { + if x != nil { + return x.ClkIdsMask } return 0 } +func (x *TimeRequest) GetUid() string { + if x != nil { + return x.Uid + } + return "" +} + +func (x *TimeRequest) GetPodContainerName() string { + if x != nil { + return x.PodContainerName + } + return "" +} + type ContainerAction struct { - Action ContainerAction_Action `protobuf:"varint,1,opt,name=action,proto3,enum=pb.ContainerAction_Action" json:"action,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Action ContainerAction_Action `protobuf:"varint,1,opt,name=action,proto3,enum=pb.ContainerAction_Action" json:"action,omitempty"` +} + +func (x *ContainerAction) Reset() { + *x = ContainerAction{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContainerAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContainerAction) ProtoMessage() {} + +func (x *ContainerAction) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -func (m *ContainerAction) Reset() { *m = ContainerAction{} } -func (m *ContainerAction) String() string { return proto.CompactTextString(m) } -func (*ContainerAction) ProtoMessage() {} +// Deprecated: Use ContainerAction.ProtoReflect.Descriptor instead. func (*ContainerAction) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{18} + return file_chaosdaemon_proto_rawDescGZIP(), []int{19} +} + +func (x *ContainerAction) GetAction() ContainerAction_Action { + if x != nil { + return x.Action + } + return ContainerAction_KILL +} + +type ExecStressRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Scope ExecStressRequest_Scope `protobuf:"varint,1,opt,name=scope,proto3,enum=pb.ExecStressRequest_Scope" json:"scope,omitempty"` + Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"` + CpuStressors string `protobuf:"bytes,3,opt,name=cpuStressors,proto3" json:"cpuStressors,omitempty"` + EnterNS bool `protobuf:"varint,4,opt,name=enterNS,proto3" json:"enterNS,omitempty"` + MemoryStressors string `protobuf:"bytes,5,opt,name=memoryStressors,proto3" json:"memoryStressors,omitempty"` + OomScoreAdj int32 `protobuf:"varint,7,opt,name=oomScoreAdj,proto3" json:"oomScoreAdj,omitempty"` +} + +func (x *ExecStressRequest) Reset() { + *x = ExecStressRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExecStressRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ContainerAction) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ContainerAction.Unmarshal(m, b) + +func (*ExecStressRequest) ProtoMessage() {} + +func (x *ExecStressRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecStressRequest.ProtoReflect.Descriptor instead. +func (*ExecStressRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{20} +} + +func (x *ExecStressRequest) GetScope() ExecStressRequest_Scope { + if x != nil { + return x.Scope + } + return ExecStressRequest_CONTAINER +} + +func (x *ExecStressRequest) GetTarget() string { + if x != nil { + return x.Target + } + return "" +} + +func (x *ExecStressRequest) GetCpuStressors() string { + if x != nil { + return x.CpuStressors + } + return "" +} + +func (x *ExecStressRequest) GetEnterNS() bool { + if x != nil { + return x.EnterNS + } + return false +} + +func (x *ExecStressRequest) GetMemoryStressors() string { + if x != nil { + return x.MemoryStressors + } + return "" +} + +func (x *ExecStressRequest) GetOomScoreAdj() int32 { + if x != nil { + return x.OomScoreAdj + } + return 0 +} + +type ExecStressResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CpuInstance string `protobuf:"bytes,1,opt,name=cpuInstance,proto3" json:"cpuInstance,omitempty"` + CpuStartTime int64 `protobuf:"varint,2,opt,name=cpuStartTime,proto3" json:"cpuStartTime,omitempty"` + MemoryInstance string `protobuf:"bytes,3,opt,name=memoryInstance,proto3" json:"memoryInstance,omitempty"` + MemoryStartTime int64 `protobuf:"varint,4,opt,name=memoryStartTime,proto3" json:"memoryStartTime,omitempty"` + CpuInstanceUid string `protobuf:"bytes,5,opt,name=cpuInstanceUid,proto3" json:"cpuInstanceUid,omitempty"` + MemoryInstanceUid string `protobuf:"bytes,6,opt,name=memoryInstanceUid,proto3" json:"memoryInstanceUid,omitempty"` +} + +func (x *ExecStressResponse) Reset() { + *x = ExecStressResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExecStressResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecStressResponse) ProtoMessage() {} + +func (x *ExecStressResponse) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -func (m *ContainerAction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ContainerAction.Marshal(b, m, deterministic) + +// Deprecated: Use ExecStressResponse.ProtoReflect.Descriptor instead. +func (*ExecStressResponse) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{21} } -func (dst *ContainerAction) XXX_Merge(src proto.Message) { - xxx_messageInfo_ContainerAction.Merge(dst, src) + +func (x *ExecStressResponse) GetCpuInstance() string { + if x != nil { + return x.CpuInstance + } + return "" } -func (m *ContainerAction) XXX_Size() int { - return xxx_messageInfo_ContainerAction.Size(m) + +func (x *ExecStressResponse) GetCpuStartTime() int64 { + if x != nil { + return x.CpuStartTime + } + return 0 } -func (m *ContainerAction) XXX_DiscardUnknown() { - xxx_messageInfo_ContainerAction.DiscardUnknown(m) + +func (x *ExecStressResponse) GetMemoryInstance() string { + if x != nil { + return x.MemoryInstance + } + return "" } -var xxx_messageInfo_ContainerAction proto.InternalMessageInfo +func (x *ExecStressResponse) GetMemoryStartTime() int64 { + if x != nil { + return x.MemoryStartTime + } + return 0 +} + +func (x *ExecStressResponse) GetCpuInstanceUid() string { + if x != nil { + return x.CpuInstanceUid + } + return "" +} + +func (x *ExecStressResponse) GetMemoryInstanceUid() string { + if x != nil { + return x.MemoryInstanceUid + } + return "" +} + +type CancelStressRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CpuInstance string `protobuf:"bytes,1,opt,name=cpuInstance,proto3" json:"cpuInstance,omitempty"` + CpuStartTime int64 `protobuf:"varint,2,opt,name=cpuStartTime,proto3" json:"cpuStartTime,omitempty"` + MemoryInstance string `protobuf:"bytes,3,opt,name=memoryInstance,proto3" json:"memoryInstance,omitempty"` + MemoryStartTime int64 `protobuf:"varint,4,opt,name=memoryStartTime,proto3" json:"memoryStartTime,omitempty"` + CpuInstanceUid string `protobuf:"bytes,5,opt,name=cpuInstanceUid,proto3" json:"cpuInstanceUid,omitempty"` + MemoryInstanceUid string `protobuf:"bytes,6,opt,name=memoryInstanceUid,proto3" json:"memoryInstanceUid,omitempty"` +} + +func (x *CancelStressRequest) Reset() { + *x = CancelStressRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CancelStressRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CancelStressRequest) ProtoMessage() {} + +func (x *CancelStressRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CancelStressRequest.ProtoReflect.Descriptor instead. +func (*CancelStressRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{22} +} + +func (x *CancelStressRequest) GetCpuInstance() string { + if x != nil { + return x.CpuInstance + } + return "" +} + +func (x *CancelStressRequest) GetCpuStartTime() int64 { + if x != nil { + return x.CpuStartTime + } + return 0 +} + +func (x *CancelStressRequest) GetMemoryInstance() string { + if x != nil { + return x.MemoryInstance + } + return "" +} + +func (x *CancelStressRequest) GetMemoryStartTime() int64 { + if x != nil { + return x.MemoryStartTime + } + return 0 +} + +func (x *CancelStressRequest) GetCpuInstanceUid() string { + if x != nil { + return x.CpuInstanceUid + } + return "" +} + +func (x *CancelStressRequest) GetMemoryInstanceUid() string { + if x != nil { + return x.MemoryInstanceUid + } + return "" +} + +type ApplyIOChaosRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Actions string `protobuf:"bytes,1,opt,name=actions,proto3" json:"actions,omitempty"` + Volume string `protobuf:"bytes,2,opt,name=volume,proto3" json:"volume,omitempty"` + ContainerId string `protobuf:"bytes,3,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + Instance int64 `protobuf:"varint,4,opt,name=instance,proto3" json:"instance,omitempty"` + StartTime int64 `protobuf:"varint,5,opt,name=startTime,proto3" json:"startTime,omitempty"` + EnterNS bool `protobuf:"varint,6,opt,name=enterNS,proto3" json:"enterNS,omitempty"` + InstanceUid string `protobuf:"bytes,7,opt,name=instance_uid,json=instanceUid,proto3" json:"instance_uid,omitempty"` +} + +func (x *ApplyIOChaosRequest) Reset() { + *x = ApplyIOChaosRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplyIOChaosRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyIOChaosRequest) ProtoMessage() {} + +func (x *ApplyIOChaosRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplyIOChaosRequest.ProtoReflect.Descriptor instead. +func (*ApplyIOChaosRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{23} +} + +func (x *ApplyIOChaosRequest) GetActions() string { + if x != nil { + return x.Actions + } + return "" +} + +func (x *ApplyIOChaosRequest) GetVolume() string { + if x != nil { + return x.Volume + } + return "" +} + +func (x *ApplyIOChaosRequest) GetContainerId() string { + if x != nil { + return x.ContainerId + } + return "" +} + +func (x *ApplyIOChaosRequest) GetInstance() int64 { + if x != nil { + return x.Instance + } + return 0 +} + +func (x *ApplyIOChaosRequest) GetStartTime() int64 { + if x != nil { + return x.StartTime + } + return 0 +} + +func (x *ApplyIOChaosRequest) GetEnterNS() bool { + if x != nil { + return x.EnterNS + } + return false +} + +func (x *ApplyIOChaosRequest) GetInstanceUid() string { + if x != nil { + return x.InstanceUid + } + return "" +} + +type ApplyIOChaosResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Instance int64 `protobuf:"varint,1,opt,name=instance,proto3" json:"instance,omitempty"` + StartTime int64 `protobuf:"varint,2,opt,name=startTime,proto3" json:"startTime,omitempty"` + InstanceUid string `protobuf:"bytes,3,opt,name=instance_uid,json=instanceUid,proto3" json:"instance_uid,omitempty"` +} + +func (x *ApplyIOChaosResponse) Reset() { + *x = ApplyIOChaosResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplyIOChaosResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyIOChaosResponse) ProtoMessage() {} + +func (x *ApplyIOChaosResponse) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplyIOChaosResponse.ProtoReflect.Descriptor instead. +func (*ApplyIOChaosResponse) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{24} +} + +func (x *ApplyIOChaosResponse) GetInstance() int64 { + if x != nil { + return x.Instance + } + return 0 +} + +func (x *ApplyIOChaosResponse) GetStartTime() int64 { + if x != nil { + return x.StartTime + } + return 0 +} + +func (x *ApplyIOChaosResponse) GetInstanceUid() string { + if x != nil { + return x.InstanceUid + } + return "" +} + +type ApplyHttpChaosRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Rules string `protobuf:"bytes,1,opt,name=rules,proto3" json:"rules,omitempty"` + ProxyPorts []uint32 `protobuf:"varint,2,rep,packed,name=proxy_ports,json=proxyPorts,proto3" json:"proxy_ports,omitempty"` + ContainerId string `protobuf:"bytes,3,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + Instance int64 `protobuf:"varint,4,opt,name=instance,proto3" json:"instance,omitempty"` + StartTime int64 `protobuf:"varint,5,opt,name=startTime,proto3" json:"startTime,omitempty"` + EnterNS bool `protobuf:"varint,6,opt,name=enterNS,proto3" json:"enterNS,omitempty"` + InstanceUid string `protobuf:"bytes,7,opt,name=instance_uid,json=instanceUid,proto3" json:"instance_uid,omitempty"` + Tls string `protobuf:"bytes,8,opt,name=tls,proto3" json:"tls,omitempty"` +} + +func (x *ApplyHttpChaosRequest) Reset() { + *x = ApplyHttpChaosRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplyHttpChaosRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyHttpChaosRequest) ProtoMessage() {} + +func (x *ApplyHttpChaosRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplyHttpChaosRequest.ProtoReflect.Descriptor instead. +func (*ApplyHttpChaosRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{25} +} + +func (x *ApplyHttpChaosRequest) GetRules() string { + if x != nil { + return x.Rules + } + return "" +} + +func (x *ApplyHttpChaosRequest) GetProxyPorts() []uint32 { + if x != nil { + return x.ProxyPorts + } + return nil +} + +func (x *ApplyHttpChaosRequest) GetContainerId() string { + if x != nil { + return x.ContainerId + } + return "" +} + +func (x *ApplyHttpChaosRequest) GetInstance() int64 { + if x != nil { + return x.Instance + } + return 0 +} + +func (x *ApplyHttpChaosRequest) GetStartTime() int64 { + if x != nil { + return x.StartTime + } + return 0 +} + +func (x *ApplyHttpChaosRequest) GetEnterNS() bool { + if x != nil { + return x.EnterNS + } + return false +} + +func (x *ApplyHttpChaosRequest) GetInstanceUid() string { + if x != nil { + return x.InstanceUid + } + return "" +} + +func (x *ApplyHttpChaosRequest) GetTls() string { + if x != nil { + return x.Tls + } + return "" +} + +type ApplyHttpChaosResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Instance int64 `protobuf:"varint,1,opt,name=instance,proto3" json:"instance,omitempty"` + StartTime int64 `protobuf:"varint,2,opt,name=startTime,proto3" json:"startTime,omitempty"` + StatusCode int32 `protobuf:"varint,3,opt,name=statusCode,proto3" json:"statusCode,omitempty"` + Error string `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"` + InstanceUid string `protobuf:"bytes,5,opt,name=instance_uid,json=instanceUid,proto3" json:"instance_uid,omitempty"` +} + +func (x *ApplyHttpChaosResponse) Reset() { + *x = ApplyHttpChaosResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplyHttpChaosResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyHttpChaosResponse) ProtoMessage() {} + +func (x *ApplyHttpChaosResponse) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplyHttpChaosResponse.ProtoReflect.Descriptor instead. +func (*ApplyHttpChaosResponse) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{26} +} + +func (x *ApplyHttpChaosResponse) GetInstance() int64 { + if x != nil { + return x.Instance + } + return 0 +} + +func (x *ApplyHttpChaosResponse) GetStartTime() int64 { + if x != nil { + return x.StartTime + } + return 0 +} + +func (x *ApplyHttpChaosResponse) GetStatusCode() int32 { + if x != nil { + return x.StatusCode + } + return 0 +} + +func (x *ApplyHttpChaosResponse) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +func (x *ApplyHttpChaosResponse) GetInstanceUid() string { + if x != nil { + return x.InstanceUid + } + return "" +} + +type TcsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Tcs []*Tc `protobuf:"bytes,1,rep,name=tcs,proto3" json:"tcs,omitempty"` + ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + EnterNS bool `protobuf:"varint,4,opt,name=enterNS,proto3" json:"enterNS,omitempty"` +} + +func (x *TcsRequest) Reset() { + *x = TcsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TcsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TcsRequest) ProtoMessage() {} + +func (x *TcsRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TcsRequest.ProtoReflect.Descriptor instead. +func (*TcsRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{27} +} + +func (x *TcsRequest) GetTcs() []*Tc { + if x != nil { + return x.Tcs + } + return nil +} + +func (x *TcsRequest) GetContainerId() string { + if x != nil { + return x.ContainerId + } + return "" +} + +func (x *TcsRequest) GetEnterNS() bool { + if x != nil { + return x.EnterNS + } + return false +} + +type Tc struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type Tc_Type `protobuf:"varint,1,opt,name=type,proto3,enum=pb.Tc_Type" json:"type,omitempty"` + Netem *Netem `protobuf:"bytes,2,opt,name=netem,proto3" json:"netem,omitempty"` + Tbf *Tbf `protobuf:"bytes,3,opt,name=tbf,proto3" json:"tbf,omitempty"` + Ipset string `protobuf:"bytes,4,opt,name=ipset,proto3" json:"ipset,omitempty"` + Protocol string `protobuf:"bytes,5,opt,name=protocol,proto3" json:"protocol,omitempty"` + SourcePort string `protobuf:"bytes,6,opt,name=source_port,json=sourcePort,proto3" json:"source_port,omitempty"` + EgressPort string `protobuf:"bytes,7,opt,name=egress_port,json=egressPort,proto3" json:"egress_port,omitempty"` + Device string `protobuf:"bytes,9,opt,name=device,proto3" json:"device,omitempty"` +} + +func (x *Tc) Reset() { + *x = Tc{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Tc) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Tc) ProtoMessage() {} + +func (x *Tc) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Tc.ProtoReflect.Descriptor instead. +func (*Tc) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{28} +} + +func (x *Tc) GetType() Tc_Type { + if x != nil { + return x.Type + } + return Tc_NETEM +} + +func (x *Tc) GetNetem() *Netem { + if x != nil { + return x.Netem + } + return nil +} + +func (x *Tc) GetTbf() *Tbf { + if x != nil { + return x.Tbf + } + return nil +} + +func (x *Tc) GetIpset() string { + if x != nil { + return x.Ipset + } + return "" +} + +func (x *Tc) GetProtocol() string { + if x != nil { + return x.Protocol + } + return "" +} + +func (x *Tc) GetSourcePort() string { + if x != nil { + return x.SourcePort + } + return "" +} + +func (x *Tc) GetEgressPort() string { + if x != nil { + return x.EgressPort + } + return "" +} + +func (x *Tc) GetDevice() string { + if x != nil { + return x.Device + } + return "" +} + +type SetDNSServerRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ContainerId string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + DnsServer string `protobuf:"bytes,2,opt,name=dns_server,json=dnsServer,proto3" json:"dns_server,omitempty"` + Enable bool `protobuf:"varint,3,opt,name=enable,proto3" json:"enable,omitempty"` + EnterNS bool `protobuf:"varint,4,opt,name=enterNS,proto3" json:"enterNS,omitempty"` +} -func (m *ContainerAction) GetAction() ContainerAction_Action { - if m != nil { - return m.Action +func (x *SetDNSServerRequest) Reset() { + *x = SetDNSServerRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } - return ContainerAction_KILL } -type ExecStressRequest struct { - Scope ExecStressRequest_Scope `protobuf:"varint,1,opt,name=scope,proto3,enum=pb.ExecStressRequest_Scope" json:"scope,omitempty"` - Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"` - Stressors string `protobuf:"bytes,3,opt,name=stressors,proto3" json:"stressors,omitempty"` - EnterNS bool `protobuf:"varint,4,opt,name=enterNS,proto3" json:"enterNS,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ExecStressRequest) Reset() { *m = ExecStressRequest{} } -func (m *ExecStressRequest) String() string { return proto.CompactTextString(m) } -func (*ExecStressRequest) ProtoMessage() {} -func (*ExecStressRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{19} -} -func (m *ExecStressRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ExecStressRequest.Unmarshal(m, b) -} -func (m *ExecStressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ExecStressRequest.Marshal(b, m, deterministic) -} -func (dst *ExecStressRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ExecStressRequest.Merge(dst, src) -} -func (m *ExecStressRequest) XXX_Size() int { - return xxx_messageInfo_ExecStressRequest.Size(m) -} -func (m *ExecStressRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ExecStressRequest.DiscardUnknown(m) +func (x *SetDNSServerRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -var xxx_messageInfo_ExecStressRequest proto.InternalMessageInfo +func (*SetDNSServerRequest) ProtoMessage() {} -func (m *ExecStressRequest) GetScope() ExecStressRequest_Scope { - if m != nil { - return m.Scope +func (x *SetDNSServerRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return ExecStressRequest_CONTAINER + return mi.MessageOf(x) +} + +// Deprecated: Use SetDNSServerRequest.ProtoReflect.Descriptor instead. +func (*SetDNSServerRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{29} } -func (m *ExecStressRequest) GetTarget() string { - if m != nil { - return m.Target +func (x *SetDNSServerRequest) GetContainerId() string { + if x != nil { + return x.ContainerId } return "" } -func (m *ExecStressRequest) GetStressors() string { - if m != nil { - return m.Stressors +func (x *SetDNSServerRequest) GetDnsServer() string { + if x != nil { + return x.DnsServer } return "" } -func (m *ExecStressRequest) GetEnterNS() bool { - if m != nil { - return m.EnterNS +func (x *SetDNSServerRequest) GetEnable() bool { + if x != nil { + return x.Enable } return false } -type ExecStressResponse struct { - Instance string `protobuf:"bytes,1,opt,name=instance,proto3" json:"instance,omitempty"` - StartTime int64 `protobuf:"varint,2,opt,name=startTime,proto3" json:"startTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +func (x *SetDNSServerRequest) GetEnterNS() bool { + if x != nil { + return x.EnterNS + } + return false } -func (m *ExecStressResponse) Reset() { *m = ExecStressResponse{} } -func (m *ExecStressResponse) String() string { return proto.CompactTextString(m) } -func (*ExecStressResponse) ProtoMessage() {} -func (*ExecStressResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{20} -} -func (m *ExecStressResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ExecStressResponse.Unmarshal(m, b) +type InstallJVMRulesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ContainerId string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + Rule string `protobuf:"bytes,2,opt,name=rule,proto3" json:"rule,omitempty"` + Port int32 `protobuf:"varint,3,opt,name=port,proto3" json:"port,omitempty"` + EnterNS bool `protobuf:"varint,4,opt,name=enterNS,proto3" json:"enterNS,omitempty"` } -func (m *ExecStressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ExecStressResponse.Marshal(b, m, deterministic) + +func (x *InstallJVMRulesRequest) Reset() { + *x = InstallJVMRulesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (dst *ExecStressResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ExecStressResponse.Merge(dst, src) + +func (x *InstallJVMRulesRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ExecStressResponse) XXX_Size() int { - return xxx_messageInfo_ExecStressResponse.Size(m) + +func (*InstallJVMRulesRequest) ProtoMessage() {} + +func (x *InstallJVMRulesRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -func (m *ExecStressResponse) XXX_DiscardUnknown() { - xxx_messageInfo_ExecStressResponse.DiscardUnknown(m) + +// Deprecated: Use InstallJVMRulesRequest.ProtoReflect.Descriptor instead. +func (*InstallJVMRulesRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{30} } -var xxx_messageInfo_ExecStressResponse proto.InternalMessageInfo +func (x *InstallJVMRulesRequest) GetContainerId() string { + if x != nil { + return x.ContainerId + } + return "" +} -func (m *ExecStressResponse) GetInstance() string { - if m != nil { - return m.Instance +func (x *InstallJVMRulesRequest) GetRule() string { + if x != nil { + return x.Rule } return "" } -func (m *ExecStressResponse) GetStartTime() int64 { - if m != nil { - return m.StartTime +func (x *InstallJVMRulesRequest) GetPort() int32 { + if x != nil { + return x.Port } return 0 } -type CancelStressRequest struct { - Instance string `protobuf:"bytes,1,opt,name=instance,proto3" json:"instance,omitempty"` - StartTime int64 `protobuf:"varint,2,opt,name=startTime,proto3" json:"startTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +func (x *InstallJVMRulesRequest) GetEnterNS() bool { + if x != nil { + return x.EnterNS + } + return false } -func (m *CancelStressRequest) Reset() { *m = CancelStressRequest{} } -func (m *CancelStressRequest) String() string { return proto.CompactTextString(m) } -func (*CancelStressRequest) ProtoMessage() {} -func (*CancelStressRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{21} -} -func (m *CancelStressRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_CancelStressRequest.Unmarshal(m, b) +type UninstallJVMRulesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ContainerId string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + Rule string `protobuf:"bytes,2,opt,name=rule,proto3" json:"rule,omitempty"` + Port int32 `protobuf:"varint,3,opt,name=port,proto3" json:"port,omitempty"` + EnterNS bool `protobuf:"varint,4,opt,name=enterNS,proto3" json:"enterNS,omitempty"` } -func (m *CancelStressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_CancelStressRequest.Marshal(b, m, deterministic) + +func (x *UninstallJVMRulesRequest) Reset() { + *x = UninstallJVMRulesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (dst *CancelStressRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_CancelStressRequest.Merge(dst, src) + +func (x *UninstallJVMRulesRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *CancelStressRequest) XXX_Size() int { - return xxx_messageInfo_CancelStressRequest.Size(m) + +func (*UninstallJVMRulesRequest) ProtoMessage() {} + +func (x *UninstallJVMRulesRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -func (m *CancelStressRequest) XXX_DiscardUnknown() { - xxx_messageInfo_CancelStressRequest.DiscardUnknown(m) + +// Deprecated: Use UninstallJVMRulesRequest.ProtoReflect.Descriptor instead. +func (*UninstallJVMRulesRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{31} } -var xxx_messageInfo_CancelStressRequest proto.InternalMessageInfo +func (x *UninstallJVMRulesRequest) GetContainerId() string { + if x != nil { + return x.ContainerId + } + return "" +} -func (m *CancelStressRequest) GetInstance() string { - if m != nil { - return m.Instance +func (x *UninstallJVMRulesRequest) GetRule() string { + if x != nil { + return x.Rule } return "" } -func (m *CancelStressRequest) GetStartTime() int64 { - if m != nil { - return m.StartTime +func (x *UninstallJVMRulesRequest) GetPort() int32 { + if x != nil { + return x.Port } return 0 } -type ApplyIoChaosRequest struct { - Actions string `protobuf:"bytes,1,opt,name=actions,proto3" json:"actions,omitempty"` - Volume string `protobuf:"bytes,2,opt,name=volume,proto3" json:"volume,omitempty"` - ContainerId string `protobuf:"bytes,3,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - Instance int64 `protobuf:"varint,4,opt,name=instance,proto3" json:"instance,omitempty"` - StartTime int64 `protobuf:"varint,5,opt,name=startTime,proto3" json:"startTime,omitempty"` - EnterNS bool `protobuf:"varint,6,opt,name=enterNS,proto3" json:"enterNS,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +func (x *UninstallJVMRulesRequest) GetEnterNS() bool { + if x != nil { + return x.EnterNS + } + return false } -func (m *ApplyIoChaosRequest) Reset() { *m = ApplyIoChaosRequest{} } -func (m *ApplyIoChaosRequest) String() string { return proto.CompactTextString(m) } -func (*ApplyIoChaosRequest) ProtoMessage() {} -func (*ApplyIoChaosRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{22} -} -func (m *ApplyIoChaosRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ApplyIoChaosRequest.Unmarshal(m, b) -} -func (m *ApplyIoChaosRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ApplyIoChaosRequest.Marshal(b, m, deterministic) -} -func (dst *ApplyIoChaosRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ApplyIoChaosRequest.Merge(dst, src) +type ApplyBlockChaosRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ContainerId string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + VolumePath string `protobuf:"bytes,2,opt,name=volume_path,json=volumePath,proto3" json:"volume_path,omitempty"` + Action ApplyBlockChaosRequest_Action `protobuf:"varint,3,opt,name=action,proto3,enum=pb.ApplyBlockChaosRequest_Action" json:"action,omitempty"` + Delay *BlockDelaySpec `protobuf:"bytes,5,opt,name=delay,proto3" json:"delay,omitempty"` + EnterNS bool `protobuf:"varint,6,opt,name=enterNS,proto3" json:"enterNS,omitempty"` } -func (m *ApplyIoChaosRequest) XXX_Size() int { - return xxx_messageInfo_ApplyIoChaosRequest.Size(m) + +func (x *ApplyBlockChaosRequest) Reset() { + *x = ApplyBlockChaosRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ApplyIoChaosRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ApplyIoChaosRequest.DiscardUnknown(m) + +func (x *ApplyBlockChaosRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -var xxx_messageInfo_ApplyIoChaosRequest proto.InternalMessageInfo +func (*ApplyBlockChaosRequest) ProtoMessage() {} -func (m *ApplyIoChaosRequest) GetActions() string { - if m != nil { - return m.Actions +func (x *ApplyBlockChaosRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return "" + return mi.MessageOf(x) +} + +// Deprecated: Use ApplyBlockChaosRequest.ProtoReflect.Descriptor instead. +func (*ApplyBlockChaosRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{32} } -func (m *ApplyIoChaosRequest) GetVolume() string { - if m != nil { - return m.Volume +func (x *ApplyBlockChaosRequest) GetContainerId() string { + if x != nil { + return x.ContainerId } return "" } -func (m *ApplyIoChaosRequest) GetContainerId() string { - if m != nil { - return m.ContainerId +func (x *ApplyBlockChaosRequest) GetVolumePath() string { + if x != nil { + return x.VolumePath } return "" } -func (m *ApplyIoChaosRequest) GetInstance() int64 { - if m != nil { - return m.Instance +func (x *ApplyBlockChaosRequest) GetAction() ApplyBlockChaosRequest_Action { + if x != nil { + return x.Action } - return 0 + return ApplyBlockChaosRequest_Delay } -func (m *ApplyIoChaosRequest) GetStartTime() int64 { - if m != nil { - return m.StartTime +func (x *ApplyBlockChaosRequest) GetDelay() *BlockDelaySpec { + if x != nil { + return x.Delay } - return 0 + return nil } -func (m *ApplyIoChaosRequest) GetEnterNS() bool { - if m != nil { - return m.EnterNS +func (x *ApplyBlockChaosRequest) GetEnterNS() bool { + if x != nil { + return x.EnterNS } return false } -type ApplyIoChaosResponse struct { - Instance int64 `protobuf:"varint,1,opt,name=instance,proto3" json:"instance,omitempty"` - StartTime int64 `protobuf:"varint,2,opt,name=startTime,proto3" json:"startTime,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} +type BlockDelaySpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *ApplyIoChaosResponse) Reset() { *m = ApplyIoChaosResponse{} } -func (m *ApplyIoChaosResponse) String() string { return proto.CompactTextString(m) } -func (*ApplyIoChaosResponse) ProtoMessage() {} -func (*ApplyIoChaosResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{23} -} -func (m *ApplyIoChaosResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ApplyIoChaosResponse.Unmarshal(m, b) + Delay int64 `protobuf:"varint,1,opt,name=delay,proto3" json:"delay,omitempty"` + Correlation float64 `protobuf:"fixed64,2,opt,name=correlation,proto3" json:"correlation,omitempty"` + Jitter int64 `protobuf:"varint,3,opt,name=jitter,proto3" json:"jitter,omitempty"` } -func (m *ApplyIoChaosResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ApplyIoChaosResponse.Marshal(b, m, deterministic) -} -func (dst *ApplyIoChaosResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ApplyIoChaosResponse.Merge(dst, src) + +func (x *BlockDelaySpec) Reset() { + *x = BlockDelaySpec{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ApplyIoChaosResponse) XXX_Size() int { - return xxx_messageInfo_ApplyIoChaosResponse.Size(m) + +func (x *BlockDelaySpec) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ApplyIoChaosResponse) XXX_DiscardUnknown() { - xxx_messageInfo_ApplyIoChaosResponse.DiscardUnknown(m) + +func (*BlockDelaySpec) ProtoMessage() {} + +func (x *BlockDelaySpec) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ApplyIoChaosResponse proto.InternalMessageInfo +// Deprecated: Use BlockDelaySpec.ProtoReflect.Descriptor instead. +func (*BlockDelaySpec) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{33} +} -func (m *ApplyIoChaosResponse) GetInstance() int64 { - if m != nil { - return m.Instance +func (x *BlockDelaySpec) GetDelay() int64 { + if x != nil { + return x.Delay } return 0 } -func (m *ApplyIoChaosResponse) GetStartTime() int64 { - if m != nil { - return m.StartTime +func (x *BlockDelaySpec) GetCorrelation() float64 { + if x != nil { + return x.Correlation } return 0 } -type TcsRequest struct { - Tcs []*Tc `protobuf:"bytes,1,rep,name=tcs,proto3" json:"tcs,omitempty"` - ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - Device string `protobuf:"bytes,3,opt,name=device,proto3" json:"device,omitempty"` - EnterNS bool `protobuf:"varint,4,opt,name=enterNS,proto3" json:"enterNS,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *TcsRequest) Reset() { *m = TcsRequest{} } -func (m *TcsRequest) String() string { return proto.CompactTextString(m) } -func (*TcsRequest) ProtoMessage() {} -func (*TcsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{24} -} -func (m *TcsRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_TcsRequest.Unmarshal(m, b) -} -func (m *TcsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_TcsRequest.Marshal(b, m, deterministic) +func (x *BlockDelaySpec) GetJitter() int64 { + if x != nil { + return x.Jitter + } + return 0 } -func (dst *TcsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_TcsRequest.Merge(dst, src) + +type BlockLimitSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Quota uint64 `protobuf:"varint,1,opt,name=quota,proto3" json:"quota,omitempty"` + PeriodUs uint64 `protobuf:"varint,2,opt,name=period_us,json=periodUs,proto3" json:"period_us,omitempty"` } -func (m *TcsRequest) XXX_Size() int { - return xxx_messageInfo_TcsRequest.Size(m) + +func (x *BlockLimitSpec) Reset() { + *x = BlockLimitSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *TcsRequest) XXX_DiscardUnknown() { - xxx_messageInfo_TcsRequest.DiscardUnknown(m) + +func (x *BlockLimitSpec) String() string { + return protoimpl.X.MessageStringOf(x) } -var xxx_messageInfo_TcsRequest proto.InternalMessageInfo +func (*BlockLimitSpec) ProtoMessage() {} -func (m *TcsRequest) GetTcs() []*Tc { - if m != nil { - return m.Tcs +func (x *BlockLimitSpec) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return nil + return mi.MessageOf(x) } -func (m *TcsRequest) GetContainerId() string { - if m != nil { - return m.ContainerId - } - return "" +// Deprecated: Use BlockLimitSpec.ProtoReflect.Descriptor instead. +func (*BlockLimitSpec) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{34} } -func (m *TcsRequest) GetDevice() string { - if m != nil { - return m.Device +func (x *BlockLimitSpec) GetQuota() uint64 { + if x != nil { + return x.Quota } - return "" + return 0 } -func (m *TcsRequest) GetEnterNS() bool { - if m != nil { - return m.EnterNS +func (x *BlockLimitSpec) GetPeriodUs() uint64 { + if x != nil { + return x.PeriodUs } - return false + return 0 } -type Tc struct { - Type Tc_Type `protobuf:"varint,1,opt,name=type,proto3,enum=pb.Tc_Type" json:"type,omitempty"` - Netem *Netem `protobuf:"bytes,2,opt,name=netem,proto3" json:"netem,omitempty"` - Tbf *Tbf `protobuf:"bytes,3,opt,name=tbf,proto3" json:"tbf,omitempty"` - Ipset string `protobuf:"bytes,4,opt,name=ipset,proto3" json:"ipset,omitempty"` - Protocol string `protobuf:"bytes,5,opt,name=protocol,proto3" json:"protocol,omitempty"` - SourcePort string `protobuf:"bytes,6,opt,name=source_port,json=sourcePort,proto3" json:"source_port,omitempty"` - EgressPort string `protobuf:"bytes,7,opt,name=egress_port,json=egressPort,proto3" json:"egress_port,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Tc) Reset() { *m = Tc{} } -func (m *Tc) String() string { return proto.CompactTextString(m) } -func (*Tc) ProtoMessage() {} -func (*Tc) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{25} -} -func (m *Tc) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Tc.Unmarshal(m, b) -} -func (m *Tc) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Tc.Marshal(b, m, deterministic) -} -func (dst *Tc) XXX_Merge(src proto.Message) { - xxx_messageInfo_Tc.Merge(dst, src) -} -func (m *Tc) XXX_Size() int { - return xxx_messageInfo_Tc.Size(m) -} -func (m *Tc) XXX_DiscardUnknown() { - xxx_messageInfo_Tc.DiscardUnknown(m) -} +type ApplyBlockChaosResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -var xxx_messageInfo_Tc proto.InternalMessageInfo + InjectionId int32 `protobuf:"varint,1,opt,name=injection_id,json=injectionId,proto3" json:"injection_id,omitempty"` +} -func (m *Tc) GetType() Tc_Type { - if m != nil { - return m.Type +func (x *ApplyBlockChaosResponse) Reset() { + *x = ApplyBlockChaosResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } - return Tc_NETEM } -func (m *Tc) GetNetem() *Netem { - if m != nil { - return m.Netem - } - return nil +func (x *ApplyBlockChaosResponse) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Tc) GetTbf() *Tbf { - if m != nil { - return m.Tbf +func (*ApplyBlockChaosResponse) ProtoMessage() {} + +func (x *ApplyBlockChaosResponse) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return nil + return mi.MessageOf(x) } -func (m *Tc) GetIpset() string { - if m != nil { - return m.Ipset - } - return "" +// Deprecated: Use ApplyBlockChaosResponse.ProtoReflect.Descriptor instead. +func (*ApplyBlockChaosResponse) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{35} } -func (m *Tc) GetProtocol() string { - if m != nil { - return m.Protocol +func (x *ApplyBlockChaosResponse) GetInjectionId() int32 { + if x != nil { + return x.InjectionId } - return "" + return 0 } -func (m *Tc) GetSourcePort() string { - if m != nil { - return m.SourcePort - } - return "" +type RecoverBlockChaosRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + InjectionId int32 `protobuf:"varint,1,opt,name=injection_id,json=injectionId,proto3" json:"injection_id,omitempty"` } -func (m *Tc) GetEgressPort() string { - if m != nil { - return m.EgressPort +func (x *RecoverBlockChaosRequest) Reset() { + *x = RecoverBlockChaosRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chaosdaemon_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } - return "" } -type SetDNSServerRequest struct { - ContainerId string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - DnsServer string `protobuf:"bytes,2,opt,name=dns_server,json=dnsServer,proto3" json:"dns_server,omitempty"` - Enable bool `protobuf:"varint,3,opt,name=enable,proto3" json:"enable,omitempty"` - EnterNS bool `protobuf:"varint,4,opt,name=enterNS,proto3" json:"enterNS,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SetDNSServerRequest) Reset() { *m = SetDNSServerRequest{} } -func (m *SetDNSServerRequest) String() string { return proto.CompactTextString(m) } -func (*SetDNSServerRequest) ProtoMessage() {} -func (*SetDNSServerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_chaosdaemon_8b0c6060d3b63305, []int{26} -} -func (m *SetDNSServerRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SetDNSServerRequest.Unmarshal(m, b) -} -func (m *SetDNSServerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SetDNSServerRequest.Marshal(b, m, deterministic) -} -func (dst *SetDNSServerRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_SetDNSServerRequest.Merge(dst, src) -} -func (m *SetDNSServerRequest) XXX_Size() int { - return xxx_messageInfo_SetDNSServerRequest.Size(m) -} -func (m *SetDNSServerRequest) XXX_DiscardUnknown() { - xxx_messageInfo_SetDNSServerRequest.DiscardUnknown(m) +func (x *RecoverBlockChaosRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -var xxx_messageInfo_SetDNSServerRequest proto.InternalMessageInfo +func (*RecoverBlockChaosRequest) ProtoMessage() {} -func (m *SetDNSServerRequest) GetContainerId() string { - if m != nil { - return m.ContainerId +func (x *RecoverBlockChaosRequest) ProtoReflect() protoreflect.Message { + mi := &file_chaosdaemon_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return "" + return mi.MessageOf(x) } -func (m *SetDNSServerRequest) GetDnsServer() string { - if m != nil { - return m.DnsServer - } - return "" +// Deprecated: Use RecoverBlockChaosRequest.ProtoReflect.Descriptor instead. +func (*RecoverBlockChaosRequest) Descriptor() ([]byte, []int) { + return file_chaosdaemon_proto_rawDescGZIP(), []int{36} } -func (m *SetDNSServerRequest) GetEnable() bool { - if m != nil { - return m.Enable +func (x *RecoverBlockChaosRequest) GetInjectionId() int32 { + if x != nil { + return x.InjectionId } - return false + return 0 } -func (m *SetDNSServerRequest) GetEnterNS() bool { - if m != nil { - return m.EnterNS - } - return false -} +var File_chaosdaemon_proto protoreflect.FileDescriptor + +var file_chaosdaemon_proto_rawDesc = []byte{ + 0x0a, 0x11, 0x63, 0x68, 0x61, 0x6f, 0x73, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x36, 0x0a, 0x08, 0x54, 0x63, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, + 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x05, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x22, 0x62, 0x0a, 0x10, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x2b, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x41, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, + 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, + 0x22, 0x25, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x9e, 0x01, 0x0a, 0x0c, 0x4e, 0x65, 0x74, 0x65, + 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x05, 0x6e, 0x65, 0x74, 0x65, + 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x65, 0x74, + 0x65, 0x6d, 0x52, 0x05, 0x6e, 0x65, 0x74, 0x65, 0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x06, + 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, + 0x62, 0x2e, 0x54, 0x63, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x06, 0x68, 0x61, 0x6e, 0x64, + 0x6c, 0x65, 0x12, 0x24, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x63, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, + 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x22, 0xca, 0x03, 0x0a, 0x05, 0x4e, 0x65, 0x74, + 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6a, 0x69, 0x74, 0x74, 0x65, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x1d, + 0x0a, 0x0a, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x63, 0x6f, 0x72, 0x72, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x02, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x72, 0x72, 0x12, 0x14, 0x0a, + 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x6f, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x02, 0x52, 0x04, 0x6c, 0x6f, 0x73, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x73, 0x73, 0x5f, + 0x63, 0x6f, 0x72, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x08, 0x6c, 0x6f, 0x73, 0x73, + 0x43, 0x6f, 0x72, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x03, 0x67, 0x61, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x64, 0x75, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x5f, 0x63, 0x6f, 0x72, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0d, 0x64, 0x75, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x72, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x72, + 0x65, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x02, 0x52, 0x07, 0x72, 0x65, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x5f, 0x63, 0x6f, 0x72, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0b, 0x72, 0x65, 0x6f, + 0x72, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x72, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x72, 0x72, + 0x75, 0x70, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x02, 0x52, 0x07, 0x63, 0x6f, 0x72, 0x72, 0x75, + 0x70, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x72, 0x72, 0x75, 0x70, 0x74, 0x5f, 0x63, 0x6f, + 0x72, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0b, 0x63, 0x6f, 0x72, 0x72, 0x75, 0x70, + 0x74, 0x43, 0x6f, 0x72, 0x72, 0x12, 0x24, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, + 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x63, 0x48, 0x61, 0x6e, + 0x64, 0x6c, 0x65, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x06, 0x68, + 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, + 0x2e, 0x54, 0x63, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x06, 0x68, 0x61, 0x6e, 0x64, 0x6c, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x61, 0x74, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x72, 0x61, 0x74, 0x65, 0x22, 0x4a, 0x0a, 0x0a, 0x54, 0x62, 0x66, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x03, 0x74, 0x62, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x07, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x62, 0x66, 0x52, 0x03, 0x74, 0x62, 0x66, 0x12, 0x21, + 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, + 0x64, 0x22, 0x81, 0x01, 0x0a, 0x03, 0x54, 0x62, 0x66, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x61, 0x74, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x06, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, + 0x65, 0x61, 0x6b, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, + 0x70, 0x65, 0x61, 0x6b, 0x52, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, + 0x62, 0x75, 0x72, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6d, 0x69, 0x6e, + 0x42, 0x75, 0x72, 0x73, 0x74, 0x22, 0x52, 0x0a, 0x0c, 0x51, 0x64, 0x69, 0x73, 0x63, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x05, 0x71, 0x64, 0x69, 0x73, 0x63, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x51, 0x64, 0x69, 0x73, 0x63, 0x52, + 0x05, 0x71, 0x64, 0x69, 0x73, 0x63, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x05, 0x51, 0x64, 0x69, + 0x73, 0x63, 0x12, 0x24, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x63, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, + 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x06, 0x68, 0x61, 0x6e, 0x64, + 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x63, + 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x06, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x22, 0x62, 0x0a, 0x13, 0x45, 0x6d, 0x61, 0x74, 0x63, 0x68, + 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, + 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, + 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, + 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x22, 0x72, 0x0a, 0x0c, 0x45, 0x6d, + 0x61, 0x74, 0x63, 0x68, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, + 0x12, 0x24, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x63, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x06, + 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x07, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x69, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x63, 0x48, + 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x07, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x69, 0x64, 0x22, 0x5a, + 0x0a, 0x0f, 0x54, 0x63, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x24, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x63, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, + 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x22, 0x30, 0x0a, 0x08, 0x54, 0x63, + 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x63, 0x48, 0x61, + 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x22, 0x6f, 0x0a, 0x0d, + 0x49, 0x50, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, + 0x06, 0x69, 0x70, 0x73, 0x65, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, + 0x70, 0x62, 0x2e, 0x49, 0x50, 0x53, 0x65, 0x74, 0x52, 0x06, 0x69, 0x70, 0x73, 0x65, 0x74, 0x73, + 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, 0x22, 0x99, 0x01, + 0x0a, 0x05, 0x49, 0x50, 0x53, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, + 0x69, 0x64, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x69, 0x64, 0x72, + 0x73, 0x12, 0x35, 0x0a, 0x0e, 0x63, 0x69, 0x64, 0x72, 0x5f, 0x61, 0x6e, 0x64, 0x5f, 0x70, 0x6f, + 0x72, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x43, + 0x69, 0x64, 0x72, 0x41, 0x6e, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x0c, 0x63, 0x69, 0x64, 0x72, + 0x41, 0x6e, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x74, + 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x35, 0x0a, 0x0b, 0x43, 0x69, 0x64, + 0x72, 0x41, 0x6e, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x12, 0x12, 0x0a, 0x04, + 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, + 0x22, 0x77, 0x0a, 0x15, 0x49, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x06, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, + 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, 0x22, 0xc3, 0x02, 0x0a, 0x05, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x70, 0x62, 0x2e, + 0x43, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x70, + 0x73, 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x69, 0x70, 0x73, 0x65, + 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x63, 0x70, 0x5f, 0x66, 0x6c, + 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x63, 0x70, 0x46, 0x6c, + 0x61, 0x67, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0x22, 0x0a, 0x09, 0x44, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x50, 0x55, + 0x54, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54, 0x10, 0x01, 0x22, + 0xb8, 0x01, 0x0a, 0x0b, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x65, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x03, 0x73, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x73, 0x65, 0x63, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x04, 0x6e, 0x73, 0x65, 0x63, 0x12, 0x20, 0x0a, 0x0c, 0x63, 0x6c, 0x6b, 0x5f, + 0x69, 0x64, 0x73, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, + 0x63, 0x6c, 0x6b, 0x49, 0x64, 0x73, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, + 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x2c, 0x0a, 0x12, + 0x70, 0x6f, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x6f, 0x64, 0x43, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x65, 0x0a, 0x0f, 0x43, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, + 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, + 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x1e, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4b, + 0x49, 0x4c, 0x4c, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x47, 0x45, 0x54, 0x50, 0x49, 0x44, 0x10, + 0x01, 0x22, 0x89, 0x02, 0x0a, 0x11, 0x45, 0x78, 0x65, 0x63, 0x53, 0x74, 0x72, 0x65, 0x73, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x65, 0x63, + 0x53, 0x74, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x53, 0x63, + 0x6f, 0x70, 0x65, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x70, 0x75, 0x53, 0x74, 0x72, 0x65, 0x73, 0x73, 0x6f, + 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x70, 0x75, 0x53, 0x74, 0x72, + 0x65, 0x73, 0x73, 0x6f, 0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, + 0x53, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, + 0x12, 0x28, 0x0a, 0x0f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x53, 0x74, 0x72, 0x65, 0x73, 0x73, + 0x6f, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, + 0x79, 0x53, 0x74, 0x72, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x6f, + 0x6d, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x41, 0x64, 0x6a, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x0b, 0x6f, 0x6f, 0x6d, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x41, 0x64, 0x6a, 0x22, 0x1f, 0x0a, 0x05, + 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x49, 0x4e, + 0x45, 0x52, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x4f, 0x44, 0x10, 0x01, 0x22, 0x82, 0x02, + 0x0a, 0x12, 0x45, 0x78, 0x65, 0x63, 0x53, 0x74, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x70, 0x75, 0x49, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x70, 0x75, 0x49, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x70, 0x75, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x70, + 0x75, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x6d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x53, 0x74, 0x61, 0x72, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x6d, 0x65, 0x6d, + 0x6f, 0x72, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, + 0x63, 0x70, 0x75, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x55, 0x69, 0x64, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x70, 0x75, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x55, 0x69, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x49, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x55, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x11, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x55, + 0x69, 0x64, 0x22, 0x83, 0x02, 0x0a, 0x13, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x74, 0x72, + 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x70, + 0x75, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x63, 0x70, 0x75, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x22, 0x0a, 0x0c, + 0x63, 0x70, 0x75, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0c, 0x63, 0x70, 0x75, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, + 0x12, 0x26, 0x0a, 0x0e, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x6d, 0x65, 0x6d, 0x6f, + 0x72, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x70, 0x75, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x55, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x70, 0x75, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x55, 0x69, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x6d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x55, 0x69, 0x64, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x49, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x55, 0x69, 0x64, 0x22, 0xe1, 0x01, 0x0a, 0x13, 0x41, 0x70, 0x70, + 0x6c, 0x79, 0x49, 0x4f, 0x43, 0x68, 0x61, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x6f, + 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x6f, 0x6c, 0x75, + 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x75, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x55, 0x69, 0x64, 0x22, 0x73, 0x0a, 0x14, + 0x41, 0x70, 0x70, 0x6c, 0x79, 0x49, 0x4f, 0x43, 0x68, 0x61, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, + 0x0a, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x75, 0x69, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x55, 0x69, + 0x64, 0x22, 0xfa, 0x01, 0x0a, 0x15, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x48, 0x74, 0x74, 0x70, 0x43, + 0x68, 0x61, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x72, + 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, + 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x6f, 0x72, + 0x74, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x75, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x55, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, + 0x74, 0x6c, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x6c, 0x73, 0x22, 0xab, + 0x01, 0x0a, 0x16, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x48, 0x74, 0x74, 0x70, 0x43, 0x68, 0x61, 0x6f, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, + 0x69, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x75, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x55, 0x69, 0x64, 0x22, 0x63, 0x0a, 0x0a, + 0x54, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x03, 0x74, 0x63, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x63, 0x52, + 0x03, 0x74, 0x63, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, + 0x4e, 0x53, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, + 0x53, 0x22, 0x8f, 0x02, 0x0a, 0x02, 0x54, 0x63, 0x12, 0x1f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0b, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x63, 0x2e, 0x54, + 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x05, 0x6e, 0x65, 0x74, + 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x65, + 0x74, 0x65, 0x6d, 0x52, 0x05, 0x6e, 0x65, 0x74, 0x65, 0x6d, 0x12, 0x19, 0x0a, 0x03, 0x74, 0x62, + 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x62, 0x66, + 0x52, 0x03, 0x74, 0x62, 0x66, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x70, 0x73, 0x65, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x70, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x67, 0x72, 0x65, + 0x73, 0x73, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, + 0x67, 0x72, 0x65, 0x73, 0x73, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x22, 0x20, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x4e, 0x45, 0x54, + 0x45, 0x4d, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x42, 0x41, 0x4e, 0x44, 0x57, 0x49, 0x44, 0x54, + 0x48, 0x10, 0x01, 0x22, 0x89, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x44, 0x4e, 0x53, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, + 0x0a, 0x0a, 0x64, 0x6e, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x64, 0x6e, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x16, 0x0a, + 0x06, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, 0x22, + 0x7d, 0x0a, 0x16, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x4a, 0x56, 0x4d, 0x52, 0x75, 0x6c, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x72, 0x75, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, + 0x70, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, 0x22, 0x7f, + 0x0a, 0x18, 0x55, 0x6e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x4a, 0x56, 0x4d, 0x52, 0x75, + 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75, 0x6c, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, 0x22, + 0xf0, 0x01, 0x0a, 0x16, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x68, + 0x61, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, + 0x0b, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x39, + 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, + 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x68, + 0x61, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x05, 0x64, 0x65, 0x6c, + 0x61, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x70, 0x65, 0x63, 0x52, 0x05, 0x64, 0x65, + 0x6c, 0x61, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x4e, 0x53, 0x22, 0x13, 0x0a, + 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x65, 0x6c, 0x61, 0x79, + 0x10, 0x00, 0x22, 0x60, 0x0a, 0x0e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x61, 0x79, + 0x53, 0x70, 0x65, 0x63, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, + 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x0b, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, + 0x6a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6a, 0x69, + 0x74, 0x74, 0x65, 0x72, 0x22, 0x43, 0x0a, 0x0e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x53, 0x70, 0x65, 0x63, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x6f, 0x74, 0x61, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x71, 0x75, 0x6f, 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, + 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x5f, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x08, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x55, 0x73, 0x22, 0x3c, 0x0a, 0x17, 0x41, 0x70, 0x70, + 0x6c, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x68, 0x61, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x69, 0x6e, 0x6a, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x3d, 0x0a, 0x18, 0x52, 0x65, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x68, 0x61, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x69, 0x6e, 0x6a, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x32, 0xd2, 0x08, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x6f, 0x73, + 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x06, 0x53, 0x65, 0x74, 0x54, 0x63, 0x73, + 0x12, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0b, 0x46, 0x6c, + 0x75, 0x73, 0x68, 0x49, 0x50, 0x53, 0x65, 0x74, 0x73, 0x12, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x49, + 0x50, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x48, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x49, 0x70, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x73, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x19, 0x2e, 0x70, 0x62, + 0x2e, 0x49, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, + 0x12, 0x3a, 0x0a, 0x0d, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x12, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x11, + 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x12, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x0d, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4b, 0x69, 0x6c, 0x6c, 0x12, 0x14, 0x2e, + 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x40, 0x0a, + 0x0f, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x47, 0x65, 0x74, 0x50, 0x69, 0x64, + 0x12, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x40, 0x0a, 0x0d, 0x45, 0x78, 0x65, 0x63, 0x53, 0x74, 0x72, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x73, + 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x53, 0x74, 0x72, 0x65, 0x73, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x65, + 0x63, 0x53, 0x74, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x44, 0x0a, 0x0f, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x74, 0x72, 0x65, 0x73, + 0x73, 0x6f, 0x72, 0x73, 0x12, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x53, 0x74, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0c, 0x41, 0x70, 0x70, 0x6c, 0x79, + 0x49, 0x4f, 0x43, 0x68, 0x61, 0x6f, 0x73, 0x12, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, + 0x6c, 0x79, 0x49, 0x4f, 0x43, 0x68, 0x61, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x49, 0x4f, 0x43, 0x68, 0x61, + 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x0e, + 0x41, 0x70, 0x70, 0x6c, 0x79, 0x48, 0x74, 0x74, 0x70, 0x43, 0x68, 0x61, 0x6f, 0x73, 0x12, 0x19, + 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x48, 0x74, 0x74, 0x70, 0x43, 0x68, 0x61, + 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x62, 0x2e, 0x41, + 0x70, 0x70, 0x6c, 0x79, 0x48, 0x74, 0x74, 0x70, 0x43, 0x68, 0x61, 0x6f, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x79, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x68, 0x61, 0x6f, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x62, 0x2e, + 0x41, 0x70, 0x70, 0x6c, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x68, 0x61, 0x6f, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x6c, + 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x68, 0x61, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x68, 0x61, 0x6f, 0x73, 0x12, 0x1c, 0x2e, 0x70, 0x62, 0x2e, + 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x68, 0x61, 0x6f, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0c, 0x53, 0x65, 0x74, 0x44, 0x4e, 0x53, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x12, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x74, 0x44, 0x4e, 0x53, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, + 0x4a, 0x56, 0x4d, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, + 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x4a, 0x56, 0x4d, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x4b, + 0x0a, 0x11, 0x55, 0x6e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x4a, 0x56, 0x4d, 0x52, 0x75, + 0x6c, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6c, 0x6c, 0x4a, 0x56, 0x4d, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_chaosdaemon_proto_rawDescOnce sync.Once + file_chaosdaemon_proto_rawDescData = file_chaosdaemon_proto_rawDesc +) -func init() { - proto.RegisterType((*TcHandle)(nil), "pb.TcHandle") - proto.RegisterType((*ContainerRequest)(nil), "pb.ContainerRequest") - proto.RegisterType((*ContainerResponse)(nil), "pb.ContainerResponse") - proto.RegisterType((*NetemRequest)(nil), "pb.NetemRequest") - proto.RegisterType((*Netem)(nil), "pb.Netem") - proto.RegisterType((*TbfRequest)(nil), "pb.TbfRequest") - proto.RegisterType((*Tbf)(nil), "pb.Tbf") - proto.RegisterType((*QdiscRequest)(nil), "pb.QdiscRequest") - proto.RegisterType((*Qdisc)(nil), "pb.Qdisc") - proto.RegisterType((*EmatchFilterRequest)(nil), "pb.EmatchFilterRequest") - proto.RegisterType((*EmatchFilter)(nil), "pb.EmatchFilter") - proto.RegisterType((*TcFilterRequest)(nil), "pb.TcFilterRequest") - proto.RegisterType((*TcFilter)(nil), "pb.TcFilter") - proto.RegisterType((*IPSetsRequest)(nil), "pb.IPSetsRequest") - proto.RegisterType((*IPSet)(nil), "pb.IPSet") - proto.RegisterType((*IptablesChainsRequest)(nil), "pb.IptablesChainsRequest") - proto.RegisterType((*Chain)(nil), "pb.Chain") - proto.RegisterType((*TimeRequest)(nil), "pb.TimeRequest") - proto.RegisterType((*ContainerAction)(nil), "pb.ContainerAction") - proto.RegisterType((*ExecStressRequest)(nil), "pb.ExecStressRequest") - proto.RegisterType((*ExecStressResponse)(nil), "pb.ExecStressResponse") - proto.RegisterType((*CancelStressRequest)(nil), "pb.CancelStressRequest") - proto.RegisterType((*ApplyIoChaosRequest)(nil), "pb.ApplyIoChaosRequest") - proto.RegisterType((*ApplyIoChaosResponse)(nil), "pb.ApplyIoChaosResponse") - proto.RegisterType((*TcsRequest)(nil), "pb.TcsRequest") - proto.RegisterType((*Tc)(nil), "pb.Tc") - proto.RegisterType((*SetDNSServerRequest)(nil), "pb.SetDNSServerRequest") - proto.RegisterEnum("pb.Chain_Direction", Chain_Direction_name, Chain_Direction_value) - proto.RegisterEnum("pb.ContainerAction_Action", ContainerAction_Action_name, ContainerAction_Action_value) - proto.RegisterEnum("pb.ExecStressRequest_Scope", ExecStressRequest_Scope_name, ExecStressRequest_Scope_value) - proto.RegisterEnum("pb.Tc_Type", Tc_Type_name, Tc_Type_value) +func file_chaosdaemon_proto_rawDescGZIP() []byte { + file_chaosdaemon_proto_rawDescOnce.Do(func() { + file_chaosdaemon_proto_rawDescData = protoimpl.X.CompressGZIP(file_chaosdaemon_proto_rawDescData) + }) + return file_chaosdaemon_proto_rawDescData +} + +var file_chaosdaemon_proto_enumTypes = make([]protoimpl.EnumInfo, 5) +var file_chaosdaemon_proto_msgTypes = make([]protoimpl.MessageInfo, 37) +var file_chaosdaemon_proto_goTypes = []interface{}{ + (Chain_Direction)(0), // 0: pb.Chain.Direction + (ContainerAction_Action)(0), // 1: pb.ContainerAction.Action + (ExecStressRequest_Scope)(0), // 2: pb.ExecStressRequest.Scope + (Tc_Type)(0), // 3: pb.Tc.Type + (ApplyBlockChaosRequest_Action)(0), // 4: pb.ApplyBlockChaosRequest.Action + (*TcHandle)(nil), // 5: pb.TcHandle + (*ContainerRequest)(nil), // 6: pb.ContainerRequest + (*ContainerResponse)(nil), // 7: pb.ContainerResponse + (*NetemRequest)(nil), // 8: pb.NetemRequest + (*Netem)(nil), // 9: pb.Netem + (*TbfRequest)(nil), // 10: pb.TbfRequest + (*Tbf)(nil), // 11: pb.Tbf + (*QdiscRequest)(nil), // 12: pb.QdiscRequest + (*Qdisc)(nil), // 13: pb.Qdisc + (*EmatchFilterRequest)(nil), // 14: pb.EmatchFilterRequest + (*EmatchFilter)(nil), // 15: pb.EmatchFilter + (*TcFilterRequest)(nil), // 16: pb.TcFilterRequest + (*TcFilter)(nil), // 17: pb.TcFilter + (*IPSetsRequest)(nil), // 18: pb.IPSetsRequest + (*IPSet)(nil), // 19: pb.IPSet + (*CidrAndPort)(nil), // 20: pb.CidrAndPort + (*IptablesChainsRequest)(nil), // 21: pb.IptablesChainsRequest + (*Chain)(nil), // 22: pb.Chain + (*TimeRequest)(nil), // 23: pb.TimeRequest + (*ContainerAction)(nil), // 24: pb.ContainerAction + (*ExecStressRequest)(nil), // 25: pb.ExecStressRequest + (*ExecStressResponse)(nil), // 26: pb.ExecStressResponse + (*CancelStressRequest)(nil), // 27: pb.CancelStressRequest + (*ApplyIOChaosRequest)(nil), // 28: pb.ApplyIOChaosRequest + (*ApplyIOChaosResponse)(nil), // 29: pb.ApplyIOChaosResponse + (*ApplyHttpChaosRequest)(nil), // 30: pb.ApplyHttpChaosRequest + (*ApplyHttpChaosResponse)(nil), // 31: pb.ApplyHttpChaosResponse + (*TcsRequest)(nil), // 32: pb.TcsRequest + (*Tc)(nil), // 33: pb.Tc + (*SetDNSServerRequest)(nil), // 34: pb.SetDNSServerRequest + (*InstallJVMRulesRequest)(nil), // 35: pb.InstallJVMRulesRequest + (*UninstallJVMRulesRequest)(nil), // 36: pb.UninstallJVMRulesRequest + (*ApplyBlockChaosRequest)(nil), // 37: pb.ApplyBlockChaosRequest + (*BlockDelaySpec)(nil), // 38: pb.BlockDelaySpec + (*BlockLimitSpec)(nil), // 39: pb.BlockLimitSpec + (*ApplyBlockChaosResponse)(nil), // 40: pb.ApplyBlockChaosResponse + (*RecoverBlockChaosRequest)(nil), // 41: pb.RecoverBlockChaosRequest + (*empty.Empty)(nil), // 42: google.protobuf.Empty +} +var file_chaosdaemon_proto_depIdxs = []int32{ + 24, // 0: pb.ContainerRequest.action:type_name -> pb.ContainerAction + 9, // 1: pb.NetemRequest.netem:type_name -> pb.Netem + 5, // 2: pb.NetemRequest.handle:type_name -> pb.TcHandle + 5, // 3: pb.NetemRequest.parent:type_name -> pb.TcHandle + 5, // 4: pb.Netem.parent:type_name -> pb.TcHandle + 5, // 5: pb.Netem.handle:type_name -> pb.TcHandle + 11, // 6: pb.TbfRequest.tbf:type_name -> pb.Tbf + 13, // 7: pb.QdiscRequest.qdisc:type_name -> pb.Qdisc + 5, // 8: pb.Qdisc.parent:type_name -> pb.TcHandle + 5, // 9: pb.Qdisc.handle:type_name -> pb.TcHandle + 15, // 10: pb.EmatchFilterRequest.filter:type_name -> pb.EmatchFilter + 5, // 11: pb.EmatchFilter.parent:type_name -> pb.TcHandle + 5, // 12: pb.EmatchFilter.classid:type_name -> pb.TcHandle + 17, // 13: pb.TcFilterRequest.filter:type_name -> pb.TcFilter + 5, // 14: pb.TcFilter.parent:type_name -> pb.TcHandle + 19, // 15: pb.IPSetsRequest.ipsets:type_name -> pb.IPSet + 20, // 16: pb.IPSet.cidr_and_ports:type_name -> pb.CidrAndPort + 22, // 17: pb.IptablesChainsRequest.chains:type_name -> pb.Chain + 0, // 18: pb.Chain.direction:type_name -> pb.Chain.Direction + 1, // 19: pb.ContainerAction.action:type_name -> pb.ContainerAction.Action + 2, // 20: pb.ExecStressRequest.scope:type_name -> pb.ExecStressRequest.Scope + 33, // 21: pb.TcsRequest.tcs:type_name -> pb.Tc + 3, // 22: pb.Tc.type:type_name -> pb.Tc.Type + 9, // 23: pb.Tc.netem:type_name -> pb.Netem + 11, // 24: pb.Tc.tbf:type_name -> pb.Tbf + 4, // 25: pb.ApplyBlockChaosRequest.action:type_name -> pb.ApplyBlockChaosRequest.Action + 38, // 26: pb.ApplyBlockChaosRequest.delay:type_name -> pb.BlockDelaySpec + 32, // 27: pb.ChaosDaemon.SetTcs:input_type -> pb.TcsRequest + 18, // 28: pb.ChaosDaemon.FlushIPSets:input_type -> pb.IPSetsRequest + 21, // 29: pb.ChaosDaemon.SetIptablesChains:input_type -> pb.IptablesChainsRequest + 23, // 30: pb.ChaosDaemon.SetTimeOffset:input_type -> pb.TimeRequest + 23, // 31: pb.ChaosDaemon.RecoverTimeOffset:input_type -> pb.TimeRequest + 6, // 32: pb.ChaosDaemon.ContainerKill:input_type -> pb.ContainerRequest + 6, // 33: pb.ChaosDaemon.ContainerGetPid:input_type -> pb.ContainerRequest + 25, // 34: pb.ChaosDaemon.ExecStressors:input_type -> pb.ExecStressRequest + 27, // 35: pb.ChaosDaemon.CancelStressors:input_type -> pb.CancelStressRequest + 28, // 36: pb.ChaosDaemon.ApplyIOChaos:input_type -> pb.ApplyIOChaosRequest + 30, // 37: pb.ChaosDaemon.ApplyHttpChaos:input_type -> pb.ApplyHttpChaosRequest + 37, // 38: pb.ChaosDaemon.ApplyBlockChaos:input_type -> pb.ApplyBlockChaosRequest + 41, // 39: pb.ChaosDaemon.RecoverBlockChaos:input_type -> pb.RecoverBlockChaosRequest + 34, // 40: pb.ChaosDaemon.SetDNSServer:input_type -> pb.SetDNSServerRequest + 35, // 41: pb.ChaosDaemon.InstallJVMRules:input_type -> pb.InstallJVMRulesRequest + 36, // 42: pb.ChaosDaemon.UninstallJVMRules:input_type -> pb.UninstallJVMRulesRequest + 42, // 43: pb.ChaosDaemon.SetTcs:output_type -> google.protobuf.Empty + 42, // 44: pb.ChaosDaemon.FlushIPSets:output_type -> google.protobuf.Empty + 42, // 45: pb.ChaosDaemon.SetIptablesChains:output_type -> google.protobuf.Empty + 42, // 46: pb.ChaosDaemon.SetTimeOffset:output_type -> google.protobuf.Empty + 42, // 47: pb.ChaosDaemon.RecoverTimeOffset:output_type -> google.protobuf.Empty + 42, // 48: pb.ChaosDaemon.ContainerKill:output_type -> google.protobuf.Empty + 7, // 49: pb.ChaosDaemon.ContainerGetPid:output_type -> pb.ContainerResponse + 26, // 50: pb.ChaosDaemon.ExecStressors:output_type -> pb.ExecStressResponse + 42, // 51: pb.ChaosDaemon.CancelStressors:output_type -> google.protobuf.Empty + 29, // 52: pb.ChaosDaemon.ApplyIOChaos:output_type -> pb.ApplyIOChaosResponse + 31, // 53: pb.ChaosDaemon.ApplyHttpChaos:output_type -> pb.ApplyHttpChaosResponse + 40, // 54: pb.ChaosDaemon.ApplyBlockChaos:output_type -> pb.ApplyBlockChaosResponse + 42, // 55: pb.ChaosDaemon.RecoverBlockChaos:output_type -> google.protobuf.Empty + 42, // 56: pb.ChaosDaemon.SetDNSServer:output_type -> google.protobuf.Empty + 42, // 57: pb.ChaosDaemon.InstallJVMRules:output_type -> google.protobuf.Empty + 42, // 58: pb.ChaosDaemon.UninstallJVMRules:output_type -> google.protobuf.Empty + 43, // [43:59] is the sub-list for method output_type + 27, // [27:43] is the sub-list for method input_type + 27, // [27:27] is the sub-list for extension type_name + 27, // [27:27] is the sub-list for extension extendee + 0, // [0:27] is the sub-list for field type_name +} + +func init() { file_chaosdaemon_proto_init() } +func file_chaosdaemon_proto_init() { + if File_chaosdaemon_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_chaosdaemon_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TcHandle); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContainerRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContainerResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NetemRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Netem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TbfRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Tbf); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QdiscRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Qdisc); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EmatchFilterRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EmatchFilter); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TcFilterRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TcFilter); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IPSetsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IPSet); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CidrAndPort); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IptablesChainsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Chain); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TimeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContainerAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExecStressRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExecStressResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CancelStressRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplyIOChaosRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplyIOChaosResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplyHttpChaosRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplyHttpChaosResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TcsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Tc); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetDNSServerRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*InstallJVMRulesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UninstallJVMRulesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplyBlockChaosRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlockDelaySpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlockLimitSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplyBlockChaosResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chaosdaemon_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RecoverBlockChaosRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_chaosdaemon_proto_rawDesc, + NumEnums: 5, + NumMessages: 37, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_chaosdaemon_proto_goTypes, + DependencyIndexes: file_chaosdaemon_proto_depIdxs, + EnumInfos: file_chaosdaemon_proto_enumTypes, + MessageInfos: file_chaosdaemon_proto_msgTypes, + }.Build() + File_chaosdaemon_proto = out.File + file_chaosdaemon_proto_rawDesc = nil + file_chaosdaemon_proto_goTypes = nil + file_chaosdaemon_proto_depIdxs = nil } // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConn +var _ grpc.ClientConnInterface // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 +const _ = grpc.SupportPackageIsVersion6 // ChaosDaemonClient is the client API for ChaosDaemon service. // @@ -1753,15 +3952,20 @@ type ChaosDaemonClient interface { ContainerGetPid(ctx context.Context, in *ContainerRequest, opts ...grpc.CallOption) (*ContainerResponse, error) ExecStressors(ctx context.Context, in *ExecStressRequest, opts ...grpc.CallOption) (*ExecStressResponse, error) CancelStressors(ctx context.Context, in *CancelStressRequest, opts ...grpc.CallOption) (*empty.Empty, error) - ApplyIoChaos(ctx context.Context, in *ApplyIoChaosRequest, opts ...grpc.CallOption) (*ApplyIoChaosResponse, error) + ApplyIOChaos(ctx context.Context, in *ApplyIOChaosRequest, opts ...grpc.CallOption) (*ApplyIOChaosResponse, error) + ApplyHttpChaos(ctx context.Context, in *ApplyHttpChaosRequest, opts ...grpc.CallOption) (*ApplyHttpChaosResponse, error) + ApplyBlockChaos(ctx context.Context, in *ApplyBlockChaosRequest, opts ...grpc.CallOption) (*ApplyBlockChaosResponse, error) + RecoverBlockChaos(ctx context.Context, in *RecoverBlockChaosRequest, opts ...grpc.CallOption) (*empty.Empty, error) SetDNSServer(ctx context.Context, in *SetDNSServerRequest, opts ...grpc.CallOption) (*empty.Empty, error) + InstallJVMRules(ctx context.Context, in *InstallJVMRulesRequest, opts ...grpc.CallOption) (*empty.Empty, error) + UninstallJVMRules(ctx context.Context, in *UninstallJVMRulesRequest, opts ...grpc.CallOption) (*empty.Empty, error) } type chaosDaemonClient struct { - cc *grpc.ClientConn + cc grpc.ClientConnInterface } -func NewChaosDaemonClient(cc *grpc.ClientConn) ChaosDaemonClient { +func NewChaosDaemonClient(cc grpc.ClientConnInterface) ChaosDaemonClient { return &chaosDaemonClient{cc} } @@ -1846,9 +4050,36 @@ func (c *chaosDaemonClient) CancelStressors(ctx context.Context, in *CancelStres return out, nil } -func (c *chaosDaemonClient) ApplyIoChaos(ctx context.Context, in *ApplyIoChaosRequest, opts ...grpc.CallOption) (*ApplyIoChaosResponse, error) { - out := new(ApplyIoChaosResponse) - err := c.cc.Invoke(ctx, "/pb.ChaosDaemon/ApplyIoChaos", in, out, opts...) +func (c *chaosDaemonClient) ApplyIOChaos(ctx context.Context, in *ApplyIOChaosRequest, opts ...grpc.CallOption) (*ApplyIOChaosResponse, error) { + out := new(ApplyIOChaosResponse) + err := c.cc.Invoke(ctx, "/pb.ChaosDaemon/ApplyIOChaos", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chaosDaemonClient) ApplyHttpChaos(ctx context.Context, in *ApplyHttpChaosRequest, opts ...grpc.CallOption) (*ApplyHttpChaosResponse, error) { + out := new(ApplyHttpChaosResponse) + err := c.cc.Invoke(ctx, "/pb.ChaosDaemon/ApplyHttpChaos", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chaosDaemonClient) ApplyBlockChaos(ctx context.Context, in *ApplyBlockChaosRequest, opts ...grpc.CallOption) (*ApplyBlockChaosResponse, error) { + out := new(ApplyBlockChaosResponse) + err := c.cc.Invoke(ctx, "/pb.ChaosDaemon/ApplyBlockChaos", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chaosDaemonClient) RecoverBlockChaos(ctx context.Context, in *RecoverBlockChaosRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/pb.ChaosDaemon/RecoverBlockChaos", in, out, opts...) if err != nil { return nil, err } @@ -1864,6 +4095,24 @@ func (c *chaosDaemonClient) SetDNSServer(ctx context.Context, in *SetDNSServerRe return out, nil } +func (c *chaosDaemonClient) InstallJVMRules(ctx context.Context, in *InstallJVMRulesRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/pb.ChaosDaemon/InstallJVMRules", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chaosDaemonClient) UninstallJVMRules(ctx context.Context, in *UninstallJVMRulesRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/pb.ChaosDaemon/UninstallJVMRules", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ChaosDaemonServer is the server API for ChaosDaemon service. type ChaosDaemonServer interface { SetTcs(context.Context, *TcsRequest) (*empty.Empty, error) @@ -1875,8 +4124,66 @@ type ChaosDaemonServer interface { ContainerGetPid(context.Context, *ContainerRequest) (*ContainerResponse, error) ExecStressors(context.Context, *ExecStressRequest) (*ExecStressResponse, error) CancelStressors(context.Context, *CancelStressRequest) (*empty.Empty, error) - ApplyIoChaos(context.Context, *ApplyIoChaosRequest) (*ApplyIoChaosResponse, error) + ApplyIOChaos(context.Context, *ApplyIOChaosRequest) (*ApplyIOChaosResponse, error) + ApplyHttpChaos(context.Context, *ApplyHttpChaosRequest) (*ApplyHttpChaosResponse, error) + ApplyBlockChaos(context.Context, *ApplyBlockChaosRequest) (*ApplyBlockChaosResponse, error) + RecoverBlockChaos(context.Context, *RecoverBlockChaosRequest) (*empty.Empty, error) SetDNSServer(context.Context, *SetDNSServerRequest) (*empty.Empty, error) + InstallJVMRules(context.Context, *InstallJVMRulesRequest) (*empty.Empty, error) + UninstallJVMRules(context.Context, *UninstallJVMRulesRequest) (*empty.Empty, error) +} + +// UnimplementedChaosDaemonServer can be embedded to have forward compatible implementations. +type UnimplementedChaosDaemonServer struct { +} + +func (*UnimplementedChaosDaemonServer) SetTcs(context.Context, *TcsRequest) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetTcs not implemented") +} +func (*UnimplementedChaosDaemonServer) FlushIPSets(context.Context, *IPSetsRequest) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method FlushIPSets not implemented") +} +func (*UnimplementedChaosDaemonServer) SetIptablesChains(context.Context, *IptablesChainsRequest) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetIptablesChains not implemented") +} +func (*UnimplementedChaosDaemonServer) SetTimeOffset(context.Context, *TimeRequest) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetTimeOffset not implemented") +} +func (*UnimplementedChaosDaemonServer) RecoverTimeOffset(context.Context, *TimeRequest) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method RecoverTimeOffset not implemented") +} +func (*UnimplementedChaosDaemonServer) ContainerKill(context.Context, *ContainerRequest) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method ContainerKill not implemented") +} +func (*UnimplementedChaosDaemonServer) ContainerGetPid(context.Context, *ContainerRequest) (*ContainerResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ContainerGetPid not implemented") +} +func (*UnimplementedChaosDaemonServer) ExecStressors(context.Context, *ExecStressRequest) (*ExecStressResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ExecStressors not implemented") +} +func (*UnimplementedChaosDaemonServer) CancelStressors(context.Context, *CancelStressRequest) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method CancelStressors not implemented") +} +func (*UnimplementedChaosDaemonServer) ApplyIOChaos(context.Context, *ApplyIOChaosRequest) (*ApplyIOChaosResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ApplyIOChaos not implemented") +} +func (*UnimplementedChaosDaemonServer) ApplyHttpChaos(context.Context, *ApplyHttpChaosRequest) (*ApplyHttpChaosResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ApplyHttpChaos not implemented") +} +func (*UnimplementedChaosDaemonServer) ApplyBlockChaos(context.Context, *ApplyBlockChaosRequest) (*ApplyBlockChaosResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ApplyBlockChaos not implemented") +} +func (*UnimplementedChaosDaemonServer) RecoverBlockChaos(context.Context, *RecoverBlockChaosRequest) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method RecoverBlockChaos not implemented") +} +func (*UnimplementedChaosDaemonServer) SetDNSServer(context.Context, *SetDNSServerRequest) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetDNSServer not implemented") +} +func (*UnimplementedChaosDaemonServer) InstallJVMRules(context.Context, *InstallJVMRulesRequest) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method InstallJVMRules not implemented") +} +func (*UnimplementedChaosDaemonServer) UninstallJVMRules(context.Context, *UninstallJVMRulesRequest) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method UninstallJVMRules not implemented") } func RegisterChaosDaemonServer(s *grpc.Server, srv ChaosDaemonServer) { @@ -2045,20 +4352,74 @@ func _ChaosDaemon_CancelStressors_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } -func _ChaosDaemon_ApplyIoChaos_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ApplyIoChaosRequest) +func _ChaosDaemon_ApplyIOChaos_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ApplyIOChaosRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChaosDaemonServer).ApplyIOChaos(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.ChaosDaemon/ApplyIOChaos", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChaosDaemonServer).ApplyIOChaos(ctx, req.(*ApplyIOChaosRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ChaosDaemon_ApplyHttpChaos_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ApplyHttpChaosRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(ChaosDaemonServer).ApplyIoChaos(ctx, in) + return srv.(ChaosDaemonServer).ApplyHttpChaos(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/pb.ChaosDaemon/ApplyIoChaos", + FullMethod: "/pb.ChaosDaemon/ApplyHttpChaos", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ChaosDaemonServer).ApplyIoChaos(ctx, req.(*ApplyIoChaosRequest)) + return srv.(ChaosDaemonServer).ApplyHttpChaos(ctx, req.(*ApplyHttpChaosRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ChaosDaemon_ApplyBlockChaos_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ApplyBlockChaosRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChaosDaemonServer).ApplyBlockChaos(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.ChaosDaemon/ApplyBlockChaos", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChaosDaemonServer).ApplyBlockChaos(ctx, req.(*ApplyBlockChaosRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ChaosDaemon_RecoverBlockChaos_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RecoverBlockChaosRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChaosDaemonServer).RecoverBlockChaos(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.ChaosDaemon/RecoverBlockChaos", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChaosDaemonServer).RecoverBlockChaos(ctx, req.(*RecoverBlockChaosRequest)) } return interceptor(ctx, in, info, handler) } @@ -2081,6 +4442,42 @@ func _ChaosDaemon_SetDNSServer_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _ChaosDaemon_InstallJVMRules_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InstallJVMRulesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChaosDaemonServer).InstallJVMRules(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.ChaosDaemon/InstallJVMRules", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChaosDaemonServer).InstallJVMRules(ctx, req.(*InstallJVMRulesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ChaosDaemon_UninstallJVMRules_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UninstallJVMRulesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChaosDaemonServer).UninstallJVMRules(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.ChaosDaemon/UninstallJVMRules", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChaosDaemonServer).UninstallJVMRules(ctx, req.(*UninstallJVMRulesRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _ChaosDaemon_serviceDesc = grpc.ServiceDesc{ ServiceName: "pb.ChaosDaemon", HandlerType: (*ChaosDaemonServer)(nil), @@ -2122,117 +4519,34 @@ var _ChaosDaemon_serviceDesc = grpc.ServiceDesc{ Handler: _ChaosDaemon_CancelStressors_Handler, }, { - MethodName: "ApplyIoChaos", - Handler: _ChaosDaemon_ApplyIoChaos_Handler, + MethodName: "ApplyIOChaos", + Handler: _ChaosDaemon_ApplyIOChaos_Handler, + }, + { + MethodName: "ApplyHttpChaos", + Handler: _ChaosDaemon_ApplyHttpChaos_Handler, + }, + { + MethodName: "ApplyBlockChaos", + Handler: _ChaosDaemon_ApplyBlockChaos_Handler, + }, + { + MethodName: "RecoverBlockChaos", + Handler: _ChaosDaemon_RecoverBlockChaos_Handler, }, { MethodName: "SetDNSServer", Handler: _ChaosDaemon_SetDNSServer_Handler, }, + { + MethodName: "InstallJVMRules", + Handler: _ChaosDaemon_InstallJVMRules_Handler, + }, + { + MethodName: "UninstallJVMRules", + Handler: _ChaosDaemon_UninstallJVMRules_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "chaosdaemon.proto", } - -func init() { proto.RegisterFile("chaosdaemon.proto", fileDescriptor_chaosdaemon_8b0c6060d3b63305) } - -var fileDescriptor_chaosdaemon_8b0c6060d3b63305 = []byte{ - // 1540 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x57, 0x4f, 0x6f, 0xdb, 0xc6, - 0x12, 0xb7, 0x44, 0xfd, 0xe3, 0x48, 0xb2, 0x65, 0xda, 0xf1, 0x63, 0xec, 0xbc, 0x67, 0x87, 0x48, - 0x1e, 0x02, 0x04, 0x50, 0x5e, 0xfc, 0x80, 0x1e, 0x7a, 0x68, 0xeb, 0xd8, 0x4e, 0xa2, 0x26, 0x91, - 0x5d, 0x8a, 0x41, 0x81, 0x5e, 0x04, 0x8a, 0x5c, 0xd9, 0x8c, 0x29, 0x92, 0xe1, 0xae, 0xdc, 0x18, - 0x39, 0xf5, 0xd8, 0x4b, 0x3f, 0x42, 0x3f, 0x46, 0x7b, 0xeb, 0xc7, 0xe8, 0x57, 0xe9, 0xb5, 0x98, - 0xd9, 0xa5, 0x44, 0xd9, 0x92, 0xab, 0xa6, 0x27, 0xed, 0xcc, 0xce, 0xfc, 0x76, 0x76, 0x66, 0xf8, - 0x9b, 0x15, 0xac, 0x7b, 0xe7, 0x6e, 0xcc, 0x7d, 0x97, 0x8d, 0xe2, 0xa8, 0x9d, 0xa4, 0xb1, 0x88, - 0x8d, 0x62, 0x32, 0xd8, 0xde, 0x39, 0x8b, 0xe3, 0xb3, 0x90, 0x3d, 0x21, 0xcd, 0x60, 0x3c, 0x7c, - 0xc2, 0x46, 0x89, 0xb8, 0x92, 0x06, 0xd6, 0x67, 0x50, 0x73, 0xbc, 0x97, 0x6e, 0xe4, 0x87, 0xcc, - 0xd8, 0x84, 0xf2, 0xc8, 0x7d, 0x17, 0xa7, 0x66, 0x61, 0xaf, 0xf0, 0xa8, 0x69, 0x4b, 0x81, 0xb4, - 0x41, 0x14, 0xa7, 0x66, 0x51, 0x69, 0x51, 0xb0, 0x06, 0xd0, 0x3a, 0x8c, 0x23, 0xe1, 0x06, 0x11, - 0x4b, 0x6d, 0xf6, 0x7e, 0xcc, 0xb8, 0x30, 0x1e, 0x43, 0xc5, 0xf5, 0x44, 0x10, 0x47, 0x04, 0x50, - 0xdf, 0xdf, 0x68, 0x27, 0x83, 0xf6, 0xc4, 0xea, 0x80, 0xb6, 0x6c, 0x65, 0x62, 0xdc, 0x87, 0x86, - 0x97, 0x6d, 0xf5, 0x03, 0x9f, 0xd0, 0x75, 0xbb, 0x3e, 0xd1, 0x75, 0x7c, 0xeb, 0x21, 0xac, 0xe7, - 0xce, 0xe0, 0x49, 0x1c, 0x71, 0x66, 0xb4, 0x40, 0x4b, 0x02, 0x5f, 0x85, 0x88, 0x4b, 0xeb, 0xe7, - 0x02, 0x34, 0xba, 0x4c, 0xb0, 0x51, 0x16, 0xc7, 0x2e, 0x94, 0x23, 0x94, 0x55, 0x18, 0x3a, 0x86, - 0x21, 0x0d, 0xa4, 0x7e, 0x89, 0xb3, 0x8d, 0x07, 0x50, 0x39, 0xa7, 0xac, 0x98, 0x1a, 0x81, 0x34, - 0x10, 0x24, 0xcb, 0x94, 0xad, 0xf6, 0xd0, 0x2a, 0x71, 0x53, 0x16, 0x09, 0xb3, 0x34, 0xcf, 0x4a, - 0xee, 0x59, 0xbf, 0x68, 0x50, 0xa6, 0xf3, 0x0d, 0x03, 0x4a, 0x22, 0x18, 0x31, 0x15, 0x3d, 0xad, - 0x8d, 0x2d, 0xa8, 0xbc, 0x0b, 0x84, 0x60, 0x59, 0x82, 0x95, 0x64, 0xfc, 0x1b, 0xc0, 0x67, 0xa1, - 0x7b, 0xd5, 0xf7, 0xe2, 0x34, 0xa5, 0x28, 0x8a, 0xb6, 0x4e, 0x9a, 0xc3, 0x38, 0xa5, 0xb2, 0x84, - 0xc1, 0x28, 0x90, 0x27, 0x37, 0x6d, 0x29, 0xe0, 0x01, 0x61, 0xcc, 0xb9, 0x59, 0x26, 0x73, 0x5a, - 0x1b, 0x3b, 0xa0, 0xe3, 0xaf, 0xc4, 0xa9, 0xd0, 0x46, 0x0d, 0x15, 0x04, 0xd3, 0x02, 0xed, 0xcc, - 0x4d, 0xcc, 0xaa, 0x4c, 0xe7, 0x99, 0x9b, 0x18, 0xf7, 0x40, 0xf7, 0xc7, 0x49, 0x18, 0x78, 0xae, - 0x60, 0x66, 0x4d, 0x1d, 0x9b, 0x29, 0x8c, 0x87, 0xb0, 0x3a, 0x11, 0x24, 0xa2, 0x4e, 0x26, 0xcd, - 0x89, 0x96, 0x60, 0x4d, 0xa8, 0xa6, 0x2c, 0x4e, 0x7d, 0x96, 0x9a, 0x40, 0xfb, 0x99, 0x88, 0xb9, - 0x57, 0x4b, 0xe9, 0x5e, 0xa7, 0xed, 0xba, 0xd2, 0x65, 0xce, 0xb8, 0x35, 0x4e, 0x84, 0xd9, 0x90, - 0xce, 0x4a, 0x94, 0x85, 0xa3, 0xa5, 0x74, 0x6e, 0x4a, 0x67, 0xa5, 0x23, 0xe7, 0x69, 0x49, 0x56, - 0x17, 0x97, 0x24, 0x57, 0xde, 0xb5, 0xc5, 0xe5, 0xb5, 0xbe, 0x06, 0x70, 0x06, 0xc3, 0xac, 0xad, - 0xee, 0x82, 0x26, 0x06, 0x43, 0xd5, 0x54, 0x55, 0x72, 0x18, 0x0c, 0x6d, 0xd4, 0x2d, 0xd3, 0xcc, - 0x3f, 0x14, 0x40, 0x73, 0x06, 0x43, 0xac, 0x50, 0x8a, 0x99, 0x45, 0x98, 0x92, 0x4d, 0xeb, 0x69, - 0x2d, 0x8b, 0xf9, 0x5a, 0x6e, 0x41, 0x65, 0x30, 0x1e, 0x0e, 0x99, 0x2c, 0x7e, 0xd3, 0x56, 0x12, - 0xd6, 0x33, 0x61, 0xee, 0x45, 0x9f, 0x60, 0x4a, 0x04, 0x53, 0x43, 0x85, 0x8d, 0x50, 0x3b, 0xa0, - 0x8f, 0x82, 0xa8, 0x3f, 0x18, 0xa7, 0x5c, 0x50, 0x17, 0x34, 0xed, 0xda, 0x28, 0x88, 0x9e, 0xa1, - 0x6c, 0xd9, 0xd0, 0xf8, 0xc6, 0x0f, 0xb8, 0x97, 0xfb, 0x50, 0xde, 0xa3, 0x9c, 0xff, 0x50, 0xa4, - 0x81, 0xd4, 0x2f, 0x73, 0xaf, 0x8f, 0x50, 0x26, 0x97, 0x5c, 0xe2, 0x0b, 0x4b, 0x25, 0xbe, 0x78, - 0xcb, 0x77, 0x85, 0xdf, 0xc9, 0x55, 0x22, 0xbf, 0x3d, 0xdd, 0xa6, 0x35, 0xea, 0xdc, 0xf4, 0x8c, - 0x9b, 0xa5, 0x3d, 0x0d, 0x75, 0xb8, 0xb6, 0x06, 0xb0, 0x71, 0x3c, 0x72, 0x85, 0x77, 0xfe, 0x3c, - 0x08, 0xc5, 0x94, 0x88, 0x1e, 0x41, 0x65, 0x48, 0x0a, 0x15, 0x4a, 0x0b, 0x0f, 0x99, 0x31, 0x54, - 0xfb, 0xcb, 0x5c, 0x30, 0x85, 0x46, 0xde, 0x55, 0xb2, 0xa4, 0xf0, 0xce, 0x09, 0x5b, 0xb7, 0xa5, - 0x90, 0xbb, 0x7d, 0xf1, 0x96, 0xdb, 0xff, 0x17, 0xaa, 0x5e, 0xe8, 0x72, 0x1e, 0xf8, 0x73, 0x69, - 0x25, 0xdb, 0xb4, 0xbe, 0x83, 0x35, 0xc7, 0x9b, 0xbd, 0xd3, 0x83, 0x6b, 0x77, 0x52, 0x9e, 0x7f, - 0xff, 0x3e, 0xff, 0x43, 0xc6, 0x57, 0x77, 0x59, 0xaa, 0x66, 0x56, 0x0c, 0xcd, 0xce, 0x69, 0x8f, - 0x09, 0x9e, 0xc5, 0x72, 0x1f, 0x2a, 0x41, 0xc2, 0x99, 0xe0, 0x66, 0x61, 0x4f, 0xcb, 0x1a, 0x87, - 0x4c, 0x6c, 0xb5, 0xb1, 0x0c, 0xc5, 0x9a, 0x50, 0x65, 0x91, 0x60, 0x69, 0xb7, 0x47, 0xc9, 0xa8, - 0xd9, 0x99, 0x68, 0x3d, 0x85, 0x32, 0xa1, 0x61, 0xcd, 0x23, 0x57, 0xf1, 0xa5, 0x6e, 0xd3, 0x1a, - 0xf3, 0xef, 0x05, 0x7e, 0xca, 0xcd, 0x22, 0x35, 0x82, 0x14, 0xac, 0xef, 0xe1, 0x4e, 0x27, 0x11, - 0xee, 0x20, 0x64, 0xfc, 0xf0, 0xdc, 0x0d, 0xa2, 0x7c, 0xac, 0x1e, 0x29, 0xf2, 0xb1, 0x92, 0x89, - 0xad, 0x36, 0xfe, 0x59, 0xac, 0x3f, 0x15, 0xa1, 0x4c, 0x70, 0x73, 0x83, 0x7d, 0x0a, 0xba, 0x1f, - 0xa4, 0x4c, 0x4e, 0x45, 0xc4, 0x5d, 0x55, 0x53, 0x11, 0x3d, 0xda, 0x47, 0xd9, 0x96, 0x3d, 0xb5, - 0xc2, 0xcf, 0x5e, 0x25, 0x57, 0xa3, 0x0b, 0x66, 0x19, 0xdd, 0x82, 0x8a, 0x70, 0xd3, 0x33, 0x26, - 0x19, 0x5f, 0xb7, 0x95, 0x64, 0x6c, 0x43, 0x8d, 0x46, 0xb9, 0x17, 0x87, 0xf4, 0xc1, 0xeb, 0xf6, - 0x44, 0xc6, 0x9b, 0xf1, 0x78, 0x9c, 0x7a, 0xac, 0x9f, 0xc4, 0xa9, 0xe0, 0xc4, 0xfe, 0xba, 0x5d, - 0x97, 0xba, 0x53, 0x54, 0x19, 0x8f, 0x61, 0xdd, 0x67, 0x5c, 0x04, 0x91, 0x8b, 0xa7, 0x2b, 0xbb, - 0x2a, 0xd9, 0xb5, 0x72, 0x1b, 0x64, 0x6c, 0x59, 0xa0, 0x4f, 0x62, 0x36, 0x74, 0x28, 0x77, 0xba, - 0xa7, 0x6f, 0x9d, 0xd6, 0x8a, 0x01, 0x50, 0x39, 0x79, 0xeb, 0xe0, 0xba, 0x60, 0x7d, 0x80, 0xba, - 0x13, 0x8c, 0xd8, 0x34, 0xff, 0xb3, 0xc9, 0x2d, 0xdc, 0x4c, 0x6e, 0x0b, 0x34, 0xce, 0x3c, 0x4a, - 0x8f, 0x66, 0xe3, 0x92, 0x52, 0x89, 0x2a, 0x8d, 0x54, 0xb4, 0x36, 0xf6, 0xa0, 0xe1, 0x85, 0x17, - 0xfd, 0xc0, 0xe7, 0xfd, 0x91, 0xcb, 0x2f, 0x14, 0xf3, 0x81, 0x17, 0x5e, 0x74, 0x7c, 0xfe, 0xc6, - 0xe5, 0x17, 0x16, 0x83, 0xb5, 0x6b, 0xaf, 0x0d, 0x63, 0x7f, 0xe6, 0x49, 0xb2, 0xba, 0xbf, 0x3d, - 0xe7, 0x49, 0xd2, 0x9e, 0x7d, 0x99, 0x58, 0xff, 0x81, 0x8a, 0xf2, 0xae, 0x41, 0xe9, 0x55, 0xe7, - 0xf5, 0x6b, 0x79, 0xc1, 0x17, 0xc7, 0xce, 0x69, 0xe7, 0xa8, 0x55, 0xb0, 0x7e, 0x2d, 0xc0, 0xfa, - 0xf1, 0x07, 0xe6, 0xf5, 0x44, 0xca, 0xf8, 0xa4, 0xcf, 0x9e, 0x42, 0x99, 0x7b, 0x71, 0xc2, 0xd4, - 0x41, 0x3b, 0x44, 0x39, 0xd7, 0xad, 0xda, 0x3d, 0x34, 0xb1, 0xa5, 0x65, 0xae, 0xa2, 0xc5, 0x99, - 0x8a, 0xde, 0x03, 0x9d, 0x93, 0x57, 0x9c, 0x72, 0x45, 0x81, 0x53, 0x45, 0xbe, 0x15, 0x4b, 0xb3, - 0xad, 0xb8, 0x0b, 0x65, 0xc2, 0x37, 0x9a, 0xa0, 0x1f, 0x9e, 0x74, 0x9d, 0x83, 0x4e, 0xf7, 0xd8, - 0x6e, 0xad, 0x18, 0x55, 0xd0, 0x4e, 0x4f, 0x30, 0xf2, 0x2e, 0x18, 0xf9, 0x90, 0xd4, 0x8b, 0x6a, - 0x1b, 0x6a, 0x41, 0xc4, 0x85, 0x1b, 0x79, 0x59, 0xef, 0x4e, 0x64, 0x19, 0x8a, 0x9b, 0x0a, 0xac, - 0xa8, 0x2a, 0xd0, 0x54, 0x61, 0x9d, 0xc0, 0xc6, 0x21, 0x9a, 0x85, 0xb3, 0xa9, 0xf8, 0x74, 0xc0, - 0xdf, 0x0a, 0xb0, 0x71, 0x90, 0x24, 0xe1, 0x55, 0x27, 0x3e, 0xc4, 0xb7, 0x6c, 0x86, 0x68, 0x42, - 0x55, 0x16, 0x87, 0x2b, 0xc0, 0x4c, 0xc4, 0x1c, 0x5e, 0xc6, 0xe1, 0x58, 0x81, 0xe9, 0xb6, 0x92, - 0x6e, 0xb4, 0x9d, 0x76, 0xb3, 0xed, 0xf2, 0x61, 0x96, 0x28, 0x92, 0x05, 0x61, 0x96, 0xaf, 0x85, - 0x99, 0x2f, 0x41, 0x65, 0xb6, 0x04, 0xa7, 0xb0, 0x39, 0x1b, 0xff, 0x82, 0x1c, 0x6b, 0x4b, 0xa7, - 0xe4, 0x23, 0x80, 0xe3, 0xe5, 0x12, 0xa1, 0x09, 0x2f, 0xa3, 0xb2, 0x8a, 0x64, 0x6b, 0x1b, 0x55, - 0xcb, 0x90, 0xd8, 0x16, 0x54, 0x7c, 0x76, 0x19, 0x78, 0xd9, 0x5c, 0x55, 0xd2, 0x2d, 0x1d, 0xf5, - 0x47, 0x01, 0x8a, 0x8e, 0x67, 0xec, 0xaa, 0x71, 0x2c, 0x5b, 0xbb, 0x2e, 0x8f, 0x6d, 0x3b, 0x57, - 0x09, 0x53, 0xb3, 0x79, 0xf2, 0xe2, 0x2e, 0x2e, 0x78, 0x71, 0xab, 0xb7, 0x93, 0x36, 0xe7, 0xed, - 0xb4, 0x09, 0x65, 0x62, 0x38, 0x45, 0x6b, 0x52, 0xb8, 0x95, 0xd5, 0x76, 0xa1, 0x9e, 0x63, 0x35, - 0x45, 0x6a, 0x30, 0x25, 0x35, 0x34, 0x60, 0x67, 0xd8, 0x91, 0xd2, 0x40, 0xb2, 0x19, 0x48, 0x15, - 0x1a, 0x58, 0x7b, 0x50, 0xc2, 0xe8, 0x91, 0xc2, 0xba, 0xc7, 0xce, 0xf1, 0x9b, 0xd6, 0x0a, 0x7e, - 0x33, 0xcf, 0x0e, 0xba, 0x47, 0xdf, 0x76, 0x8e, 0x9c, 0x97, 0xad, 0x82, 0xf5, 0x63, 0x01, 0x36, - 0x7a, 0x4c, 0x1c, 0x75, 0x7b, 0x3d, 0x96, 0x5e, 0x4e, 0xc7, 0xf0, 0x12, 0x74, 0x86, 0x0f, 0xf7, - 0x88, 0xf7, 0x39, 0xf9, 0xa9, 0x3a, 0xe8, 0x7e, 0xc4, 0x25, 0x10, 0x56, 0x81, 0x45, 0x38, 0xa8, - 0xd4, 0x24, 0x51, 0xd2, 0xe2, 0x2a, 0xec, 0xff, 0x5e, 0x86, 0x3a, 0xb5, 0xd3, 0x11, 0xfd, 0xb5, - 0x43, 0x52, 0xeb, 0x31, 0xe1, 0x78, 0xdc, 0x58, 0x95, 0xa5, 0xc8, 0xda, 0x63, 0x7b, 0xab, 0x2d, - 0xff, 0xeb, 0xb5, 0xb3, 0xff, 0x7a, 0xed, 0x63, 0xfc, 0xaf, 0x67, 0xad, 0x18, 0x9f, 0x43, 0xfd, - 0x79, 0x38, 0xe6, 0xe7, 0x72, 0x90, 0x1b, 0xeb, 0x93, 0x89, 0xbd, 0x84, 0xef, 0x4b, 0x58, 0xef, - 0x31, 0x31, 0x3b, 0x5e, 0x8d, 0xbb, 0x84, 0x30, 0x6f, 0xe4, 0xde, 0x1a, 0x45, 0x13, 0x23, 0x0f, - 0x46, 0xec, 0x64, 0x38, 0xc4, 0x32, 0xaf, 0xd1, 0x05, 0xa6, 0xe3, 0xe2, 0x16, 0xdf, 0x2f, 0x60, - 0xdd, 0x66, 0x5e, 0x7c, 0xc9, 0xd2, 0x4f, 0xf3, 0xff, 0x12, 0x9a, 0x13, 0xe2, 0x7f, 0x15, 0x84, - 0xa1, 0xb1, 0x39, 0x33, 0x0b, 0xfe, 0x1a, 0xe0, 0xab, 0xdc, 0x78, 0x79, 0xc1, 0xc4, 0x69, 0xe0, - 0x2f, 0x80, 0xb8, 0x73, 0x4d, 0x2b, 0x39, 0x80, 0x10, 0x9a, 0x53, 0xfe, 0x45, 0x2e, 0xbf, 0x33, - 0x77, 0x4a, 0x6c, 0x6f, 0x5d, 0x57, 0x4f, 0x10, 0x8e, 0x60, 0x2d, 0xcf, 0xb8, 0x88, 0xf1, 0x2f, - 0x3a, 0xed, 0x26, 0x0d, 0xdf, 0x72, 0x93, 0x43, 0x68, 0xe4, 0x59, 0x4a, 0x42, 0xcc, 0xe1, 0xdd, - 0x6d, 0xf3, 0xe6, 0xc6, 0x24, 0x94, 0x03, 0x68, 0xe4, 0x3f, 0x10, 0x09, 0x32, 0xe7, 0x93, 0x59, - 0x1c, 0xc7, 0xa0, 0x42, 0x9a, 0xff, 0xff, 0x19, 0x00, 0x00, 0xff, 0xff, 0x1e, 0xa9, 0xc7, 0xe3, - 0xb9, 0x10, 0x00, 0x00, -} diff --git a/pkg/chaosdaemon/pb/chaosdaemon.proto b/pkg/chaosdaemon/pb/chaosdaemon.proto index 22c20d96ae..02984194d2 100644 --- a/pkg/chaosdaemon/pb/chaosdaemon.proto +++ b/pkg/chaosdaemon/pb/chaosdaemon.proto @@ -20,9 +20,18 @@ service ChaosDaemon { rpc ExecStressors (ExecStressRequest) returns (ExecStressResponse) {} rpc CancelStressors (CancelStressRequest) returns (google.protobuf.Empty) {} - rpc ApplyIoChaos(ApplyIoChaosRequest) returns (ApplyIoChaosResponse) {} + rpc ApplyIOChaos(ApplyIOChaosRequest) returns (ApplyIOChaosResponse) {} + + rpc ApplyHttpChaos(ApplyHttpChaosRequest) returns (ApplyHttpChaosResponse) {} + + rpc ApplyBlockChaos(ApplyBlockChaosRequest) returns (ApplyBlockChaosResponse) {} + rpc RecoverBlockChaos(RecoverBlockChaosRequest) returns (google.protobuf.Empty) {} rpc SetDNSServer (SetDNSServerRequest) returns (google.protobuf.Empty) {} + + rpc InstallJVMRules(InstallJVMRulesRequest) returns (google.protobuf.Empty) {} + + rpc UninstallJVMRules(UninstallJVMRulesRequest) returns (google.protobuf.Empty) {} } message TcHandle { @@ -62,6 +71,7 @@ message Netem { float corrupt_corr = 13; TcHandle parent = 14; TcHandle handle = 15; + string rate = 16; } message TbfRequest { @@ -70,7 +80,7 @@ message TbfRequest { } message Tbf { - uint64 rate = 1; + string rate = 1; uint32 limit = 2; uint32 buffer = 3; uint64 peak_rate = 4; @@ -118,6 +128,14 @@ message IPSetsRequest { message IPSet { string name = 1; repeated string cidrs = 2; + repeated CidrAndPort cidr_and_ports = 3; + repeated string set_names = 4; + string type = 5; +} + +message CidrAndPort { + string cidr = 1; + uint32 port = 2; } message IptablesChainsRequest { @@ -138,6 +156,8 @@ message Chain { string protocol = 5; string source_ports = 6; string destination_ports = 7; + string tcp_flags = 8; + string device = 9; } message TimeRequest { @@ -145,6 +165,8 @@ message TimeRequest { int64 sec = 2; int64 nsec = 3; uint64 clk_ids_mask = 4; + string uid = 5; + string pod_container_name = 6; } message ContainerAction { @@ -162,21 +184,31 @@ message ExecStressRequest { } Scope scope = 1; string target = 2; - string stressors = 3; + string cpuStressors = 3; bool enterNS = 4; + string memoryStressors = 5; + int32 oomScoreAdj = 7; } message ExecStressResponse { - string instance = 1; - int64 startTime = 2; + string cpuInstance = 1; + int64 cpuStartTime = 2; + string memoryInstance = 3; + int64 memoryStartTime = 4; + string cpuInstanceUid = 5; + string memoryInstanceUid = 6; } message CancelStressRequest { - string instance = 1; - int64 startTime = 2; + string cpuInstance = 1; + int64 cpuStartTime = 2; + string memoryInstance = 3; + int64 memoryStartTime = 4; + string cpuInstanceUid = 5; + string memoryInstanceUid = 6; } -message ApplyIoChaosRequest { +message ApplyIOChaosRequest { string actions = 1; string volume = 2; string container_id = 3; @@ -184,17 +216,40 @@ message ApplyIoChaosRequest { int64 instance = 4; int64 startTime = 5; bool enterNS = 6; + string instance_uid = 7; +} + +message ApplyIOChaosResponse { + int64 instance = 1; + int64 startTime = 2; + string instance_uid = 3; +} + +message ApplyHttpChaosRequest { + string rules = 1; + repeated uint32 proxy_ports = 2; + string container_id = 3; + + int64 instance = 4; + int64 startTime = 5; + bool enterNS = 6; + string instance_uid = 7; + + string tls = 8; } -message ApplyIoChaosResponse { +message ApplyHttpChaosResponse { int64 instance = 1; int64 startTime = 2; + int32 statusCode = 3; + string error = 4; + string instance_uid = 5; } + message TcsRequest { repeated Tc tcs = 1; string container_id = 2; - string device = 3; bool enterNS = 4; } @@ -210,6 +265,7 @@ message Tc { string protocol = 5; string source_port = 6; string egress_port = 7; + string device = 9; } message SetDNSServerRequest { @@ -218,3 +274,47 @@ message SetDNSServerRequest { bool enable = 3; bool enterNS = 4; } + +message InstallJVMRulesRequest { + string container_id = 1; + string rule = 2; + int32 port = 3; + bool enterNS = 4; +} + +message UninstallJVMRulesRequest { + string container_id = 1; + string rule = 2; + int32 port = 3; + bool enterNS = 4; +} + +message ApplyBlockChaosRequest { + string container_id = 1; + string volume_path = 2; + enum Action { + Delay = 0; + } + Action action = 3; + BlockDelaySpec delay = 5; + bool enterNS = 6; +} + +message BlockDelaySpec { + int64 delay = 1; + double correlation = 2; + int64 jitter = 3; +} + +message BlockLimitSpec { + uint64 quota = 1; + uint64 period_us = 2; +} + +message ApplyBlockChaosResponse { + int32 injection_id = 1; +} + +message RecoverBlockChaosRequest { + int32 injection_id = 1; +} diff --git a/pkg/chaosdaemon/response.go b/pkg/chaosdaemon/response.go index bd7e926ef4..76d362be43 100644 --- a/pkg/chaosdaemon/response.go +++ b/pkg/chaosdaemon/response.go @@ -1,15 +1,17 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon diff --git a/pkg/chaosdaemon/server.go b/pkg/chaosdaemon/server.go index ec645d31f9..feefc1bda4 100755 --- a/pkg/chaosdaemon/server.go +++ b/pkg/chaosdaemon/server.go @@ -1,15 +1,17 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon @@ -18,36 +20,41 @@ import ( "crypto/tls" "crypto/x509" "fmt" - "io/ioutil" "net" + "net/http" + "os" + "sync" + "github.com/go-logr/logr" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/moby/locker" + "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "golang.org/x/sync/errgroup" "google.golang.org/grpc" "google.golang.org/grpc/credentials" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/reflection" - ctrl "sigs.k8s.io/controller-runtime" "github.com/chaos-mesh/chaos-mesh/pkg/bpm" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients" - pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/tasks" grpcUtils "github.com/chaos-mesh/chaos-mesh/pkg/grpc" + "github.com/chaos-mesh/chaos-mesh/pkg/log" + "github.com/chaos-mesh/chaos-mesh/pkg/metrics" ) -var log = ctrl.Log.WithName("chaos-daemon-server") - //go:generate protoc -I pb pb/chaosdaemon.proto --go_out=plugins=grpc:pb // Config contains the basic chaos daemon configuration. type Config struct { - HTTPPort int - GRPCPort int - Host string - Runtime string - Profiling bool + HTTPPort int + GRPCPort int + Host string + CrClientConfig *crclients.CrClientConfig + Profiling bool tlsConfig } @@ -61,61 +68,78 @@ type tlsConfig struct { // Get the http address func (c *Config) HttpAddr() string { - return fmt.Sprintf("%s:%d", c.Host, c.HTTPPort) + return net.JoinHostPort(c.Host, fmt.Sprintf("%d", c.HTTPPort)) } // Get the grpc address func (c *Config) GrpcAddr() string { - return fmt.Sprintf("%s:%d", c.Host, c.GRPCPort) + return net.JoinHostPort(c.Host, fmt.Sprintf("%d", c.GRPCPort)) } // DaemonServer represents a grpc server for tc daemon type DaemonServer struct { crClient crclients.ContainerRuntimeInfoClient - backgroundProcessManager bpm.BackgroundProcessManager + backgroundProcessManager *bpm.BackgroundProcessManager + rootLogger logr.Logger - IPSetLocker *locker.Locker + // tproxyLocker is a set of tproxy processes to lock stdin/stdout/stderr + tproxyLocker *sync.Map + + IPSetLocker *locker.Locker + timeChaosServer TimeChaosServer } -func newDaemonServer(containerRuntime string) (*DaemonServer, error) { - crClient, err := crclients.CreateContainerRuntimeInfoClient(containerRuntime) +func (s *DaemonServer) getLoggerFromContext(ctx context.Context) logr.Logger { + return log.EnrichLoggerWithContext(ctx, s.rootLogger) +} + +func newDaemonServer(clientConfig *crclients.CrClientConfig, reg prometheus.Registerer, log logr.Logger) (*DaemonServer, error) { + crClient, err := crclients.CreateContainerRuntimeInfoClient(clientConfig) if err != nil { return nil, err } - return NewDaemonServerWithCRClient(crClient), nil + return NewDaemonServerWithCRClient(crClient, reg, log), nil } // NewDaemonServerWithCRClient returns DaemonServer with container runtime client -func NewDaemonServerWithCRClient(crClient crclients.ContainerRuntimeInfoClient) *DaemonServer { +func NewDaemonServerWithCRClient(crClient crclients.ContainerRuntimeInfoClient, reg prometheus.Registerer, log logr.Logger) *DaemonServer { return &DaemonServer{ IPSetLocker: locker.New(), crClient: crClient, - backgroundProcessManager: bpm.NewBackgroundProcessManager(), + backgroundProcessManager: bpm.StartBackgroundProcessManager(reg, log), + tproxyLocker: new(sync.Map), + rootLogger: log, + timeChaosServer: TimeChaosServer{ + podContainerNameProcessMap: tasks.NewPodProcessMap(), + manager: tasks.NewTaskManager(logr.New(log.GetSink()).WithName("TimeChaos")), + nameLocker: tasks.NewLockMap[tasks.PodContainerName](), + logger: logr.New(log.GetSink()).WithName("TimeChaos"), + }, } } -func newGRPCServer(containerRuntime string, reg prometheus.Registerer, tlsConf tlsConfig) (*grpc.Server, error) { - ds, err := newDaemonServer(containerRuntime) - if err != nil { - return nil, err - } - +func newGRPCServer(daemonServer *DaemonServer, reg prometheus.Registerer, tlsConf tlsConfig) (*grpc.Server, error) { grpcMetrics := grpc_prometheus.NewServerMetrics() grpcMetrics.EnableHandlingTimeHistogram( - grpc_prometheus.WithHistogramBuckets([]float64{0.001, 0.01, 0.1, 0.3, 0.6, 1, 3, 6, 10}), + grpc_prometheus.WithHistogramBuckets(metrics.ChaosDaemonGrpcServerBuckets), + metrics.WithHistogramName("chaos_daemon_grpc_server_handling_seconds"), + ) + reg.MustRegister( + grpcMetrics, + metrics.DefaultChaosDaemonMetricsCollector.InjectCrClient(daemonServer.crClient), ) - reg.MustRegister(grpcMetrics) grpcOpts := []grpc.ServerOption{ grpc_middleware.WithUnaryServerChain( grpcUtils.TimeoutServerInterceptor, grpcMetrics.UnaryServerInterceptor(), + MetadataExtractor(log.MetaNamespacedName), ), } if tlsConf != (tlsConfig{}) { - caCert, err := ioutil.ReadFile(tlsConf.CaCert) + caCert, err := os.ReadFile(tlsConf.CaCert) if err != nil { return nil, err } @@ -131,6 +155,7 @@ func newGRPCServer(containerRuntime string, reg prometheus.Registerer, tlsConf t Certificates: []tls.Certificate{serverCert}, ClientCAs: caCertPool, ClientAuth: tls.RequireAndVerifyClientCert, + MinVersion: tls.VersionTLS13, }) grpcOpts = append(grpcOpts, grpc.Creds(creds)) @@ -139,57 +164,98 @@ func newGRPCServer(containerRuntime string, reg prometheus.Registerer, tlsConf t s := grpc.NewServer(grpcOpts...) grpcMetrics.InitializeMetrics(s) - pb.RegisterChaosDaemonServer(s, ds) + pb.RegisterChaosDaemonServer(s, daemonServer) reflection.Register(s) return s, nil } +func MetadataExtractor(keys ...log.Metadatkey) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + // Get the metadata from the incoming context + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return nil, errors.New("couldn't parse incoming context metadata") + } + for _, key := range keys { + values := md.Get(string(key)) + if len(values) > 0 { + ctx = context.WithValue(ctx, key, values[0]) + } + } + + return handler(ctx, req) + } +} + // RegisterGatherer combine prometheus.Registerer and prometheus.Gatherer type RegisterGatherer interface { prometheus.Registerer prometheus.Gatherer } -// StartServer starts chaos-daemon. -func StartServer(conf *Config, reg RegisterGatherer) error { - g := &errgroup.Group{} +// Server is the server for chaos daemon +type Server struct { + daemonServer *DaemonServer + httpServer *http.Server + grpcServer *grpc.Server - httpBindAddr := conf.HttpAddr() - httpServer := newHTTPServerBuilder().Addr(httpBindAddr).Metrics(reg).Profiling(conf.Profiling).Build() + conf *Config + logger logr.Logger +} - grpcBindAddr := conf.GrpcAddr() - grpcListener, err := net.Listen("tcp", grpcBindAddr) +// BuildServer builds a chaos daemon server +func BuildServer(conf *Config, reg RegisterGatherer, log logr.Logger) (*Server, error) { + server := &Server{conf: conf, logger: log} + var err error + server.daemonServer, err = newDaemonServer(conf.CrClientConfig, reg, log) + if err != nil { + return nil, errors.Wrap(err, "create daemon server") + } + + server.httpServer = newHTTPServerBuilder().Addr(conf.HttpAddr()).Metrics(reg).Profiling(conf.Profiling).Build() + server.grpcServer, err = newGRPCServer(server.daemonServer, reg, conf.tlsConfig) if err != nil { - log.Error(err, "failed to listen grpc address", "grpcBindAddr", grpcBindAddr) - return err + return nil, errors.Wrap(err, "create grpc server") } - grpcServer, err := newGRPCServer(conf.Runtime, reg, conf.tlsConfig) + return server, nil +} + +// Start starts chaos-daemon. +func (s *Server) Start() error { + grpcBindAddr := s.conf.GrpcAddr() + grpcListener, err := net.Listen("tcp", grpcBindAddr) if err != nil { - log.Error(err, "failed to create grpc server") - return err + return errors.Wrapf(err, "listen grpc address %s", grpcBindAddr) } - g.Go(func() error { - log.Info("Starting http endpoint", "address", httpBindAddr) - if err := httpServer.ListenAndServe(); err != nil { - log.Error(err, "failed to start http endpoint") - httpServer.Shutdown(context.Background()) - return err + var eg errgroup.Group + + eg.Go(func() error { + s.logger.Info("Starting http endpoint", "address", s.conf.HttpAddr()) + if err := s.httpServer.ListenAndServe(); err != nil { + return errors.Wrap(err, "start http endpoint") } return nil }) - g.Go(func() error { - log.Info("Starting grpc endpoint", "address", grpcBindAddr, "runtime", conf.Runtime) - if err := grpcServer.Serve(grpcListener); err != nil { - log.Error(err, "failed to start grpc endpoint") - grpcServer.Stop() - return err + eg.Go(func() error { + s.logger.Info("Starting grpc endpoint", "address", grpcBindAddr, "runtime", s.conf.CrClientConfig.Runtime) + if err := s.grpcServer.Serve(grpcListener); err != nil { + return errors.Wrap(err, "start grpc endpoint") } return nil }) - return g.Wait() + return eg.Wait() +} + +func (s *Server) Shutdown() error { + if err := s.httpServer.Shutdown(context.TODO()); err != nil { + return errors.Wrap(err, "shut grpc endpoint down") + } + s.grpcServer.GracefulStop() + s.daemonServer.backgroundProcessManager.Shutdown(context.TODO()) + return nil } diff --git a/pkg/chaosdaemon/server_test.go b/pkg/chaosdaemon/server_test.go index a9058bbfce..c6cdc5fb9a 100644 --- a/pkg/chaosdaemon/server_test.go +++ b/pkg/chaosdaemon/server_test.go @@ -1,38 +1,64 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/prometheus/client_golang/prometheus" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients/test" + "github.com/chaos-mesh/chaos-mesh/pkg/log" "github.com/chaos-mesh/chaos-mesh/pkg/mock" ) var _ = Describe("netem server", func() { + logger, err := log.NewDefaultZapLogger() + Expect(err).To(BeNil()) + Context("newDaemonServer", func() { - It("should work", func() { + It("should work without socket path", func() { + _, err := newDaemonServer(&crclients.CrClientConfig{Runtime: crclients.ContainerRuntimeDocker}, nil, logger) + Expect(err).To(BeNil()) defer mock.With("MockContainerdClient", &test.MockClient{})() - _, err := newDaemonServer(crclients.ContainerRuntimeContainerd) + _, err = newDaemonServer(&crclients.CrClientConfig{Runtime: crclients.ContainerRuntimeContainerd}, nil, logger) + Expect(err).To(BeNil()) + }) + + It("should work with socket path", func() { + _, err := newDaemonServer(&crclients.CrClientConfig{ + Runtime: crclients.ContainerRuntimeDocker, + SocketPath: "/foo/bar/docker.socket"}, nil, logger) + Expect(err).To(BeNil()) + }) + + It("should work with socket path and ns", func() { + defer mock.With("MockContainerdClient", &test.MockClient{})() + _, err := newDaemonServer(&crclients.CrClientConfig{Runtime: crclients.ContainerRuntimeContainerd}, nil, logger) + Expect(err).To(BeNil()) + _, err = newDaemonServer(&crclients.CrClientConfig{ + Runtime: crclients.ContainerRuntimeContainerd, + SocketPath: "/foo/bar/containerd.socket", + ContainerdNS: "chaos-mesh.org"}, nil, logger) Expect(err).To(BeNil()) }) It("should fail on CreateContainerRuntimeInfoClient", func() { - _, err := newDaemonServer("invalid-runtime") + _, err := newDaemonServer(&crclients.CrClientConfig{Runtime: "invalid-runtime"}, nil, logger) Expect(err).ToNot(BeNil()) }) }) @@ -40,7 +66,9 @@ var _ = Describe("netem server", func() { Context("newGRPCServer", func() { It("should work", func() { defer mock.With("MockContainerdClient", &test.MockClient{})() - _, err := newGRPCServer(crclients.ContainerRuntimeContainerd, &MockRegisterer{}, tlsConfig{}) + daemonServer, err := newDaemonServer(&crclients.CrClientConfig{Runtime: crclients.ContainerRuntimeContainerd}, nil, logger) + Expect(err).To(BeNil()) + _, err = newGRPCServer(daemonServer, &MockRegisterer{}, tlsConfig{}) Expect(err).To(BeNil()) }) @@ -48,7 +76,10 @@ var _ = Describe("netem server", func() { Ω(func() { defer mock.With("MockContainerdClient", &test.MockClient{})() defer mock.With("PanicOnMustRegister", "mock panic")() - newGRPCServer(crclients.ContainerRuntimeContainerd, &MockRegisterer{}, tlsConfig{}) + daemonServer, err := newDaemonServer(&crclients.CrClientConfig{Runtime: crclients.ContainerRuntimeContainerd}, nil, logger) + Expect(err).To(BeNil()) + _, err = newGRPCServer(daemonServer, &MockRegisterer{}, tlsConfig{}) + Expect(err).To(BeNil()) }).Should(Panic()) }) }) diff --git a/pkg/chaosdaemon/setup_test.go b/pkg/chaosdaemon/setup_test.go index cfb7acc510..f23cad2d41 100644 --- a/pkg/chaosdaemon/setup_test.go +++ b/pkg/chaosdaemon/setup_test.go @@ -1,31 +1,29 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - - "sigs.k8s.io/controller-runtime/pkg/envtest" ) func TestAPIs(t *testing.T) { RegisterFailHandler(Fail) - RunSpecsWithDefaultAndCustomReporters(t, - "chaosdaemon Suite", - []Reporter{envtest.NewlineReporter{}}) + RunSpecs(t, "chaosdaemon Suite") } diff --git a/pkg/chaosdaemon/stress_server_darwin.go b/pkg/chaosdaemon/stress_server_darwin.go index b48ca5c476..6e8e8c5632 100644 --- a/pkg/chaosdaemon/stress_server_darwin.go +++ b/pkg/chaosdaemon/stress_server_darwin.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon diff --git a/pkg/chaosdaemon/stress_server_linux.go b/pkg/chaosdaemon/stress_server_linux.go index c84b2811fc..dbbac2df5c 100644 --- a/pkg/chaosdaemon/stress_server_linux.go +++ b/pkg/chaosdaemon/stress_server_linux.go @@ -1,95 +1,146 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon import ( - "bufio" "context" - "fmt" - "io" - "os" - "path/filepath" "strconv" "strings" "syscall" "time" - "github.com/containerd/cgroups" "github.com/golang/protobuf/ptypes/empty" - "github.com/pkg/errors" - "github.com/shirou/gopsutil/process" "github.com/chaos-mesh/chaos-mesh/pkg/bpm" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/cgroups" pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" -) - -var ( - // Possible cgroup subsystems - cgroupSubsys = []string{"cpu", "memory", "systemd", "net_cls", - "net_prio", "freezer", "blkio", "perf_event", "devices", - "cpuset", "cpuacct", "pids", "hugetlb"} + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/util" ) func (s *DaemonServer) ExecStressors(ctx context.Context, req *pb.ExecStressRequest) (*pb.ExecStressResponse, error) { + log := s.getLoggerFromContext(ctx) log.Info("Executing stressors", "request", req) - pid, err := s.crClient.GetPidFromContainerID(ctx, req.Target) + + // cpuStressors + cpuProc, err := s.ExecCPUStressors(ctx, req) if err != nil { + // this error would be resolved by grpc server framework, it's the top level to print it. + s.rootLogger.Error(err, "exec cpu stressors", "containerID", req.Target, "cpuStressors", req.CpuStressors) return nil, err } - path := pidPath(int(pid)) - id, err := s.crClient.FormatContainerID(ctx, req.Target) + + // memoryStressor + memoryProc, err := s.ExecMemoryStressors(ctx, req) if err != nil { return nil, err } - cgroup, err := findValidCgroup(path, id) - if err != nil { - return nil, err + + resp := new(pb.ExecStressResponse) + if cpuProc != nil { + resp.CpuInstance = strconv.Itoa(cpuProc.Pair.Pid) + resp.CpuStartTime = cpuProc.Pair.CreateTime + resp.CpuInstanceUid = cpuProc.Uid } - if req.Scope == pb.ExecStressRequest_POD { - cgroup, _ = filepath.Split(cgroup) + if memoryProc != nil { + resp.MemoryInstance = strconv.Itoa(memoryProc.Pair.Pid) + resp.MemoryStartTime = memoryProc.Pair.CreateTime + resp.MemoryInstanceUid = memoryProc.Uid } - control, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(cgroup)) - if err != nil { + + return resp, nil +} + +func (s *DaemonServer) CancelStressors(ctx context.Context, + req *pb.CancelStressRequest) (*empty.Empty, error) { + log := s.getLoggerFromContext(ctx) + CpuPid, err := strconv.Atoi(req.CpuInstance) + if req.CpuInstance != "" && err != nil { return nil, err } - processBuilder := bpm.DefaultProcessBuilder("stress-ng", strings.Fields(req.Stressors)...). - EnablePause() - if req.EnterNS { - processBuilder = processBuilder.SetNS(pid, bpm.PidNS) + MemoryPid, err := strconv.Atoi(req.MemoryInstance) + if req.MemoryInstance != "" && err != nil { + return nil, err + } + + if req.CpuInstanceUid == "" && CpuPid != 0 { + if uid, ok := s.backgroundProcessManager.GetUID(bpm.ProcessPair{Pid: CpuPid, CreateTime: req.CpuStartTime}); ok { + req.CpuInstanceUid = uid + } + } + + if req.MemoryInstanceUid == "" && MemoryPid != 0 { + if uid, ok := s.backgroundProcessManager.GetUID(bpm.ProcessPair{Pid: MemoryPid, CreateTime: req.MemoryStartTime}); ok { + req.MemoryInstanceUid = uid + } + } + + log.Info("Canceling stressors", "request", req) + + if req.CpuInstanceUid != "" { + err = s.backgroundProcessManager.KillBackgroundProcess(ctx, req.CpuInstanceUid) + if err != nil { + return nil, err + } + } + + if req.MemoryInstanceUid != "" { + err = s.backgroundProcessManager.KillBackgroundProcess(ctx, req.MemoryInstanceUid) + if err != nil { + return nil, err + } } - cmd := processBuilder.Build() - err = s.backgroundProcessManager.StartProcess(cmd) + log.Info("killing stressor successfully") + return &empty.Empty{}, nil +} + +func (s *DaemonServer) ExecCPUStressors(ctx context.Context, + req *pb.ExecStressRequest) (*bpm.Process, error) { + log := s.getLoggerFromContext(ctx) + if req.CpuStressors == "" { + return nil, nil + } + pid, err := s.crClient.GetPidFromContainerID(ctx, req.Target) if err != nil { return nil, err } - log.Info("Start process successfully") - procState, err := process.NewProcess(int32(cmd.Process.Pid)) + attachCGroup, err := cgroups.GetAttacherForPID(int(pid)) if err != nil { return nil, err } - ct, err := procState.CreateTime() + + processBuilder := bpm.DefaultProcessBuilder("stress-ng", strings.Fields(req.CpuStressors)...). + EnablePause() + if req.EnterNS { + processBuilder = processBuilder.SetNS(pid, bpm.PidNS) + } + cmd := processBuilder.Build(ctx) + + proc, err := s.backgroundProcessManager.StartProcess(ctx, cmd) if err != nil { return nil, err } + log.Info("Start stress-ng successfully", "command", cmd, "pid", proc.Pair.Pid, "uid", proc.Uid) - if err = control.Add(cgroups.Process{Pid: cmd.Process.Pid}); err != nil { + if err = attachCGroup.AttachProcess(proc.Pair.Pid); err != nil { if kerr := cmd.Process.Kill(); kerr != nil { - log.Error(kerr, "kill stressors failed", "request", req) + log.Error(kerr, "kill stress-ng failed", "request", req) } return nil, err } @@ -103,7 +154,8 @@ func (s *DaemonServer) ExecStressors(ctx context.Context, log.Info("send signal to resume process") time.Sleep(time.Millisecond) - comm, err := ReadCommName(cmd.Process.Pid) + // TODO: integrate the resume process into the bpm + comm, err := util.ReadCommName(cmd.Process.Pid) if err != nil { return nil, err } @@ -114,149 +166,68 @@ func (s *DaemonServer) ExecStressors(ctx context.Context, log.Info("the process hasn't resumed, step into the following loop", "comm", comm) } - return &pb.ExecStressResponse{ - Instance: strconv.Itoa(cmd.Process.Pid), - StartTime: ct, - }, nil + return proc, nil } -var errFinished = "os: process already finished" - -func (s *DaemonServer) CancelStressors(ctx context.Context, - req *pb.CancelStressRequest) (*empty.Empty, error) { - pid, err := strconv.Atoi(req.Instance) - if err != nil { - return nil, err +func (s *DaemonServer) ExecMemoryStressors(ctx context.Context, + req *pb.ExecStressRequest) (*bpm.Process, error) { + log := s.getLoggerFromContext(ctx) + if req.MemoryStressors == "" { + return nil, nil } - log.Info("Canceling stressors", "request", req) - - err = s.backgroundProcessManager.KillBackgroundProcess(ctx, pid, req.StartTime) + pid, err := s.crClient.GetPidFromContainerID(ctx, req.Target) if err != nil { return nil, err } - log.Info("killing stressor successfully") - return &empty.Empty{}, nil -} - -func findValidCgroup(path cgroups.Path, target string) (string, error) { - for _, subsys := range cgroupSubsys { - p, err := path(cgroups.Name(subsys)) - if err != nil { - log.Error(err, "Failed to retrieve the cgroup path", "subsystem", subsys, "target", target) - continue - } - if strings.Contains(p, target) { - return p, nil - } - } - return "", fmt.Errorf("never found valid cgroup for %s", target) -} -// pidPath will return the correct cgroup paths for an existing process running inside a cgroup -// This is commonly used for the Load function to restore an existing container. -// -// Note: it is migrated from cgroups.pidPath since it will find mountinfo incorrectly inside -// the daemonset. Hope we can fix it in official cgroups repo to solve it. -func pidPath(pid int) cgroups.Path { - p := fmt.Sprintf("/proc/%d/cgroup", pid) - paths, err := parseCgroupFile(p) + attachCGroup, err := cgroups.GetAttacherForPID(int(pid)) if err != nil { - return errorPath(errors.Wrapf(err, "parse cgroup file %s", p)) + return nil, err } - return existingPath(paths, pid, "") -} -func errorPath(err error) cgroups.Path { - return func(_ cgroups.Name) (string, error) { - return "", err - } -} + processBuilder := bpm.DefaultProcessBuilder("memStress", strings.Fields(req.MemoryStressors)...). + EnablePause() -func existingPath(paths map[string]string, pid int, suffix string) cgroups.Path { - // localize the paths based on the root mount dest for nested cgroups - for n, p := range paths { - dest, err := getCgroupDestination(pid, string(n)) - if err != nil { - return errorPath(err) - } - rel, err := filepath.Rel(dest, p) - if err != nil { - return errorPath(err) - } - if rel == "." { - rel = dest - } - paths[n] = filepath.Join("/", rel) + if req.OomScoreAdj != 0 { + processBuilder = processBuilder.SetOOMScoreAdj(int(req.OomScoreAdj)) } - return func(name cgroups.Name) (string, error) { - root, ok := paths[string(name)] - if !ok { - if root, ok = paths[fmt.Sprintf("name=%s", name)]; !ok { - return "", cgroups.ErrControllerNotActive - } - } - if suffix != "" { - return filepath.Join(root, suffix), nil - } - return root, nil + if req.EnterNS { + processBuilder = processBuilder.SetNS(pid, bpm.PidNS) } -} + cmd := processBuilder.Build(ctx) -func parseCgroupFile(path string) (map[string]string, error) { - f, err := os.Open(path) + proc, err := s.backgroundProcessManager.StartProcess(ctx, cmd) if err != nil { return nil, err } - defer f.Close() - return parseCgroupFromReader(f) -} + log.Info("Start memStress successfully", "command", cmd, "pid", proc.Pair.Pid, "uid", proc.Uid) -func parseCgroupFromReader(r io.Reader) (map[string]string, error) { - var ( - cgroups = make(map[string]string) - s = bufio.NewScanner(r) - ) - for s.Scan() { - var ( - text = s.Text() - parts = strings.SplitN(text, ":", 3) - ) - if len(parts) < 3 { - return nil, fmt.Errorf("invalid cgroup entry: %q", text) - } - for _, subs := range strings.Split(parts[1], ",") { - if subs != "" { - cgroups[subs] = parts[2] - } + if err = attachCGroup.AttachProcess(proc.Pair.Pid); err != nil { + if kerr := cmd.Process.Kill(); kerr != nil { + log.Error(kerr, "kill memStress failed", "request", req) } - } - - if err := s.Err(); err != nil { return nil, err } - return cgroups, nil -} + for { + // TODO: find a better way to resume pause process + if err := cmd.Process.Signal(syscall.SIGCONT); err != nil { + return nil, err + } -func getCgroupDestination(pid int, subsystem string) (string, error) { - // use the process's mount info - p := fmt.Sprintf("/proc/%d/mountinfo", pid) - f, err := os.Open(p) - if err != nil { - return "", err - } - defer f.Close() - s := bufio.NewScanner(f) - for s.Scan() { - fields := strings.Fields(s.Text()) - for _, opt := range strings.Split(fields[len(fields)-1], ",") { - if opt == subsystem { - return fields[3], nil - } + log.Info("send signal to resume process") + time.Sleep(time.Millisecond) + comm, err := util.ReadCommName(proc.Pair.Pid) + + if err != nil { + return nil, err } + if comm != "pause\n" { + log.Info("pause has been resumed", "comm", comm) + break + } + log.Info("the process hasn't resumed, step into the following loop", "comm", comm) } - if err := s.Err(); err != nil { - return "", err - } - return "", fmt.Errorf("never found desct for %s", subsystem) + + return proc, nil } diff --git a/pkg/chaosdaemon/tasks/key_lockmap.go b/pkg/chaosdaemon/tasks/key_lockmap.go new file mode 100644 index 0000000000..fe55ab61f9 --- /dev/null +++ b/pkg/chaosdaemon/tasks/key_lockmap.go @@ -0,0 +1,45 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package tasks + +import "sync" + +type LockMap[K comparable] struct { + sync.Map +} + +func NewLockMap[K comparable]() LockMap[K] { + return LockMap[K]{ + sync.Map{}, + } +} + +func (l *LockMap[K]) Lock(key K) func() { + value, _ := l.LoadOrStore(key, &sync.Mutex{}) + mtx := value.(*sync.Mutex) + mtx.Lock() + + return func() { + if mtx != nil { + mtx.Unlock() + } + } +} + +// Del :TODO: Fix bug on deleting a using value +func (l *LockMap[K]) Del(key K) { + l.Delete(key) +} diff --git a/pkg/chaosdaemon/tasks/pod_container_handler.go b/pkg/chaosdaemon/tasks/pod_container_handler.go new file mode 100644 index 0000000000..df5311e1f4 --- /dev/null +++ b/pkg/chaosdaemon/tasks/pod_container_handler.go @@ -0,0 +1,129 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tasks + +import ( + "sync" + + "github.com/go-logr/logr" + + "github.com/chaos-mesh/chaos-mesh/pkg/cerr" +) + +var ErrNotPodContainerName = cerr.NotType[PodContainerName]() + +var ErrPodProcessMapNotInit = cerr.NotInit[map[PodContainerName]SysPID]().WrapName("PodContainerNameProcessMap").Err() + +type PodContainerName string + +func (p PodContainerName) ToID() string { + return string(p) +} + +// ChaosOnPOD stand for the inner process injector for container. +type ChaosOnPOD interface { + Injectable + Recoverable +} + +type PodContainerNameProcessMap struct { + m map[PodContainerName]SysPID + rwLock sync.RWMutex +} + +func NewPodProcessMap() PodContainerNameProcessMap { + return PodContainerNameProcessMap{ + m: make(map[PodContainerName]SysPID), + rwLock: sync.RWMutex{}, + } +} + +func (p *PodContainerNameProcessMap) Read(PodContainerName PodContainerName) (SysPID, error) { + p.rwLock.RLock() + defer p.rwLock.RUnlock() + sysPID, ok := p.m[PodContainerName] + if !ok { + return SysPID(0), ErrNotFoundSysID.WithStack().Err() + } + return sysPID, nil +} + +func (p *PodContainerNameProcessMap) Write(PodContainerName PodContainerName, sysPID SysPID) { + p.rwLock.Lock() + defer p.rwLock.Unlock() + p.m[PodContainerName] = sysPID +} + +func (p *PodContainerNameProcessMap) Delete(podPID PodContainerName) { + p.rwLock.Lock() + defer p.rwLock.Unlock() + + delete(p.m, podPID) +} + +// PodHandler implements injecting & recovering on a kubernetes POD. +type PodHandler struct { + PodProcessMap *PodContainerNameProcessMap + SubProcess ChaosOnPOD + Logger logr.Logger +} + +func NewPodHandler(podProcessMap *PodContainerNameProcessMap, sub ChaosOnPOD, logger logr.Logger) PodHandler { + return PodHandler{ + PodProcessMap: podProcessMap, + SubProcess: sub, + Logger: logr.New(logger.GetSink()), + } +} + +// Inject get the container process IsID and Inject it with major injector. +// Be careful about the error handling here. +func (p *PodHandler) Inject(id IsID) error { + podPID, ok := id.(PodContainerName) + if !ok { + return ErrNotPodContainerName.WrapInput(id).Err() + } + if p.PodProcessMap == nil { + return ErrPodProcessMapNotInit + } + + sysPID, err := p.PodProcessMap.Read(podPID) + if err != nil { + return err + } + + err = p.SubProcess.Inject(sysPID) + return err +} + +// Recover get the container process IsID and Recover it with major injector. +// Be careful about the error handling here. +func (p *PodHandler) Recover(id IsID) error { + podPID, ok := id.(PodContainerName) + if !ok { + return ErrNotPodContainerName.WrapInput(id).Err() + } + if p.PodProcessMap == nil { + return ErrPodProcessMapNotInit + } + + sysPID, err := p.PodProcessMap.Read(podPID) + if err != nil { + return err + } + + err = p.SubProcess.Recover(sysPID) + return err +} diff --git a/pkg/chaosdaemon/tasks/process_group_handler.go b/pkg/chaosdaemon/tasks/process_group_handler.go new file mode 100644 index 0000000000..5ded57cf37 --- /dev/null +++ b/pkg/chaosdaemon/tasks/process_group_handler.go @@ -0,0 +1,133 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package tasks + +import ( + "strconv" + + "github.com/go-logr/logr" + + "github.com/chaos-mesh/chaos-mesh/pkg/cerr" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/util" +) + +var ErrNotTypeSysID = cerr.NotType[SysPID]() +var ErrNotFoundSysID = cerr.NotFoundType[SysPID]() + +type SysPID uint32 + +func (s SysPID) ToID() string { + return strconv.FormatUint(uint64(s), 10) +} + +// ChaosOnProcessGroup is used for inject a chaos on a linux process group. +// Fork is used for create a new chaos on child process. +// Assign is used for update a chaos on child process. +type ChaosOnProcessGroup interface { + Fork() (ChaosOnProcessGroup, error) + Assign + + Injectable + Recoverable +} + +// ProcessGroupHandler implements injecting & recovering on a linux process group. +type ProcessGroupHandler struct { + LeaderProcess ChaosOnProcessGroup + childMap map[IsID]ChaosOnProcessGroup + Logger logr.Logger +} + +func NewProcessGroupHandler(logger logr.Logger, leader ChaosOnProcessGroup) ProcessGroupHandler { + return ProcessGroupHandler{ + LeaderProcess: leader, + childMap: make(map[IsID]ChaosOnProcessGroup), + Logger: logr.New(logger.GetSink()), + } +} + +// Inject try to inject the leader process and then try to inject child process. +// If something wrong in injecting a child process, Inject will just log error & continue. +func (gp *ProcessGroupHandler) Inject(pid IsID) error { + sysPID, ok := pid.(SysPID) + if !ok { + return ErrNotTypeSysID.WrapInput(pid).Err() + } + + err := gp.LeaderProcess.Inject(sysPID) + if err != nil { + return cerr.FromErr(err).Wrapf("inject leader process: %v", sysPID).Err() + } + + childPIDs, err := util.GetChildProcesses(uint32(sysPID), gp.Logger) + if err != nil { + return cerr.NotFound("child process").WrapErr(err).Err() + } + + for _, childPID := range childPIDs { + childSysPID := SysPID(childPID) + if childProcessChaos, ok := gp.childMap[childSysPID]; ok { + err := gp.LeaderProcess.Assign(childProcessChaos) + if err != nil { + gp.Logger.Error(err, "failed to assign old child process") + continue + } + err = childProcessChaos.Inject(childSysPID) + if err != nil { + gp.Logger.Error(err, "failed to inject old child process") + } + } else { + childProcessChaos, err := gp.LeaderProcess.Fork() + if err != nil { + gp.Logger.Error(err, "failed to create child process") + continue + } + err = childProcessChaos.Inject(childSysPID) + if err != nil { + gp.Logger.Error(err, "failed to inject new child process") + continue + } + gp.childMap[childSysPID] = childProcessChaos + } + } + return nil +} + +// Recover try to recover the leader process and then try to recover child process. +func (gp *ProcessGroupHandler) Recover(pid IsID) error { + _, ok := pid.(SysPID) + if !ok { + return ErrNotTypeSysID.WrapInput(pid).Err() + } + err := gp.LeaderProcess.Recover(pid) + if err != nil { + return cerr.FromErr(err).Wrapf("recovery leader process : %v", pid).Err() + } + + for childID, group := range gp.childMap { + childSysPID, ok := childID.(SysPID) + if !ok { + gp.Logger.Error(cerr.NotType[SysPID]().WrapInput(childID).Err(), + "failed to recover old child process") + } + + err := group.Recover(childSysPID) + if err != nil { + gp.Logger.Error(err, "failed to recover old child process") + } + } + return nil +} diff --git a/pkg/chaosdaemon/tasks/task_config_manager.go b/pkg/chaosdaemon/tasks/task_config_manager.go new file mode 100644 index 0000000000..37f829d8f7 --- /dev/null +++ b/pkg/chaosdaemon/tasks/task_config_manager.go @@ -0,0 +1,183 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package tasks + +import ( + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/pkg/cerr" +) + +var ErrNotFoundID = cerr.NotFound("ID") +var ErrNotFoundTaskID = cerr.NotFound("TaskID") +var ErrNotFoundTypeTaskConfig = cerr.NotFoundType[TaskConfig]() + +var ErrDiffID = cerr.FromErr(errors.New("different IsID")) + +var ErrTaskConfigMapNotInit = cerr.NotInit[map[TaskID]TaskConfig]().WrapName("TaskConfigMap").Err() + +type IsID interface { + ToID() string +} + +// Object ensure the outer config change will not change +// the data inside the TaskManager. +type Object interface { + DeepCopy() Object +} + +// Mergeable introduces the data gathering ability. +type Mergeable interface { + Merge(a Mergeable) error +} + +// TaskConfig defines a composite of flexible config with an immutable target. +// TaskConfig.Id is the ID of task. +// TaskConfig.Data is the config provided by developer. +type TaskConfig struct { + Id IsID + Data Object +} + +func NewTaskConfig(id IsID, data Object) TaskConfig { + return TaskConfig{ + id, + data.DeepCopy(), + } +} + +type TaskID = string + +// TaskConfigManager provides some basic methods on TaskConfig. +// If developers wants to use MergeTaskConfig, they must implement Mergeable for the TaskConfig. +type TaskConfigManager struct { + TaskConfigMap map[TaskID]TaskConfig +} + +func NewTaskConfigManager() TaskConfigManager { + return TaskConfigManager{make(map[TaskID]TaskConfig)} +} + +func (m TaskConfigManager) AddTaskConfig(id TaskID, task TaskConfig) error { + if m.TaskConfigMap == nil { + return ErrTaskConfigMapNotInit + } + if _, ok := m.TaskConfigMap[id]; ok { + return errors.Wrapf(cerr.ErrDuplicateEntity, "uid: %s, task: %v", id, task) + } + m.TaskConfigMap[id] = task + return nil +} + +func (m TaskConfigManager) UpdateTaskConfig(id TaskID, task TaskConfig) (TaskConfig, error) { + if m.TaskConfigMap == nil { + return TaskConfig{}, ErrTaskConfigMapNotInit + } + taskOld, ok := m.TaskConfigMap[id] + if !ok { + return TaskConfig{}, ErrNotFoundTaskID.WrapInput(id).WrapInput(task).Err() + } + if taskOld.Id != task.Id { + return TaskConfig{}, ErrDiffID.Wrapf("expect: %v, input: %v", taskOld.Id, task.Id).Err() + } + m.TaskConfigMap[id] = task + return taskOld, nil +} + +// DeleteTaskConfig Delete task inside the TaskConfigManager +func (m TaskConfigManager) DeleteTaskConfig(id TaskID) error { + if m.TaskConfigMap == nil { + return ErrTaskConfigMapNotInit + } + _, ok := m.TaskConfigMap[id] + if !ok { + return ErrNotFoundTypeTaskConfig.WrapInput(id).Err() + } + delete(m.TaskConfigMap, id) + return nil +} + +func (m TaskConfigManager) GetConfigWithUID(id TaskID) (TaskConfig, error) { + t, ok := m.TaskConfigMap[id] + if !ok { + return TaskConfig{}, ErrNotFoundTaskID.WrapInput(id).Err() + } + return t, nil +} + +func (m TaskConfigManager) GetUIDsWithPID(id IsID) []TaskID { + uIds := make([]TaskID, 0) + for uid, task := range m.TaskConfigMap { + if task.Id == id { + uIds = append(uIds, uid) + } + } + return uIds +} + +func (m TaskConfigManager) CheckTask(uid TaskID, pid IsID) error { + t, ok := m.TaskConfigMap[uid] + if !ok { + return ErrNotFoundTaskID.WrapInput(uid).Err() + } + if t.Id != pid { + return ErrDiffID.Wrapf("expect: %v, input: %v", t.Id, pid).Err() + } + return nil +} + +// MergeTaskConfig will sum the TaskConfig with a same TaskConfig.Id. +// If developers want to use it with type T, they must implement Mergeable for *T. +// IMPORTANT: Just here , we do not assume A.Merge(B) == B.Merge(A). +// What MergeTaskConfig do : A := new(TaskConfig), A.Merge(B).Merge(C).Merge(D)... , A marked as uid. +func (m TaskConfigManager) MergeTaskConfig(uid TaskID) (TaskConfig, error) { + if m.TaskConfigMap == nil { + return TaskConfig{}, ErrTaskConfigMapNotInit + } + taskRaw, ok := m.TaskConfigMap[uid] + if !ok { + return TaskConfig{}, ErrNotFoundTaskID.WrapInput(uid).Err() + } + + task := TaskConfig{ + Id: taskRaw.Id, + Data: taskRaw.Data.DeepCopy(), + } + uids := m.GetUIDsWithPID(task.Id) + + for _, uidTemp := range uids { + if uid == uidTemp { + continue + } + taskTemp, ok := m.TaskConfigMap[uidTemp] + if !ok { + return TaskConfig{}, ErrNotFoundTypeTaskConfig.WrapInput(uidTemp).Err() + } + AddableData, ok := task.Data.(Mergeable) + if !ok { + return TaskConfig{}, cerr.NotImpl[Mergeable]().WrapInput(task.Data).Err() + } + AddableTempData, ok := taskTemp.Data.(Mergeable) + if !ok { + return TaskConfig{}, cerr.NotImpl[Mergeable]().WrapInput(taskTemp.Data).Err() + } + err := AddableData.Merge(AddableTempData) + if err != nil { + return TaskConfig{}, err + } + } + return task, nil +} diff --git a/pkg/chaosdaemon/tasks/task_manager.go b/pkg/chaosdaemon/tasks/task_manager.go new file mode 100644 index 0000000000..5285e3f0cf --- /dev/null +++ b/pkg/chaosdaemon/tasks/task_manager.go @@ -0,0 +1,291 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package tasks + +import ( + "github.com/go-logr/logr" + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/pkg/cerr" +) + +// Injectable stand for the base behavior of task : inject a process with IsID. +type Injectable interface { + Inject(pid IsID) error +} + +// Recoverable introduce the task recovering ability. +// Used in Recover. +type Recoverable interface { + Recover(pid IsID) error +} + +// Creator init an Injectable with values. +// We use it in a case that TaskConfig.Data init an Injectable task here. +type Creator interface { + New(values interface{}) (Injectable, error) +} + +// Assign change some of an Injectable task with its own values. +// We use it in a case that we use TaskConfig.Data +// to update an Injectable task. +type Assign interface { + Assign(Injectable) error +} + +// TaskExecutor indicate that the type can be used +// for execute task here as a task config. +// Mergeable means we can sum many task config in to one for apply. +// Creator means we can use the task config to create a running task +// which can Inject on IsID. +// Assign means we can use the task config to update an existing running task. +type TaskExecutor interface { + Object + Mergeable + Creator + Assign +} + +// TaskManager is a Manager for chaos tasks. +// A task base on a target marked with its IsID. +// We assume task should implement Injectable. +// We use TaskConfig.Data which implement TaskExecutor to: +// +// Sum task configs on same IsID into one. +// Create task. +// Assign or update task. +// +// SO if developers wants to use functions in TaskManager , +// their imported TaskConfig need to implement interface TaskExecutor. +// If developers wants to recover task successfully, +// the task must implement Recoverable. +// If not implement , +// the Recover function will return a ErrNotImplement("Recoverable") error. +// IMPORTANT: We assume task config obey that TaskConfig.Data A,B. A.Merge(B) +// is approximately equal to B.Merge(A) +type TaskManager struct { + taskConfigManager TaskConfigManager + taskMap map[IsID]Injectable + + logger logr.Logger +} + +func NewTaskManager(logger logr.Logger) TaskManager { + return TaskManager{ + NewTaskConfigManager(), + make(map[IsID]Injectable), + logger, + } +} + +func (cm TaskManager) CopyTaskConfigManager() TaskConfigManager { + tm := NewTaskConfigManager() + for uid, task := range cm.taskConfigManager.TaskConfigMap { + tm.TaskConfigMap[uid] = task + } + return tm +} + +func (cm TaskManager) CopyTaskMap() map[IsID]Injectable { + pm := make(map[IsID]Injectable) + for pid, chaosOnProcess := range cm.taskMap { + cm.taskMap[pid] = chaosOnProcess + } + return pm +} + +func (cm TaskManager) GetConfigWithUID(id TaskID) (TaskConfig, error) { + return cm.taskConfigManager.GetConfigWithUID(id) +} + +func (cm TaskManager) GetTaskWithPID(pid IsID) (Injectable, error) { + p, ok := cm.taskMap[pid] + if !ok { + return nil, ErrNotFoundID.WrapInput(pid).Err() + } + return p, nil +} + +func (cm TaskManager) GetUIDsWithPID(pid IsID) []TaskID { + return cm.taskConfigManager.GetUIDsWithPID(pid) +} + +func (cm TaskManager) CheckTasks(uid TaskID, pid IsID) error { + config, err := cm.GetConfigWithUID(uid) + if err != nil { + return err + } + if config.Id != pid { + return ErrDiffID.Wrapf("expected: %v, input: %v", config.Id, pid).Err() + } + return nil +} + +// Create the first task, +// the New function of TaskExecutor:Creator will only be used here. +// values is only the import parameter of New function in TaskExecutor:Creator. +// If it comes a task are already be injected on the IsID, +// Create will return ChaosErr.ErrDuplicateEntity. +func (cm TaskManager) Create(uid TaskID, pid IsID, config TaskExecutor, values interface{}) error { + if _, ok := cm.taskMap[pid]; ok { + return errors.Wrapf(cerr.ErrDuplicateEntity, "create") + } + + err := cm.taskConfigManager.AddTaskConfig(uid, NewTaskConfig(pid, config)) + if err != nil { + return err + } + + processTask, err := config.New(values) + if err != nil { + _ = cm.taskConfigManager.DeleteTaskConfig(uid) + return errors.Wrapf(err, "New task: %v", config) + } + + cm.taskMap[pid] = processTask + err = cm.commit(uid, pid) + if err != nil { + _ = cm.taskConfigManager.DeleteTaskConfig(uid) + delete(cm.taskMap, pid) + return errors.Wrapf(err, "update new task") + } + return nil +} + +// Apply the task when the target pid of task is already be Created. +// If it comes a TaskID injected , Apply will return ChaosErr.ErrDuplicateEntity. +// If the Process has not been Created , Apply will return ChaosErr.NotFound("IsID"). +func (cm TaskManager) Apply(uid TaskID, pid IsID, config TaskExecutor) error { + err := cm.taskConfigManager.AddTaskConfig(uid, NewTaskConfig(pid, config)) + if err != nil { + return err + } + err = cm.commit(uid, pid) + if err != nil { + _ = cm.taskConfigManager.DeleteTaskConfig(uid) + return err + } + return nil +} + +// Update the task with a same TaskID, IsID and new task config. +// If it comes a TaskID not injected , Update will return ChaosErr.NotFound("TaskID"). +// If it comes the import IsID of task do not equal to the last one, +// Update will return ErrDiffID. +func (cm TaskManager) Update(uid TaskID, pid IsID, config TaskExecutor) error { + oldTask, err := cm.taskConfigManager.UpdateTaskConfig(uid, NewTaskConfig(pid, config)) + if err != nil { + return err + } + err = cm.commit(uid, pid) + if err != nil { + _, _ = cm.taskConfigManager.UpdateTaskConfig(uid, oldTask) + return err + } + return nil +} + +// Recover the task when there is no task config on IsID or +// recovering the task with last task config on IsID. +// Recover in Recoverable will be used here, +// if it runs failed it will just return the error. +// If Recover is failed but developer wants to clear it, +// just run : TaskManager.ClearTask(pid, true). +// If IsID is already recovered successfully, Recover will return ChaosErr.NotFound("IsID"). +// If TaskID is not Applied or Created or the target IsID of TaskID is not the import pid, +// Recover will return ChaosErr.NotFound("TaskID"). +func (cm TaskManager) Recover(uid TaskID, pid IsID) error { + uIDs := cm.taskConfigManager.GetUIDsWithPID(pid) + if len(uIDs) == 0 { + return ErrNotFoundTaskID.WrapInput(pid).Err() + } + if len(uIDs) == 1 { + if uIDs[0] != uid { + return ErrNotFoundTaskID.WrapInput(uid).Err() + } + err := cm.ClearTask(pid, false) + if err != nil { + return err + } + err = cm.taskConfigManager.DeleteTaskConfig(uid) + if err != nil { + cm.logger.Error(err, "recover task with error") + } + return nil + } + + err := cm.taskConfigManager.DeleteTaskConfig(uid) + if err != nil { + cm.logger.Error(err, "recover task with error") + return nil + } + + uIDs = cm.taskConfigManager.GetUIDsWithPID(pid) + + err = cm.commit(uIDs[0], pid) + if err != nil { + return errors.Wrapf(err, "update new task") + } + return nil +} + +func (cm TaskManager) commit(uid TaskID, pid IsID) error { + task, err := cm.taskConfigManager.MergeTaskConfig(uid) + if err != nil { + return errors.Wrapf(err, "unknown recovering in the taskConfigManager, TaskID: %v", uid) + } + process, ok := cm.taskMap[pid] + if !ok { + return ErrNotFoundID.WrapInput(pid).Err() + } + tasker, ok := task.Data.(TaskExecutor) + if !ok { + return errors.New("task.Data here must implement TaskExecutor") + } + err = tasker.Assign(process) + if err != nil { + return err + } + err = process.Inject(pid) + if err != nil { + return errors.Wrapf(err, "inject existing process IsID : %v", pid) + } + return nil +} + +// ClearTask clear the task totally. +// IMPORTANT: Developer should only use this function +// when want to force clear task with ignoreRecoverErr==true. +func (cm TaskManager) ClearTask(pid IsID, ignoreRecoverErr bool) error { + if process, ok := cm.taskMap[pid]; ok { + pRecover, ok := process.(Recoverable) + if !ok { + return cerr.NotImpl[Recoverable]().WrapInput(process).Err() + } + err := pRecover.Recover(pid) + if err != nil { + if ignoreRecoverErr { + cm.logger.Error(errors.Wrapf(err, "recover chaos"), "ERR IGNORED") + } else { + return errors.Wrapf(err, "recover chaos") + } + + } + delete(cm.taskMap, pid) + return nil + } + return ErrNotFoundID.WrapInput(pid).Err() +} diff --git a/pkg/chaosdaemon/tasks/tasks_test.go b/pkg/chaosdaemon/tasks/tasks_test.go new file mode 100644 index 0000000000..86ff6cc61a --- /dev/null +++ b/pkg/chaosdaemon/tasks/tasks_test.go @@ -0,0 +1,169 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package tasks + +import ( + "fmt" + "testing" + + "github.com/go-logr/logr" + "github.com/go-logr/zapr" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "go.uber.org/zap" + + "github.com/chaos-mesh/chaos-mesh/pkg/cerr" +) + +type FakeConfig struct { + i int +} + +func (f *FakeConfig) Merge(a Mergeable) error { + A, OK := a.(*FakeConfig) + if OK { + f.i += A.i + return nil + } + return cerr.NotType[*FakeConfig]().WrapInput(a).Err() +} + +func (f *FakeConfig) DeepCopy() Object { + temp := *f + return &temp +} + +func (f *FakeConfig) Assign(c Injectable) error { + C, OK := c.(*FakeChaos) + if OK { + C.C.i = f.i + return nil + } + return cerr.NotType[*FakeConfig]().WrapInput(c).Err() +} + +func (f *FakeConfig) New(immutableValues interface{}) (Injectable, error) { + temp := immutableValues.(*FakeChaos) + f.Assign(temp) + return temp, nil +} + +type FakeChaos struct { + C FakeConfig + ErrWhenRecover bool + ErrWhenInject bool + logger logr.Logger +} + +func (f *FakeChaos) Inject(pid IsID) error { + if f.ErrWhenInject { + return cerr.NotImpl[Injectable]().Err() + } + return nil +} + +func (f *FakeChaos) Recover(pid IsID) error { + if f.ErrWhenRecover { + return cerr.NotImpl[Recoverable]().Err() + } + return nil +} + +func TestTasksManager(t *testing.T) { + var log logr.Logger + + zapLog, err := zap.NewDevelopment() + if err != nil { + panic(fmt.Sprintf("who watches the watchmen (%v)?", err)) + } + log = zapr.NewLogger(zapLog) + + m := NewTaskManager(log) + + chaos := FakeChaos{ + ErrWhenRecover: false, + ErrWhenInject: false, + logger: log, + } + task1 := FakeConfig{i: 1} + uid1 := "1" + err = m.Create(uid1, SysPID(1), &task1, &chaos) + chaosInterface, err := m.GetTaskWithPID(SysPID(1)) + assert.NoError(t, err) + chaoso := chaosInterface.(*FakeChaos) + assert.Equal(t, chaoso.C, task1) + assert.Equal(t, chaoso, &chaos) + + task2 := FakeConfig{i: 1} + uid2 := "2" + err = m.Apply(uid2, SysPID(1), &task2) + chaosInterface, err = m.GetTaskWithPID(SysPID(1)) + assert.NoError(t, err) + chaoso = chaosInterface.(*FakeChaos) + assert.Equal(t, chaoso.C, FakeConfig{i: 2}) + assert.Equal(t, chaos.C, FakeConfig{i: 2}) + + assert.Equal(t, task1, FakeConfig{1}) + assert.Equal(t, task2, FakeConfig{1}) +} + +func TestTasksManagerError(t *testing.T) { + var log logr.Logger + + zapLog, err := zap.NewDevelopment() + if err != nil { + panic(fmt.Sprintf("who watches the watchmen (%v)?", err)) + } + log = zapr.NewLogger(zapLog) + + m := NewTaskManager(log) + + chaos := FakeChaos{ + ErrWhenRecover: false, + ErrWhenInject: false, + logger: log, + } + task1 := FakeConfig{i: 1} + uid1 := "1" + err = m.Create(uid1, SysPID(1), &task1, &chaos) + assert.NoError(t, err) + err = m.Apply(uid1, SysPID(1), &task1) + assert.Equal(t, errors.Cause(err), cerr.ErrDuplicateEntity) + err = m.Recover(uid1, SysPID(1)) + assert.NoError(t, err) + err = m.Recover(uid1, SysPID(1)) + assert.Equal(t, errors.Cause(err), ErrNotFoundTaskID.Err()) + + chaos.ErrWhenInject = true + tasks2 := FakeConfig{i: 1} + err = m.Create(uid1, SysPID(1), &tasks2, &chaos) + assert.Equal(t, errors.Cause(err).Error(), cerr.NotImpl[Injectable]().Err().Error()) + _, err = m.GetConfigWithUID(uid1) + assert.Equal(t, errors.Cause(err), ErrNotFoundTaskID.Err()) + + chaos.ErrWhenInject = false + chaos.ErrWhenRecover = true + tasks3 := FakeConfig{i: 1} + err = m.Create(uid1, SysPID(1), &tasks3, &chaos) + assert.NoError(t, err) + err = m.Recover(uid1, SysPID(1)) + assert.Equal(t, errors.Cause(err).Error(), cerr.NotImpl[Recoverable]().Err().Error()) + p, err := m.GetTaskWithPID(SysPID(1)) + inner := p.(*FakeChaos) + inner.ErrWhenRecover = false + err = m.Recover(uid1, SysPID(1)) + assert.NoError(t, err) +} diff --git a/pkg/chaosdaemon/tc_server.go b/pkg/chaosdaemon/tc_server.go index 00ccc18833..874af20a15 100644 --- a/pkg/chaosdaemon/tc_server.go +++ b/pkg/chaosdaemon/tc_server.go @@ -1,30 +1,36 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon import ( "context" + "encoding/json" "fmt" + "net" "strings" + "github.com/go-logr/logr" + "github.com/golang/protobuf/ptypes/empty" + "github.com/pkg/errors" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "github.com/chaos-mesh/chaos-mesh/pkg/bpm" pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" - - "github.com/golang/protobuf/ptypes/empty" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/util" ) const ( @@ -36,11 +42,11 @@ const ( func generateQdiscArgs(action string, qdisc *pb.Qdisc) ([]string, error) { if qdisc == nil { - return nil, fmt.Errorf("qdisc is required") + return nil, errors.New("qdisc is required") } if qdisc.Type == "" { - return nil, fmt.Errorf("qdisc.Type is required") + return nil, errors.New("qdisc.Type is required") } args := []string{"qdisc", action, "dev", "eth0"} @@ -68,13 +74,43 @@ func generateQdiscArgs(action string, qdisc *pb.Qdisc) ([]string, error) { return args, nil } -func setDefaultTcsRequest(in *pb.TcsRequest) { - if len(in.Device) == 0 { - in.Device = defaultDevice +func getAllInterfaces(ctx context.Context, log logr.Logger, pid uint32, enterNS bool) ([]string, error) { + var ifaces []string + if enterNS { + ipOutput, err := bpm.DefaultProcessBuilder("ip", "-j", "addr", "show").SetNS(pid, bpm.NetNS).SetContext(ctx).Build(ctx).CombinedOutput() + if err != nil { + return []string{}, err + } + var data []map[string]interface{} + + err = json.Unmarshal(ipOutput, &data) + if err != nil { + return []string{}, err + } + for _, iface := range data { + name, ok := iface["ifname"] + if !ok { + return []string{}, errors.New("fail to read ifname from ip -j addr show") + } + ifaces = append(ifaces, name.(string)) + } + log.Info("get interfaces from ip command", "ifaces", ifaces) + } else { + interfaces, err := net.Interfaces() + if err != nil { + return []string{}, errors.New("fail to read ifname from net.Interfaces()") + } + for _, iface := range interfaces { + ifaces = append(ifaces, iface.Name) + } + log.Info("get interfaces from net.Interfaces()", "ifaces", ifaces) } + + return ifaces, nil } func (s *DaemonServer) SetTcs(ctx context.Context, in *pb.TcsRequest) (*empty.Empty, error) { + log := s.getLoggerFromContext(ctx) log.Info("handling tc request", "tcs", in) pid, err := s.crClient.GetPidFromContainerID(ctx, in.ContainerId) @@ -82,70 +118,91 @@ func (s *DaemonServer) SetTcs(ctx context.Context, in *pb.TcsRequest) (*empty.Em return nil, status.Errorf(codes.Internal, "get pid from containerID error: %v", err) } - setDefaultTcsRequest(in) + tcCli := buildTcClient(ctx, log, in.EnterNS, pid) - tcCli := buildTcClient(ctx, in.EnterNS, pid) - err = tcCli.flush(in.Device) + ifaces, err := getAllInterfaces(ctx, log, pid, in.EnterNS) + if err != nil { + log.Error(err, "error while getting interfaces") + return nil, err + } + for _, iface := range ifaces { + err = tcCli.flush(iface) + if err != nil { + log.Error(err, "fail to flush tc rules on device", "device", iface) + } + } if err != nil { - log.Error(err, "error while flushing client") return &empty.Empty{}, err } - // tc rules are split into two different kinds according to whether it has filter. - // all tc rules without filter are called `globalTc` and the tc rules with filter will be called `filterTc`. - // the `globalTc` rules will be piped one by one from root, and the last `globalTc` will be connected with a PRIO - // qdisc, which has `3 + len(filterTc)` bands. Then the 4.. bands will be connected to `filterTc` and a filter will - // be setuped to flow packet from PRIO qdisc to it. - - // for example, four tc rules: - // - NETEM: 50ms latency without filter - // - NETEM: 100ms latency without filter - // - NETEM: 50ms latency with filter ipset A - // - NETEM: 100ms latency with filter ipset B - // will generate tc rules: - // tc qdisc del dev eth0 root - // tc qdisc add dev eth0 root handle 1: netem delay 50000 - // tc qdisc add dev eth0 parent 1: handle 2: netem delay 100000 - // tc qdisc add dev eth0 parent 2: handle 3: prio bands 5 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 - // tc qdisc add dev eth0 parent 3:1 handle 4: sfq - // tc qdisc add dev eth0 parent 3:2 handle 5: sfq - // tc qdisc add dev eth0 parent 3:3 handle 6: sfq - // tc qdisc add dev eth0 parent 3:4 handle 7: netem delay 50000 - // iptables -A TC-TABLES-0 -m set --match-set A dst -j CLASSIFY --set-class 3:4 -w 5 - // tc qdisc add dev eth0 parent 3:5 handle 8: netem delay 100000 - // iptables -A TC-TABLES-1 -m set --match-set B dst -j CLASSIFY --set-class 3:5 -w 5 - - globalTc := []*pb.Tc{} - filterTc := make(map[string][]*pb.Tc) - - for _, tc := range in.Tcs { - filter := abstractTcFilter(tc) - if len(filter) > 0 { - filterTc[filter] = append(filterTc[filter], tc) - continue + for device, rules := range s.groupRulesAccordingToDevices(in.Tcs) { + // tc rules are split into two different kinds according to whether it has filter. + // all tc rules without filter are called `globalTc` and the tc rules with filter will be called `filterTc`. + // the `globalTc` rules will be piped one by one from root, and the last `globalTc` will be connected with a PRIO + // qdisc, which has `3 + len(filterTc)` bands. Then the 4.. bands will be connected to `filterTc` and a filter will + // be setuped to flow packet from PRIO qdisc to it. + + // for example, four tc rules: + // - NETEM: 50ms latency without filter + // - NETEM: 100ms latency without filter + // - NETEM: 50ms latency with filter ipset A + // - NETEM: 100ms latency with filter ipset B + // will generate tc rules: + // tc qdisc del dev eth0 root + // tc qdisc add dev eth0 root handle 1: netem delay 50000 + // tc qdisc add dev eth0 parent 1: handle 2: netem delay 100000 + // tc qdisc add dev eth0 parent 2: handle 3: prio bands 5 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 + // tc qdisc add dev eth0 parent 3:1 handle 4: sfq + // tc qdisc add dev eth0 parent 3:2 handle 5: sfq + // tc qdisc add dev eth0 parent 3:3 handle 6: sfq + // tc qdisc add dev eth0 parent 3:4 handle 7: netem delay 50000 + // iptables -A TC-TABLES-0 -o eth0 -m set --match-set A dst -j CLASSIFY --set-class 3:4 -w 5 + // tc qdisc add dev eth0 parent 3:5 handle 8: netem delay 100000 + // iptables -A TC-TABLES-1 -o eth0 -m set --match-set B dst -j CLASSIFY --set-class 3:5 -w 5 + + globalTc := []*pb.Tc{} + filterTc := make(map[string][]*pb.Tc) + + for _, tc := range rules { + filter := abstractTcFilter(tc) + if len(filter) > 0 { + filterTc[filter] = append(filterTc[filter], tc) + continue + } + globalTc = append(globalTc, tc) } - globalTc = append(globalTc, tc) - } - if len(globalTc) > 0 { - if err := s.setGlobalTcs(tcCli, globalTc, in.Device); err != nil { - log.Error(err, "error while setting global tc") - return &empty.Empty{}, nil + if len(globalTc) > 0 { + if err := s.setGlobalTcs(log, tcCli, globalTc, device); err != nil { + log.Error(err, "error while setting global tc") + return &empty.Empty{}, err + } } - } - if len(filterTc) > 0 { - iptablesCli := buildIptablesClient(ctx, in.EnterNS, pid) - if err := s.setFilterTcs(tcCli, iptablesCli, filterTc, in.Device, len(globalTc)); err != nil { - log.Error(err, "error while setting filter tc") - return &empty.Empty{}, nil + if len(filterTc) > 0 { + iptablesCli := buildIptablesClient(ctx, in.EnterNS, pid) + if err := s.setFilterTcs(log, tcCli, iptablesCli, filterTc, device, len(globalTc)); err != nil { + log.Error(err, "error while setting filter tc") + return &empty.Empty{}, err + } } } return &empty.Empty{}, nil } -func (s *DaemonServer) setGlobalTcs(cli tcClient, tcs []*pb.Tc, device string) error { +func (s *DaemonServer) groupRulesAccordingToDevices(tcs []*pb.Tc) map[string][]*pb.Tc { + rules := make(map[string][]*pb.Tc) + for _, tc := range tcs { + if tc.Device == "" { + tc.Device = defaultDevice + } + rules[tc.Device] = append(rules[tc.Device], tc) + } + return rules +} + +func (s *DaemonServer) setGlobalTcs(log logr.Logger, cli tcClient, tcs []*pb.Tc, device string) error { for index, tc := range tcs { parentArg := "root" if index > 0 { @@ -165,6 +222,7 @@ func (s *DaemonServer) setGlobalTcs(cli tcClient, tcs []*pb.Tc, device string) e } func (s *DaemonServer) setFilterTcs( + log logr.Logger, tcCli tcClient, iptablesCli iptablesClient, filterTc map[string][]*pb.Tc, @@ -207,6 +265,7 @@ func (s *DaemonServer) setFilterTcs( Name: fmt.Sprintf("TC-TABLES-%d", index), Direction: pb.Chain_OUTPUT, Target: fmt.Sprintf("CLASSIFY --set-class %d:%d", parent, index+4), + Device: device, } tc := tcs[0] @@ -214,23 +273,9 @@ func (s *DaemonServer) setFilterTcs( ch.Ipsets = []string{tc.Ipset} } - if len(tc.Protocol) > 0 { - ch.Protocol = fmt.Sprintf("--protocol %s", tc.Protocol) - } - - if len(tc.SourcePort) > 0 { - ch.SourcePorts = fmt.Sprintf("--source-port %s", tc.SourcePort) - if strings.Contains(tc.SourcePort, ",") { - ch.SourcePorts = fmt.Sprintf("-m multiport --source-ports %s", tc.SourcePort) - } - } - - if len(tc.EgressPort) > 0 { - ch.DestinationPorts = fmt.Sprintf("--destination-port %s", tc.EgressPort) - if strings.Contains(tc.EgressPort, ",") { - ch.DestinationPorts = fmt.Sprintf("-m multiport --destination-ports %s", tc.EgressPort) - } - } + ch.Protocol = tc.Protocol + ch.SourcePorts = tc.SourcePort + ch.DestinationPorts = tc.EgressPort chains = append(chains, ch) @@ -246,13 +291,15 @@ func (s *DaemonServer) setFilterTcs( type tcClient struct { ctx context.Context + log logr.Logger enterNS bool pid uint32 } -func buildTcClient(ctx context.Context, enterNS bool, pid uint32) tcClient { +func buildTcClient(ctx context.Context, log logr.Logger, enterNS bool, pid uint32) tcClient { return tcClient{ ctx, + log, enterNS, pid, } @@ -263,23 +310,23 @@ func (c *tcClient) flush(device string) error { if c.enterNS { processBuilder = processBuilder.SetNS(c.pid, bpm.NetNS) } - cmd := processBuilder.Build() + cmd := processBuilder.Build(c.ctx) output, err := cmd.CombinedOutput() if err != nil { if (!strings.Contains(string(output), ruleNotExistLowerVersion)) && (!strings.Contains(string(output), ruleNotExist)) { - return encodeOutputToError(output, err) + return util.EncodeOutputToError(output, err) } } return nil } func (c *tcClient) addTc(device string, parentArg string, handleArg string, tc *pb.Tc) error { - log.Info("add tc", "tc", tc) + c.log.Info("add tc", "tc", tc) if tc.Type == pb.Tc_BANDWIDTH { if tc.Tbf == nil { - return fmt.Errorf("tbf is nil while type is BANDWIDTH") + return errors.New("tbf is nil while type is BANDWIDTH") } err := c.addTbf(device, parentArg, handleArg, tc.Tbf) if err != nil { @@ -289,7 +336,7 @@ func (c *tcClient) addTc(device string, parentArg string, handleArg string, tc * } else if tc.Type == pb.Tc_NETEM { if tc.Netem == nil { - return fmt.Errorf("netem is nil while type is NETEM") + return errors.New("netem is nil while type is NETEM") } err := c.addNetem(device, parentArg, handleArg, tc.Netem) if err != nil { @@ -297,14 +344,14 @@ func (c *tcClient) addTc(device string, parentArg string, handleArg string, tc * } } else { - return fmt.Errorf("unknown tc qdisc type") + return errors.New("unknown tc qdisc type") } return nil } func (c *tcClient) addPrio(device string, parent int, band int) error { - log.Info("adding prio", "parent", parent) + c.log.Info("adding prio", "parent", parent) parentArg := "root" if parent > 0 { @@ -316,10 +363,10 @@ func (c *tcClient) addPrio(device string, parent int, band int) error { if c.enterNS { processBuilder = processBuilder.SetNS(c.pid, bpm.NetNS) } - cmd := processBuilder.Build() + cmd := processBuilder.Build(c.ctx) output, err := cmd.CombinedOutput() if err != nil { - return encodeOutputToError(output, err) + return util.EncodeOutputToError(output, err) } for index := 1; index <= 3; index++ { @@ -329,10 +376,10 @@ func (c *tcClient) addPrio(device string, parent int, band int) error { if c.enterNS { processBuilder = processBuilder.SetNS(c.pid, bpm.NetNS) } - cmd := processBuilder.Build() + cmd := processBuilder.Build(c.ctx) output, err := cmd.CombinedOutput() if err != nil { - return encodeOutputToError(output, err) + return util.EncodeOutputToError(output, err) } } @@ -340,51 +387,33 @@ func (c *tcClient) addPrio(device string, parent int, band int) error { } func (c *tcClient) addNetem(device string, parent string, handle string, netem *pb.Netem) error { - log.Info("adding netem", "device", device, "parent", parent, "handle", handle) + c.log.Info("adding netem", "device", device, "parent", parent, "handle", handle) args := fmt.Sprintf("qdisc add dev %s %s %s netem %s", device, parent, handle, convertNetemToArgs(netem)) processBuilder := bpm.DefaultProcessBuilder("tc", strings.Split(args, " ")...).SetContext(c.ctx) if c.enterNS { processBuilder = processBuilder.SetNS(c.pid, bpm.NetNS) } - cmd := processBuilder.Build() + cmd := processBuilder.Build(c.ctx) output, err := cmd.CombinedOutput() if err != nil { - return encodeOutputToError(output, err) + return util.EncodeOutputToError(output, err) } return nil } func (c *tcClient) addTbf(device string, parent string, handle string, tbf *pb.Tbf) error { - log.Info("adding tbf", "device", device, "parent", parent, "handle", handle) + c.log.Info("adding tbf", "device", device, "parent", parent, "handle", handle) args := fmt.Sprintf("qdisc add dev %s %s %s tbf %s", device, parent, handle, convertTbfToArgs(tbf)) processBuilder := bpm.DefaultProcessBuilder("tc", strings.Split(args, " ")...).SetContext(c.ctx) if c.enterNS { processBuilder = processBuilder.SetNS(c.pid, bpm.NetNS) } - cmd := processBuilder.Build() + cmd := processBuilder.Build(c.ctx) output, err := cmd.CombinedOutput() if err != nil { - return encodeOutputToError(output, err) - } - return nil -} - -func (c *tcClient) addFilter(device string, parent string, classid string, ipset string) error { - log.Info("adding filter", "parent", parent, "classid", classid, "ipset", ipset) - - args := strings.Split(fmt.Sprintf("filter add dev %s %s basic match", device, parent), " ") - args = append(args, fmt.Sprintf("ipset(%s dst)", ipset)) - args = append(args, strings.Split(classid, " ")...) - processBuilder := bpm.DefaultProcessBuilder("tc", args...).SetContext(c.ctx) - if c.enterNS { - processBuilder = processBuilder.SetNS(c.pid, bpm.NetNS) - } - cmd := processBuilder.Build() - output, err := cmd.CombinedOutput() - if err != nil { - return encodeOutputToError(output, err) + return util.EncodeOutputToError(output, err) } return nil } @@ -439,6 +468,10 @@ func convertNetemToArgs(netem *pb.Netem) string { } } + if len(netem.Rate) > 0 { + args = fmt.Sprintf("%s rate %s", args, netem.Rate) + } + trimedArgs := []string{} for _, part := range strings.Split(args, " ") { @@ -451,7 +484,7 @@ func convertNetemToArgs(netem *pb.Netem) string { } func convertTbfToArgs(tbf *pb.Tbf) string { - args := fmt.Sprintf("rate %d burst %d", tbf.Rate, tbf.Buffer) + args := fmt.Sprintf("rate %s burst %d", tbf.Rate, tbf.Buffer) if tbf.Limit > 0 { args = fmt.Sprintf("%s limit %d", args, tbf.Limit) } diff --git a/pkg/chaosdaemon/tc_server_test.go b/pkg/chaosdaemon/tc_server_test.go index e699083e67..d095057a8c 100644 --- a/pkg/chaosdaemon/tc_server_test.go +++ b/pkg/chaosdaemon/tc_server_test.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon @@ -169,4 +171,13 @@ func Test_convertNetemToArgs(t *testing.T) { }) g.Expect(args).To(Equal("delay 1000 10000 reorder 5.000000 gap 10 corrupt 10.000000 50.000000")) }) + + t.Run("delay with rate", func(t *testing.T) { + args := convertNetemToArgs(&pb.Netem{ + Time: 1000, + Jitter: 10000, + Rate: "8000bit", + }) + g.Expect(args).To(Equal("delay 1000 10000 rate 8000bit")) + }) } diff --git a/pkg/chaosdaemon/time_server.go b/pkg/chaosdaemon/time_server.go deleted file mode 100644 index 40466a5953..0000000000 --- a/pkg/chaosdaemon/time_server.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package chaosdaemon - -import ( - "context" - - "github.com/chaos-mesh/chaos-mesh/pkg/time" - - "github.com/golang/protobuf/ptypes/empty" - - pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" -) - -func (s *DaemonServer) SetTimeOffset(ctx context.Context, req *pb.TimeRequest) (*empty.Empty, error) { - log.Info("Shift time", "Request", req) - - pid, err := s.crClient.GetPidFromContainerID(ctx, req.ContainerId) - if err != nil { - log.Error(err, "error while getting PID") - return nil, err - } - - childPids, err := GetChildProcesses(pid) - if err != nil { - log.Error(err, "fail to get child processes") - } - allPids := append(childPids, pid) - log.Info("all related processes found", "pids", allPids) - - for _, pid := range allPids { - err = time.ModifyTime(int(pid), req.Sec, req.Nsec, req.ClkIdsMask) - if err != nil { - log.Error(err, "error while modifying time", "pid", pid) - return nil, err - } - } - - return &empty.Empty{}, nil -} - -func (s *DaemonServer) RecoverTimeOffset(ctx context.Context, req *pb.TimeRequest) (*empty.Empty, error) { - log.Info("Recover time", "Request", req) - - pid, err := s.crClient.GetPidFromContainerID(ctx, req.ContainerId) - if err != nil { - log.Error(err, "error while getting PID") - return nil, err - } - - childPids, err := GetChildProcesses(pid) - if err != nil { - log.Error(err, "fail to get child processes") - } - allPids := append(childPids, pid) - log.Info("get all related process pids", "pids", allPids) - - for _, pid := range allPids { - // FIXME: if the process has halted and no process with this pid exists, we will get an error. - err = time.ModifyTime(int(pid), int64(0), int64(0), 0) - if err != nil { - log.Error(err, "error while recovering", "pid", pid) - return nil, err - } - } - - return &empty.Empty{}, nil -} diff --git a/pkg/chaosdaemon/time_server_darwin.go b/pkg/chaosdaemon/time_server_darwin.go new file mode 100644 index 0000000000..8ccf867d07 --- /dev/null +++ b/pkg/chaosdaemon/time_server_darwin.go @@ -0,0 +1,54 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Since TimeChaos is not unimplemented in darwin os. This file is only used for debugging, for example if your editor has gopls activated automatically. + +package chaosdaemon + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/golang/protobuf/ptypes/empty" + + pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/tasks" +) + +type TimeChaosServer struct { + podContainerNameProcessMap tasks.PodContainerNameProcessMap + manager tasks.TaskManager + + nameLocker tasks.LockMap[tasks.PodContainerName] + logger logr.Logger +} + +func (s *TimeChaosServer) SetPodContainerNameProcess(idName tasks.PodContainerName, sysID tasks.SysPID) { +} + +func (s *TimeChaosServer) DelPodContainerNameProcess(idName tasks.PodContainerName) { +} + +func (s *TimeChaosServer) SetTimeOffset(uid tasks.TaskID, id tasks.PodContainerName, config interface{}) error { + return nil +} + +func (s *DaemonServer) SetTimeOffset(ctx context.Context, req *pb.TimeRequest) (*empty.Empty, error) { + return &empty.Empty{}, nil +} + +func (s *DaemonServer) RecoverTimeOffset(ctx context.Context, req *pb.TimeRequest) (*empty.Empty, error) { + return &empty.Empty{}, nil +} diff --git a/pkg/chaosdaemon/time_server_linux.go b/pkg/chaosdaemon/time_server_linux.go new file mode 100644 index 0000000000..5997c4817a --- /dev/null +++ b/pkg/chaosdaemon/time_server_linux.go @@ -0,0 +1,126 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package chaosdaemon + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/golang/protobuf/ptypes/empty" + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/pkg/cerr" + pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/tasks" + "github.com/chaos-mesh/chaos-mesh/pkg/time" +) + +type TimeChaosServer struct { + podContainerNameProcessMap tasks.PodContainerNameProcessMap + manager tasks.TaskManager + + nameLocker tasks.LockMap[tasks.PodContainerName] + logger logr.Logger +} + +func (s *TimeChaosServer) SetPodContainerNameProcess(idName tasks.PodContainerName, sysID tasks.SysPID) { + s.podContainerNameProcessMap.Write(idName, sysID) +} + +func (s *TimeChaosServer) DelPodContainerNameProcess(idName tasks.PodContainerName) { + s.podContainerNameProcessMap.Delete(idName) +} + +func (s *TimeChaosServer) SetTimeOffset(uid tasks.TaskID, id tasks.PodContainerName, config time.Config) error { + paras := time.ConfigCreatorParas{ + Logger: s.logger, + Config: config, + PodProcessMap: &s.podContainerNameProcessMap, + } + + unlock := s.nameLocker.Lock(id) + defer unlock() + // We assume the base time skew is not sensitive with process changes which + // means time skew will not return error when the task target pod changes container id & IsID. + // We assume controller will never update tasks. + // According to the above, we do not handle error from s.manager.Apply like + // ErrDuplicateEntity(task TaskID). + err := s.manager.Create(uid, id, &config, paras) + if err != nil { + if errors.Cause(err) == cerr.ErrDuplicateEntity { + err := s.manager.Apply(uid, id, &config) + if err != nil { + return err + } + } else { + return err + } + } + return nil +} + +func (s *DaemonServer) SetTimeOffset(ctx context.Context, req *pb.TimeRequest) (*empty.Empty, error) { + logger := s.timeChaosServer.logger + + logger.Info("Shift time", "Request", req) + + pid, err := s.crClient.GetPidFromContainerID(ctx, req.ContainerId) + if err != nil { + logger.Error(err, "error while getting IsID") + return nil, err + } + + s.timeChaosServer.SetPodContainerNameProcess(tasks.PodContainerName(req.PodContainerName), tasks.SysPID(pid)) + err = s.timeChaosServer.SetTimeOffset(req.Uid, tasks.PodContainerName(req.PodContainerName), + time.NewConfig(req.Sec, req.Nsec, req.ClkIdsMask)) + if err != nil { + logger.Error(err, "error while applying chaos") + return nil, err + } + return &empty.Empty{}, nil +} + +func (s *DaemonServer) RecoverTimeOffset(ctx context.Context, req *pb.TimeRequest) (*empty.Empty, error) { + logger := s.timeChaosServer.logger + + logger.Info("Recover time", "Request", req) + + pid, err := s.crClient.GetPidFromContainerID(ctx, req.ContainerId) + if err != nil { + logger.Error(err, "error while getting IsID") + return nil, err + } + + nameID := tasks.PodContainerName(req.PodContainerName) + + s.timeChaosServer.SetPodContainerNameProcess(nameID, tasks.SysPID(pid)) + + unlock := s.timeChaosServer.nameLocker.Lock(nameID) + defer unlock() + + err = s.timeChaosServer.manager.Recover(req.Uid, nameID) + if err != nil { + logger.Error(err, "error while recovering chaos") + return nil, err + } + + if len(s.timeChaosServer.manager.GetUIDsWithPID(nameID)) == 0 { + s.timeChaosServer.DelPodContainerNameProcess(nameID) + s.timeChaosServer.nameLocker.Del(nameID) + } + + return &empty.Empty{}, nil +} diff --git a/pkg/chaosdaemon/time_server_test.go b/pkg/chaosdaemon/time_server_test.go deleted file mode 100644 index d4181169eb..0000000000 --- a/pkg/chaosdaemon/time_server_test.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package chaosdaemon - -import ( - "context" - "errors" - - "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients" - "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients/test" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" - "github.com/chaos-mesh/chaos-mesh/pkg/mock" -) - -var _ = Describe("time server", func() { - defer mock.With("MockContainerdClient", &test.MockClient{})() - s, _ := newDaemonServer(crclients.ContainerRuntimeContainerd) - - Context("SetTimeOffset", func() { - It("should work", func() { - // Inject nil error to ignore any error - const ignore = true - defer mock.With("ModifyTimeError", ignore)() - - _, err := s.SetTimeOffset(context.TODO(), &pb.TimeRequest{ - ContainerId: "containerd://container-id", - }) - Expect(err).To(BeNil()) - }) - - It("should fail on get pid", func() { - const errorStr = "mock error on load container" - defer mock.With("LoadContainerError", errors.New(errorStr))() - - _, err := s.SetTimeOffset(context.TODO(), &pb.TimeRequest{ - ContainerId: "containerd://container-id", - }) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(Equal(errorStr)) - }) - - It("should fail on modify time", func() { - const errorStr = "mock error on modify time" - defer mock.With("ModifyTimeError", errors.New(errorStr))() - - _, err := s.SetTimeOffset(context.TODO(), &pb.TimeRequest{ - ContainerId: "containerd://container-id", - }) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(Equal(errorStr)) - }) - }) - - Context("RecoverTimeOffset", func() { - It("should work", func() { - // Inject nil error to ignore any error - const ignore = true - defer mock.With("ModifyTimeError", ignore)() - - _, err := s.RecoverTimeOffset(context.TODO(), &pb.TimeRequest{ - ContainerId: "containerd://container-id", - }) - Expect(err).To(BeNil()) - }) - - It("should fail on get pid", func() { - const errorStr = "mock error on load container" - defer mock.With("LoadContainerError", errors.New(errorStr))() - - _, err := s.RecoverTimeOffset(context.TODO(), &pb.TimeRequest{ - ContainerId: "containerd://container-id", - }) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(Equal(errorStr)) - }) - - It("should fail on modify time", func() { - const errorStr = "mock error on modify time" - defer mock.With("ModifyTimeError", errors.New(errorStr))() - - _, err := s.RecoverTimeOffset(context.TODO(), &pb.TimeRequest{ - ContainerId: "containerd://container-id", - }) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(Equal(errorStr)) - }) - }) -}) diff --git a/pkg/chaosdaemon/tproxyconfig/config.go b/pkg/chaosdaemon/tproxyconfig/config.go new file mode 100644 index 0000000000..0b880da3f7 --- /dev/null +++ b/pkg/chaosdaemon/tproxyconfig/config.go @@ -0,0 +1,205 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package tproxyconfig + +import ( + "encoding/json" +) + +type Config struct { + ProxyPorts []uint32 `json:"proxy_ports,omitempty"` + Rules []PodHttpChaosBaseRule `json:"rules"` + TLS *TLSConfig `json:"tls,omitempty"` +} + +type TLSConfig struct { + CertFile TLSConfigItem `json:"cert_file,omitempty"` + KeyFile TLSConfigItem `json:"key_file,omitempty"` + CAFile *TLSConfigItem `json:"ca_file,omitempty"` +} + +type TLSConfigItem struct { + Type string `json:"type"` + Value []byte `json:"value"` +} + +// PodHttpChaosBaseRule defines the injection rule without source and port. +type PodHttpChaosBaseRule struct { + // Target is the object to be selected and injected, . + Target PodHttpChaosTarget `json:"target"` + + // Selector contains the rules to select target. + Selector PodHttpChaosSelector `json:"selector"` + + // Actions contains rules to inject target. + Actions PodHttpChaosActions `json:"actions"` +} + +type PodHttpChaosSelector struct { + // Port is a rule to select server listening on specific port. + // +optional + Port *int32 `json:"port,omitempty"` + + // Path is a rule to select target by uri path in http request. + // +optional + Path *string `json:"path,omitempty"` + + // Method is a rule to select target by http method in request. + // +optional + Method *string `json:"method,omitempty"` + + // Code is a rule to select target by http status code in response. + // +optional + Code *int32 `json:"code,omitempty"` + + // RequestHeaders is a rule to select target by http headers in request. + // The key-value pairs represent header name and header value pairs. + // +optional + RequestHeaders map[string]string `json:"request_headers,omitempty"` + + // ResponseHeaders is a rule to select target by http headers in response. + // The key-value pairs represent header name and header value pairs. + // +optional + ResponseHeaders map[string]string `json:"response_headers,omitempty"` +} + +// PodHttpChaosActions defines possible actions of HttpChaos. +type PodHttpChaosActions struct { + // Abort is a rule to abort a http session. + // +optional + Abort *bool `json:"abort,omitempty"` + + // Delay represents the delay of the target request/response. + // A duration string is a possibly unsigned sequence of + // decimal numbers, each with optional fraction and a unit suffix, + // such as "300ms", "2h45m". + // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + // +optional + Delay *string `json:"delay,omitempty"` + + // Replace is a rule to replace some contents in target. + // +optional + Replace *PodHttpChaosReplaceActions `json:"replace,omitempty"` + + // Patch is a rule to patch some contents in target. + // +optional + Patch *PodHttpChaosPatchActions `json:"patch,omitempty"` +} + +// PodHttpChaosPatchBody defines the patch-body action of HttpChaos. +type PodHttpChaosPatchBody struct { + Contents PodHttpChaosBodyPatchContent `json:"contents"` +} + +type PodHttpChaosBodyPatchContent struct { + // Type represents the patch type, only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) currently. + Type string `json:"type"` + + // Value is the patch contents. + Value string `json:"value"` +} + +func (p *PodHttpChaosPatchBody) UnmarshalJSON(data []byte) error { + var pp PodHttpChaosBodyPatchContent + err := json.Unmarshal(data, &pp) + if err != nil { + return err + } + p.Contents = pp + return nil +} + +// PodHttpChaosPatchActions defines possible patch-actions of HttpChaos. +type PodHttpChaosPatchActions struct { + // Body is a rule to patch message body of target. + // +optional + Body *PodHttpChaosPatchBody `json:"body,omitempty"` + + // Queries is a rule to append uri queries of target(Request only). + // For example: `[["foo", "bar"], ["foo", "unknown"]]`. + // +optional + Queries [][]string `json:"queries,omitempty"` + + // Headers is a rule to append http headers of target. + // For example: `[["Set-Cookie", ""], ["Set-Cookie", ""]]`. + // +optional + Headers [][]string `json:"headers,omitempty"` +} + +// PodHttpChaosReplaceBody defines the replace-body of HttpChaos. +type PodHttpChaosReplaceBody struct { + Contents PodHttpChaosBodyReplaceContent `json:"contents"` +} + +type PodHttpChaosBodyReplaceContent struct { + // Type represents the patch type, only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) currently. + Type string `json:"type"` + + // Value is the patch contents. + Value string `json:"value"` +} + +func (p *PodHttpChaosReplaceBody) UnmarshalJSON(data []byte) error { + var pp PodHttpChaosBodyReplaceContent + err := json.Unmarshal(data, &pp) + if err == nil { + p.Contents = pp + return nil + } + var bys []byte + + err = json.Unmarshal(data, &bys) + if err == nil { + p.Contents = PodHttpChaosBodyReplaceContent{ + Type: "TEXT", + Value: string(bys), + } + return nil + } + return err +} + +// PodHttpChaosReplaceActions defines possible replace-actions of HttpChaos. +type PodHttpChaosReplaceActions struct { + // Path is rule to to replace uri path in http request. + // +optional + Path *string `json:"path,omitempty"` + + // Method is a rule to replace http method in request. + // +optional + Method *string `json:"method,omitempty"` + + // Code is a rule to replace http status code in response. + // +optional + Code *int32 `json:"code,omitempty"` + + // Body is a rule to replace http message body in target. + // +optional + Body *PodHttpChaosReplaceBody `json:"body,omitempty"` + + // Queries is a rule to replace uri queries in http request. + // For example, with value `{ "foo": "unknown" }`, the `/?foo=bar` will be altered to `/?foo=unknown`, + // +optional + Queries map[string]string `json:"queries,omitempty"` + + // Headers is a rule to replace http headers of target. + // The key-value pairs represent header name and header value pairs. + // +optional + Headers map[string]string `json:"headers,omitempty"` +} + +// PodHttpChaosTarget represents the type of an HttpChaos Action +type PodHttpChaosTarget string diff --git a/pkg/chaosdaemon/types.go b/pkg/chaosdaemon/types.go index 7bee35ef47..d843d53434 100644 --- a/pkg/chaosdaemon/types.go +++ b/pkg/chaosdaemon/types.go @@ -1,15 +1,17 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package chaosdaemon diff --git a/pkg/chaosdaemon/util.go b/pkg/chaosdaemon/util.go deleted file mode 100755 index 63b1dc52ea..0000000000 --- a/pkg/chaosdaemon/util.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package chaosdaemon - -import ( - "fmt" - "io/ioutil" - "os" - "strconv" - "sync" - - "github.com/chaos-mesh/chaos-mesh/pkg/bpm" -) - -// ReadCommName returns the command name of process -func ReadCommName(pid int) (string, error) { - f, err := os.Open(fmt.Sprintf("%s/%d/comm", bpm.DefaultProcPrefix, pid)) - if err != nil { - return "", err - } - defer f.Close() - - b, err := ioutil.ReadAll(f) - if err != nil { - return "", err - } - - return string(b), nil -} - -// GetChildProcesses will return all child processes's pid. Include all generations. -// only return error when /proc/pid/tasks cannot be read -func GetChildProcesses(ppid uint32) ([]uint32, error) { - procs, err := ioutil.ReadDir(bpm.DefaultProcPrefix) - if err != nil { - return nil, err - } - - type processPair struct { - Pid uint32 - Ppid uint32 - } - - pairs := make(chan processPair) - done := make(chan bool) - - go func() { - var wg sync.WaitGroup - - for _, proc := range procs { - _, err := strconv.ParseUint(proc.Name(), 10, 32) - if err != nil { - continue - } - - statusPath := bpm.DefaultProcPrefix + "/" + proc.Name() + "/stat" - - wg.Add(1) - go func() { - defer wg.Done() - - reader, err := os.Open(statusPath) - if err != nil { - log.Error(err, "read status file error", "path", statusPath) - return - } - defer reader.Close() - - var ( - pid uint32 - comm string - state string - parent uint32 - ) - // according to procfs's man page - fmt.Fscanf(reader, "%d %s %s %d", &pid, &comm, &state, &parent) - - pairs <- processPair{ - Pid: pid, - Ppid: parent, - } - }() - } - - wg.Wait() - done <- true - }() - - processGraph := NewGraph() - for { - select { - case pair := <-pairs: - processGraph.Insert(pair.Ppid, pair.Pid) - case <-done: - return processGraph.Flatten(ppid), nil - } - } -} - -func encodeOutputToError(output []byte, err error) error { - return fmt.Errorf("error code: %v, msg: %s", err, string(output)) -} diff --git a/pkg/chaosdaemon/util/util.go b/pkg/chaosdaemon/util/util.go new file mode 100755 index 0000000000..0a0b5eef52 --- /dev/null +++ b/pkg/chaosdaemon/util/util.go @@ -0,0 +1,119 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package util + +import ( + "fmt" + "io" + "os" + "strconv" + "sync" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/pkg/bpm" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/graph" +) + +// ReadCommName returns the command name of process +func ReadCommName(pid int) (string, error) { + f, err := os.Open(fmt.Sprintf("%s/%d/comm", bpm.DefaultProcPrefix, pid)) + if err != nil { + return "", err + } + defer f.Close() + + b, err := io.ReadAll(f) + if err != nil { + return "", err + } + + return string(b), nil +} + +// GetChildProcesses will return all child processes's pid. Include all generations. +// Only return error when `/proc` cannot be read. +func GetChildProcesses(ppid uint32, logger logr.Logger) ([]uint32, error) { + procs, err := os.ReadDir(bpm.DefaultProcPrefix) + if err != nil { + return nil, errors.Wrapf(err, "read /proc") + } + + type processPair struct { + Pid uint32 + Ppid uint32 + } + + pairs := make(chan processPair) + done := make(chan bool) + + go func() { + var wg sync.WaitGroup + + for _, proc := range procs { + _, err := strconv.ParseUint(proc.Name(), 10, 32) + if err != nil { + continue + } + + statusPath := bpm.DefaultProcPrefix + "/" + proc.Name() + "/stat" + + wg.Add(1) + go func() { + defer wg.Done() + + reader, err := os.Open(statusPath) + if err != nil { + logger.Error(err, "read status file error", "path", statusPath) + return + } + defer reader.Close() + + var ( + pid uint32 + comm string + state string + parent uint32 + ) + // according to procfs's man page + fmt.Fscanf(reader, "%d %s %s %d", &pid, &comm, &state, &parent) + + pairs <- processPair{ + Pid: pid, + Ppid: parent, + } + }() + } + + wg.Wait() + done <- true + }() + + processGraph := graph.NewGraph() + for { + select { + case pair := <-pairs: + processGraph.Insert(pair.Ppid, pair.Pid) + case <-done: + return processGraph.Flatten(ppid, logger), nil + } + } +} + +func EncodeOutputToError(output []byte, err error) error { + return errors.Errorf("error code: %v, msg: %s", err, string(output)) +} diff --git a/pkg/chaoskernel/pb/bpfki.pb.go b/pkg/chaoskernel/pb/bpfki.pb.go index 55938fa1e8..a1433a5076 100644 --- a/pkg/chaoskernel/pb/bpfki.pb.go +++ b/pkg/chaoskernel/pb/bpfki.pb.go @@ -1,29 +1,34 @@ // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.12.1 // source: bpfki.proto package bpfki import ( context "context" - fmt "fmt" - math "math" + reflect "reflect" + sync "sync" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 type FailKernRequest_FAILTYPE int32 @@ -33,412 +38,648 @@ const ( FailKernRequest_BIO FailKernRequest_FAILTYPE = 2 ) -var FailKernRequest_FAILTYPE_name = map[int32]string{ - 0: "SLAB", - 1: "PAGE", - 2: "BIO", -} +// Enum value maps for FailKernRequest_FAILTYPE. +var ( + FailKernRequest_FAILTYPE_name = map[int32]string{ + 0: "SLAB", + 1: "PAGE", + 2: "BIO", + } + FailKernRequest_FAILTYPE_value = map[string]int32{ + "SLAB": 0, + "PAGE": 1, + "BIO": 2, + } +) -var FailKernRequest_FAILTYPE_value = map[string]int32{ - "SLAB": 0, - "PAGE": 1, - "BIO": 2, +func (x FailKernRequest_FAILTYPE) Enum() *FailKernRequest_FAILTYPE { + p := new(FailKernRequest_FAILTYPE) + *p = x + return p } func (x FailKernRequest_FAILTYPE) String() string { - return proto.EnumName(FailKernRequest_FAILTYPE_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (FailKernRequest_FAILTYPE) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_62eed357eb71de0e, []int{1, 0} +func (FailKernRequest_FAILTYPE) Descriptor() protoreflect.EnumDescriptor { + return file_bpfki_proto_enumTypes[0].Descriptor() } -type BumpTimeRequest struct { - Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` - Tid uint32 `protobuf:"varint,2,opt,name=tid,proto3" json:"tid,omitempty"` - Second int32 `protobuf:"varint,3,opt,name=second,proto3" json:"second,omitempty"` - Subsecond int32 `protobuf:"varint,4,opt,name=subsecond,proto3" json:"subsecond,omitempty"` - Probability float32 `protobuf:"fixed32,5,opt,name=probability,proto3" json:"probability,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *BumpTimeRequest) Reset() { *m = BumpTimeRequest{} } -func (m *BumpTimeRequest) String() string { return proto.CompactTextString(m) } -func (*BumpTimeRequest) ProtoMessage() {} -func (*BumpTimeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_62eed357eb71de0e, []int{0} +func (FailKernRequest_FAILTYPE) Type() protoreflect.EnumType { + return &file_bpfki_proto_enumTypes[0] +} + +func (x FailKernRequest_FAILTYPE) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) } -func (m *BumpTimeRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_BumpTimeRequest.Unmarshal(m, b) +// Deprecated: Use FailKernRequest_FAILTYPE.Descriptor instead. +func (FailKernRequest_FAILTYPE) EnumDescriptor() ([]byte, []int) { + return file_bpfki_proto_rawDescGZIP(), []int{1, 0} } -func (m *BumpTimeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_BumpTimeRequest.Marshal(b, m, deterministic) + +type BumpTimeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` + Tid uint32 `protobuf:"varint,2,opt,name=tid,proto3" json:"tid,omitempty"` + Second int32 `protobuf:"varint,3,opt,name=second,proto3" json:"second,omitempty"` + Subsecond int32 `protobuf:"varint,4,opt,name=subsecond,proto3" json:"subsecond,omitempty"` + Probability float32 `protobuf:"fixed32,5,opt,name=probability,proto3" json:"probability,omitempty"` } -func (m *BumpTimeRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_BumpTimeRequest.Merge(m, src) + +func (x *BumpTimeRequest) Reset() { + *x = BumpTimeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_bpfki_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *BumpTimeRequest) XXX_Size() int { - return xxx_messageInfo_BumpTimeRequest.Size(m) + +func (x *BumpTimeRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *BumpTimeRequest) XXX_DiscardUnknown() { - xxx_messageInfo_BumpTimeRequest.DiscardUnknown(m) + +func (*BumpTimeRequest) ProtoMessage() {} + +func (x *BumpTimeRequest) ProtoReflect() protoreflect.Message { + mi := &file_bpfki_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_BumpTimeRequest proto.InternalMessageInfo +// Deprecated: Use BumpTimeRequest.ProtoReflect.Descriptor instead. +func (*BumpTimeRequest) Descriptor() ([]byte, []int) { + return file_bpfki_proto_rawDescGZIP(), []int{0} +} -func (m *BumpTimeRequest) GetPid() uint32 { - if m != nil { - return m.Pid +func (x *BumpTimeRequest) GetPid() uint32 { + if x != nil { + return x.Pid } return 0 } -func (m *BumpTimeRequest) GetTid() uint32 { - if m != nil { - return m.Tid +func (x *BumpTimeRequest) GetTid() uint32 { + if x != nil { + return x.Tid } return 0 } -func (m *BumpTimeRequest) GetSecond() int32 { - if m != nil { - return m.Second +func (x *BumpTimeRequest) GetSecond() int32 { + if x != nil { + return x.Second } return 0 } -func (m *BumpTimeRequest) GetSubsecond() int32 { - if m != nil { - return m.Subsecond +func (x *BumpTimeRequest) GetSubsecond() int32 { + if x != nil { + return x.Subsecond } return 0 } -func (m *BumpTimeRequest) GetProbability() float32 { - if m != nil { - return m.Probability +func (x *BumpTimeRequest) GetProbability() float32 { + if x != nil { + return x.Probability } return 0 } type FailKernRequest struct { - Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` - Tid uint32 `protobuf:"varint,2,opt,name=tid,proto3" json:"tid,omitempty"` - Ftype FailKernRequest_FAILTYPE `protobuf:"varint,3,opt,name=ftype,proto3,enum=bpfki.FailKernRequest_FAILTYPE" json:"ftype,omitempty"` - Headers []string `protobuf:"bytes,4,rep,name=headers,proto3" json:"headers,omitempty"` - Callchain []*FailKernRequestFrame `protobuf:"bytes,5,rep,name=callchain,proto3" json:"callchain,omitempty"` - Probability float32 `protobuf:"fixed32,6,opt,name=probability,proto3" json:"probability,omitempty"` - Times uint32 `protobuf:"varint,7,opt,name=times,proto3" json:"times,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FailKernRequest) Reset() { *m = FailKernRequest{} } -func (m *FailKernRequest) String() string { return proto.CompactTextString(m) } -func (*FailKernRequest) ProtoMessage() {} -func (*FailKernRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_62eed357eb71de0e, []int{1} -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *FailKernRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FailKernRequest.Unmarshal(m, b) + Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` + Tid uint32 `protobuf:"varint,2,opt,name=tid,proto3" json:"tid,omitempty"` + Ftype FailKernRequest_FAILTYPE `protobuf:"varint,3,opt,name=ftype,proto3,enum=bpfki.FailKernRequest_FAILTYPE" json:"ftype,omitempty"` + Headers []string `protobuf:"bytes,4,rep,name=headers,proto3" json:"headers,omitempty"` + Callchain []*FailKernRequestFrame `protobuf:"bytes,5,rep,name=callchain,proto3" json:"callchain,omitempty"` + Probability float32 `protobuf:"fixed32,6,opt,name=probability,proto3" json:"probability,omitempty"` + Times uint32 `protobuf:"varint,7,opt,name=times,proto3" json:"times,omitempty"` } -func (m *FailKernRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FailKernRequest.Marshal(b, m, deterministic) -} -func (m *FailKernRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_FailKernRequest.Merge(m, src) + +func (x *FailKernRequest) Reset() { + *x = FailKernRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_bpfki_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *FailKernRequest) XXX_Size() int { - return xxx_messageInfo_FailKernRequest.Size(m) + +func (x *FailKernRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *FailKernRequest) XXX_DiscardUnknown() { - xxx_messageInfo_FailKernRequest.DiscardUnknown(m) + +func (*FailKernRequest) ProtoMessage() {} + +func (x *FailKernRequest) ProtoReflect() protoreflect.Message { + mi := &file_bpfki_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_FailKernRequest proto.InternalMessageInfo +// Deprecated: Use FailKernRequest.ProtoReflect.Descriptor instead. +func (*FailKernRequest) Descriptor() ([]byte, []int) { + return file_bpfki_proto_rawDescGZIP(), []int{1} +} -func (m *FailKernRequest) GetPid() uint32 { - if m != nil { - return m.Pid +func (x *FailKernRequest) GetPid() uint32 { + if x != nil { + return x.Pid } return 0 } -func (m *FailKernRequest) GetTid() uint32 { - if m != nil { - return m.Tid +func (x *FailKernRequest) GetTid() uint32 { + if x != nil { + return x.Tid } return 0 } -func (m *FailKernRequest) GetFtype() FailKernRequest_FAILTYPE { - if m != nil { - return m.Ftype +func (x *FailKernRequest) GetFtype() FailKernRequest_FAILTYPE { + if x != nil { + return x.Ftype } return FailKernRequest_SLAB } -func (m *FailKernRequest) GetHeaders() []string { - if m != nil { - return m.Headers +func (x *FailKernRequest) GetHeaders() []string { + if x != nil { + return x.Headers } return nil } -func (m *FailKernRequest) GetCallchain() []*FailKernRequestFrame { - if m != nil { - return m.Callchain +func (x *FailKernRequest) GetCallchain() []*FailKernRequestFrame { + if x != nil { + return x.Callchain } return nil } -func (m *FailKernRequest) GetProbability() float32 { - if m != nil { - return m.Probability +func (x *FailKernRequest) GetProbability() float32 { + if x != nil { + return x.Probability } return 0 } -func (m *FailKernRequest) GetTimes() uint32 { - if m != nil { - return m.Times +func (x *FailKernRequest) GetTimes() uint32 { + if x != nil { + return x.Times } return 0 } -type FailKernRequestFrame struct { - Funcname string `protobuf:"bytes,1,opt,name=funcname,proto3" json:"funcname,omitempty"` - Parameters string `protobuf:"bytes,2,opt,name=parameters,proto3" json:"parameters,omitempty"` - Predicate string `protobuf:"bytes,3,opt,name=predicate,proto3" json:"predicate,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FailKernRequestFrame) Reset() { *m = FailKernRequestFrame{} } -func (m *FailKernRequestFrame) String() string { return proto.CompactTextString(m) } -func (*FailKernRequestFrame) ProtoMessage() {} -func (*FailKernRequestFrame) Descriptor() ([]byte, []int) { - return fileDescriptor_62eed357eb71de0e, []int{1, 0} -} +type FailSyscallRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *FailKernRequestFrame) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FailKernRequestFrame.Unmarshal(m, b) + Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` + Tid uint32 `protobuf:"varint,2,opt,name=tid,proto3" json:"tid,omitempty"` + Methods []string `protobuf:"bytes,3,rep,name=methods,proto3" json:"methods,omitempty"` + Err uint32 `protobuf:"varint,4,opt,name=err,proto3" json:"err,omitempty"` + Probability float32 `protobuf:"fixed32,5,opt,name=probability,proto3" json:"probability,omitempty"` } -func (m *FailKernRequestFrame) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FailKernRequestFrame.Marshal(b, m, deterministic) -} -func (m *FailKernRequestFrame) XXX_Merge(src proto.Message) { - xxx_messageInfo_FailKernRequestFrame.Merge(m, src) -} -func (m *FailKernRequestFrame) XXX_Size() int { - return xxx_messageInfo_FailKernRequestFrame.Size(m) -} -func (m *FailKernRequestFrame) XXX_DiscardUnknown() { - xxx_messageInfo_FailKernRequestFrame.DiscardUnknown(m) -} - -var xxx_messageInfo_FailKernRequestFrame proto.InternalMessageInfo -func (m *FailKernRequestFrame) GetFuncname() string { - if m != nil { - return m.Funcname +func (x *FailSyscallRequest) Reset() { + *x = FailSyscallRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_bpfki_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } - return "" } -func (m *FailKernRequestFrame) GetParameters() string { - if m != nil { - return m.Parameters - } - return "" +func (x *FailSyscallRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *FailKernRequestFrame) GetPredicate() string { - if m != nil { - return m.Predicate +func (*FailSyscallRequest) ProtoMessage() {} + +func (x *FailSyscallRequest) ProtoReflect() protoreflect.Message { + mi := &file_bpfki_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return "" + return mi.MessageOf(x) } -type FailSyscallRequest struct { - Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` - Tid uint32 `protobuf:"varint,2,opt,name=tid,proto3" json:"tid,omitempty"` - Methods []string `protobuf:"bytes,3,rep,name=methods,proto3" json:"methods,omitempty"` - Err uint32 `protobuf:"varint,4,opt,name=err,proto3" json:"err,omitempty"` - Probability float32 `protobuf:"fixed32,5,opt,name=probability,proto3" json:"probability,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FailSyscallRequest) Reset() { *m = FailSyscallRequest{} } -func (m *FailSyscallRequest) String() string { return proto.CompactTextString(m) } -func (*FailSyscallRequest) ProtoMessage() {} +// Deprecated: Use FailSyscallRequest.ProtoReflect.Descriptor instead. func (*FailSyscallRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_62eed357eb71de0e, []int{2} -} - -func (m *FailSyscallRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FailSyscallRequest.Unmarshal(m, b) -} -func (m *FailSyscallRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FailSyscallRequest.Marshal(b, m, deterministic) -} -func (m *FailSyscallRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_FailSyscallRequest.Merge(m, src) + return file_bpfki_proto_rawDescGZIP(), []int{2} } -func (m *FailSyscallRequest) XXX_Size() int { - return xxx_messageInfo_FailSyscallRequest.Size(m) -} -func (m *FailSyscallRequest) XXX_DiscardUnknown() { - xxx_messageInfo_FailSyscallRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_FailSyscallRequest proto.InternalMessageInfo -func (m *FailSyscallRequest) GetPid() uint32 { - if m != nil { - return m.Pid +func (x *FailSyscallRequest) GetPid() uint32 { + if x != nil { + return x.Pid } return 0 } -func (m *FailSyscallRequest) GetTid() uint32 { - if m != nil { - return m.Tid +func (x *FailSyscallRequest) GetTid() uint32 { + if x != nil { + return x.Tid } return 0 } -func (m *FailSyscallRequest) GetMethods() []string { - if m != nil { - return m.Methods +func (x *FailSyscallRequest) GetMethods() []string { + if x != nil { + return x.Methods } return nil } -func (m *FailSyscallRequest) GetErr() uint32 { - if m != nil { - return m.Err +func (x *FailSyscallRequest) GetErr() uint32 { + if x != nil { + return x.Err } return 0 } -func (m *FailSyscallRequest) GetProbability() float32 { - if m != nil { - return m.Probability +func (x *FailSyscallRequest) GetProbability() float32 { + if x != nil { + return x.Probability } return 0 } type StatusResponse struct { - Ret int32 `protobuf:"varint,1,opt,name=ret,proto3" json:"ret,omitempty"` - Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ret int32 `protobuf:"varint,1,opt,name=ret,proto3" json:"ret,omitempty"` + Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` +} + +func (x *StatusResponse) Reset() { + *x = StatusResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_bpfki_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StatusResponse) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *StatusResponse) Reset() { *m = StatusResponse{} } -func (m *StatusResponse) String() string { return proto.CompactTextString(m) } -func (*StatusResponse) ProtoMessage() {} +func (*StatusResponse) ProtoMessage() {} + +func (x *StatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_bpfki_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StatusResponse.ProtoReflect.Descriptor instead. func (*StatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_62eed357eb71de0e, []int{3} + return file_bpfki_proto_rawDescGZIP(), []int{3} +} + +func (x *StatusResponse) GetRet() int32 { + if x != nil { + return x.Ret + } + return 0 +} + +func (x *StatusResponse) GetMsg() string { + if x != nil { + return x.Msg + } + return "" } -func (m *StatusResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_StatusResponse.Unmarshal(m, b) +type FailKernRequestFrame struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Funcname string `protobuf:"bytes,1,opt,name=funcname,proto3" json:"funcname,omitempty"` + Parameters string `protobuf:"bytes,2,opt,name=parameters,proto3" json:"parameters,omitempty"` + Predicate string `protobuf:"bytes,3,opt,name=predicate,proto3" json:"predicate,omitempty"` } -func (m *StatusResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_StatusResponse.Marshal(b, m, deterministic) + +func (x *FailKernRequestFrame) Reset() { + *x = FailKernRequestFrame{} + if protoimpl.UnsafeEnabled { + mi := &file_bpfki_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *StatusResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_StatusResponse.Merge(m, src) + +func (x *FailKernRequestFrame) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *StatusResponse) XXX_Size() int { - return xxx_messageInfo_StatusResponse.Size(m) + +func (*FailKernRequestFrame) ProtoMessage() {} + +func (x *FailKernRequestFrame) ProtoReflect() protoreflect.Message { + mi := &file_bpfki_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -func (m *StatusResponse) XXX_DiscardUnknown() { - xxx_messageInfo_StatusResponse.DiscardUnknown(m) + +// Deprecated: Use FailKernRequestFrame.ProtoReflect.Descriptor instead. +func (*FailKernRequestFrame) Descriptor() ([]byte, []int) { + return file_bpfki_proto_rawDescGZIP(), []int{1, 0} } -var xxx_messageInfo_StatusResponse proto.InternalMessageInfo +func (x *FailKernRequestFrame) GetFuncname() string { + if x != nil { + return x.Funcname + } + return "" +} -func (m *StatusResponse) GetRet() int32 { - if m != nil { - return m.Ret +func (x *FailKernRequestFrame) GetParameters() string { + if x != nil { + return x.Parameters } - return 0 + return "" } -func (m *StatusResponse) GetMsg() string { - if m != nil { - return m.Msg +func (x *FailKernRequestFrame) GetPredicate() string { + if x != nil { + return x.Predicate } return "" } -func init() { - proto.RegisterEnum("bpfki.FailKernRequest_FAILTYPE", FailKernRequest_FAILTYPE_name, FailKernRequest_FAILTYPE_value) - proto.RegisterType((*BumpTimeRequest)(nil), "bpfki.BumpTimeRequest") - proto.RegisterType((*FailKernRequest)(nil), "bpfki.FailKernRequest") - proto.RegisterType((*FailKernRequestFrame)(nil), "bpfki.FailKernRequest.frame") - proto.RegisterType((*FailSyscallRequest)(nil), "bpfki.FailSyscallRequest") - proto.RegisterType((*StatusResponse)(nil), "bpfki.StatusResponse") -} - -func init() { proto.RegisterFile("bpfki.proto", fileDescriptor_62eed357eb71de0e) } - -var fileDescriptor_62eed357eb71de0e = []byte{ - // 518 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0x4d, 0x6f, 0xda, 0x40, - 0x10, 0x8d, 0x31, 0xe6, 0x63, 0xdc, 0x00, 0x5a, 0xb5, 0x91, 0x8b, 0xa2, 0xd6, 0xe2, 0x52, 0x4e, - 0x1c, 0x68, 0x7b, 0xa9, 0xd4, 0x48, 0x58, 0x0d, 0x15, 0x4a, 0x22, 0xd0, 0x3a, 0xaa, 0xd4, 0xe3, - 0x62, 0x0f, 0x65, 0x55, 0xfc, 0xd1, 0xdd, 0x25, 0x12, 0x7f, 0x20, 0xb7, 0xfe, 0x87, 0xfe, 0xd4, - 0x6a, 0x6d, 0x07, 0x1c, 0xa2, 0x48, 0x21, 0xb9, 0xcd, 0xbc, 0xdd, 0x7d, 0x7e, 0x6f, 0xe6, 0xc9, - 0x60, 0xcf, 0xd3, 0xc5, 0x6f, 0x3e, 0x48, 0x45, 0xa2, 0x12, 0x62, 0x65, 0x4d, 0xef, 0xaf, 0x01, - 0x6d, 0x6f, 0x1d, 0xa5, 0xd7, 0x3c, 0x42, 0x8a, 0x7f, 0xd6, 0x28, 0x15, 0xe9, 0x80, 0x99, 0xf2, - 0xd0, 0x31, 0x5c, 0xa3, 0x7f, 0x4c, 0x75, 0xa9, 0x11, 0xc5, 0x43, 0xa7, 0x92, 0x23, 0x8a, 0x87, - 0xe4, 0x04, 0x6a, 0x12, 0x83, 0x24, 0x0e, 0x1d, 0xd3, 0x35, 0xfa, 0x16, 0x2d, 0x3a, 0x72, 0x0a, - 0x4d, 0xb9, 0x9e, 0x17, 0x47, 0xd5, 0xec, 0x68, 0x07, 0x10, 0x17, 0xec, 0x54, 0x24, 0x73, 0x36, - 0xe7, 0x2b, 0xae, 0x36, 0x8e, 0xe5, 0x1a, 0xfd, 0x0a, 0x2d, 0x43, 0xbd, 0x5b, 0x13, 0xda, 0x63, - 0xc6, 0x57, 0x17, 0x28, 0xe2, 0x43, 0xf4, 0x7c, 0x06, 0x6b, 0xa1, 0x36, 0x29, 0x66, 0x72, 0x5a, - 0xc3, 0xf7, 0x83, 0xdc, 0xeb, 0x1e, 0xd5, 0x60, 0x3c, 0x9a, 0x5c, 0x5e, 0xff, 0x9c, 0x9d, 0xd3, - 0xfc, 0x36, 0x71, 0xa0, 0xbe, 0x44, 0x16, 0xa2, 0x90, 0x4e, 0xd5, 0x35, 0xfb, 0x4d, 0x7a, 0xd7, - 0x92, 0x2f, 0xd0, 0x0c, 0xd8, 0x6a, 0x15, 0x2c, 0x19, 0x8f, 0x1d, 0xcb, 0x35, 0xfb, 0xf6, 0xf0, - 0xf4, 0x11, 0xd2, 0x85, 0x60, 0x11, 0xd2, 0xdd, 0xf5, 0x7d, 0x9b, 0xb5, 0x07, 0x36, 0xc9, 0x6b, - 0xb0, 0x14, 0x8f, 0x50, 0x3a, 0xf5, 0xcc, 0x42, 0xde, 0x74, 0x19, 0x58, 0x19, 0x17, 0xe9, 0x42, - 0x63, 0xb1, 0x8e, 0x83, 0x98, 0x45, 0x98, 0xd9, 0x6e, 0xd2, 0x6d, 0x4f, 0xde, 0x01, 0xa4, 0x4c, - 0xdf, 0x52, 0x5a, 0x75, 0x25, 0x3b, 0x2d, 0x21, 0x7a, 0x03, 0xa9, 0xc0, 0x90, 0x07, 0x4c, 0xe5, - 0xd3, 0x68, 0xd2, 0x1d, 0xd0, 0xfb, 0x00, 0x8d, 0xbb, 0x19, 0x90, 0x06, 0x54, 0xfd, 0xcb, 0x91, - 0xd7, 0x39, 0xd2, 0xd5, 0x6c, 0xf4, 0xfd, 0xbc, 0x63, 0x90, 0x3a, 0x98, 0xde, 0x64, 0xda, 0xa9, - 0xf4, 0x6e, 0x0d, 0x20, 0xda, 0xa8, 0xbf, 0x91, 0xda, 0xd8, 0x21, 0xbb, 0x70, 0xa0, 0x1e, 0xa1, - 0x5a, 0x26, 0xa1, 0x74, 0xcc, 0x7c, 0xa8, 0x45, 0xab, 0xef, 0xa2, 0x10, 0x59, 0x2e, 0x8e, 0xa9, - 0x2e, 0x9f, 0x90, 0x88, 0x4f, 0xd0, 0xf2, 0x15, 0x53, 0x6b, 0x49, 0x51, 0xa6, 0x49, 0x2c, 0x51, - 0xb3, 0x08, 0x54, 0x99, 0x06, 0x8b, 0xea, 0x52, 0x23, 0x91, 0xfc, 0x55, 0x0c, 0x43, 0x97, 0xc3, - 0x7f, 0x55, 0x78, 0xe5, 0xcd, 0xc6, 0x17, 0x13, 0x1f, 0xc5, 0x0d, 0x0f, 0x90, 0x7c, 0x05, 0xf0, - 0x51, 0xe9, 0x98, 0xff, 0x60, 0x2b, 0x72, 0x52, 0xac, 0x72, 0x2f, 0xfa, 0xdd, 0x37, 0x05, 0x7e, - 0xff, 0x8b, 0xbd, 0x23, 0x32, 0x82, 0x16, 0xc5, 0x20, 0xb9, 0x41, 0xf1, 0x6c, 0x8a, 0x33, 0xb0, - 0x0b, 0x05, 0x7e, 0x8a, 0xc1, 0xe1, 0xef, 0x3d, 0x68, 0x97, 0x24, 0x3c, 0x8f, 0xe3, 0x0c, 0x6c, - 0xbd, 0xd4, 0xab, 0xab, 0xa9, 0xf0, 0x26, 0xd3, 0xed, 0xfb, 0xbd, 0x44, 0x3f, 0x65, 0x0c, 0x2f, - 0xa0, 0xb0, 0x4b, 0xb9, 0x22, 0x6f, 0x4b, 0xef, 0xef, 0x67, 0xed, 0x71, 0x8a, 0x6f, 0x5b, 0x15, - 0x2f, 0x60, 0x99, 0xd7, 0xb2, 0x1f, 0xe1, 0xc7, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x91, 0xa8, - 0xf4, 0xbf, 0x17, 0x05, 0x00, 0x00, +var File_bpfki_proto protoreflect.FileDescriptor + +var file_bpfki_proto_rawDesc = []byte{ + 0x0a, 0x0b, 0x62, 0x70, 0x66, 0x6b, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x62, + 0x70, 0x66, 0x6b, 0x69, 0x22, 0x8d, 0x01, 0x0a, 0x0f, 0x42, 0x75, 0x6d, 0x70, 0x54, 0x69, 0x6d, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x74, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, + 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, + 0x63, 0x6f, 0x6e, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x73, 0x65, 0x63, 0x6f, 0x6e, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x75, 0x62, 0x73, 0x65, 0x63, 0x6f, + 0x6e, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x62, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x62, 0x61, 0x62, 0x69, + 0x6c, 0x69, 0x74, 0x79, 0x22, 0x86, 0x03, 0x0a, 0x0f, 0x46, 0x61, 0x69, 0x6c, 0x4b, 0x65, 0x72, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x74, 0x69, 0x64, 0x12, 0x35, 0x0a, 0x05, + 0x66, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x62, 0x70, + 0x66, 0x6b, 0x69, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x4b, 0x65, 0x72, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x2e, 0x46, 0x41, 0x49, 0x4c, 0x54, 0x59, 0x50, 0x45, 0x52, 0x05, 0x66, 0x74, + 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x3a, 0x0a, + 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x62, 0x70, 0x66, 0x6b, 0x69, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x4b, 0x65, 0x72, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x09, + 0x63, 0x61, 0x6c, 0x6c, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x72, 0x6f, + 0x62, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0b, + 0x70, 0x72, 0x6f, 0x62, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x1a, 0x61, 0x0a, 0x05, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x75, + 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x75, + 0x6e, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x65, 0x64, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x65, 0x64, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x22, 0x27, 0x0a, 0x08, 0x46, 0x41, 0x49, 0x4c, 0x54, 0x59, 0x50, 0x45, + 0x12, 0x08, 0x0a, 0x04, 0x53, 0x4c, 0x41, 0x42, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x41, + 0x47, 0x45, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x42, 0x49, 0x4f, 0x10, 0x02, 0x22, 0x86, 0x01, + 0x0a, 0x12, 0x46, 0x61, 0x69, 0x6c, 0x53, 0x79, 0x73, 0x63, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x03, 0x74, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x68, + 0x6f, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x03, 0x65, 0x72, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x62, 0x61, 0x62, 0x69, 0x6c, + 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x62, 0x61, + 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x22, 0x34, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x72, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, + 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x32, 0xa0, 0x04, 0x0a, + 0x0c, 0x42, 0x50, 0x46, 0x4b, 0x49, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3d, 0x0a, + 0x0a, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x56, 0x61, 0x6c, 0x12, 0x16, 0x2e, 0x62, 0x70, + 0x66, 0x6b, 0x69, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x62, 0x70, 0x66, 0x6b, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0e, + 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x56, 0x61, 0x6c, 0x12, 0x16, + 0x2e, 0x62, 0x70, 0x66, 0x6b, 0x69, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x54, 0x69, 0x6d, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x62, 0x70, 0x66, 0x6b, 0x69, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x3e, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12, 0x16, + 0x2e, 0x62, 0x70, 0x66, 0x6b, 0x69, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x54, 0x69, 0x6d, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x62, 0x70, 0x66, 0x6b, 0x69, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x42, 0x0a, 0x0f, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x70, + 0x65, 0x63, 0x12, 0x16, 0x2e, 0x62, 0x70, 0x66, 0x6b, 0x69, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x54, + 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x62, 0x70, 0x66, + 0x6b, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x0b, 0x46, 0x61, 0x69, 0x6c, 0x4d, 0x4d, 0x4f, 0x72, 0x42, + 0x49, 0x4f, 0x12, 0x16, 0x2e, 0x62, 0x70, 0x66, 0x6b, 0x69, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x4b, + 0x65, 0x72, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x62, 0x70, 0x66, + 0x6b, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x4d, 0x4d, + 0x4f, 0x72, 0x42, 0x49, 0x4f, 0x12, 0x16, 0x2e, 0x62, 0x70, 0x66, 0x6b, 0x69, 0x2e, 0x46, 0x61, + 0x69, 0x6c, 0x4b, 0x65, 0x72, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, + 0x62, 0x70, 0x66, 0x6b, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0b, 0x46, 0x61, 0x69, 0x6c, 0x53, 0x79, + 0x73, 0x63, 0x61, 0x6c, 0x6c, 0x12, 0x19, 0x2e, 0x62, 0x70, 0x66, 0x6b, 0x69, 0x2e, 0x46, 0x61, + 0x69, 0x6c, 0x53, 0x79, 0x73, 0x63, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x15, 0x2e, 0x62, 0x70, 0x66, 0x6b, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0e, 0x52, 0x65, 0x63, + 0x6f, 0x76, 0x65, 0x72, 0x53, 0x79, 0x73, 0x63, 0x61, 0x6c, 0x6c, 0x12, 0x19, 0x2e, 0x62, 0x70, + 0x66, 0x6b, 0x69, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x53, 0x79, 0x73, 0x63, 0x61, 0x6c, 0x6c, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x62, 0x70, 0x66, 0x6b, 0x69, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_bpfki_proto_rawDescOnce sync.Once + file_bpfki_proto_rawDescData = file_bpfki_proto_rawDesc +) + +func file_bpfki_proto_rawDescGZIP() []byte { + file_bpfki_proto_rawDescOnce.Do(func() { + file_bpfki_proto_rawDescData = protoimpl.X.CompressGZIP(file_bpfki_proto_rawDescData) + }) + return file_bpfki_proto_rawDescData +} + +var file_bpfki_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_bpfki_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_bpfki_proto_goTypes = []interface{}{ + (FailKernRequest_FAILTYPE)(0), // 0: bpfki.FailKernRequest.FAILTYPE + (*BumpTimeRequest)(nil), // 1: bpfki.BumpTimeRequest + (*FailKernRequest)(nil), // 2: bpfki.FailKernRequest + (*FailSyscallRequest)(nil), // 3: bpfki.FailSyscallRequest + (*StatusResponse)(nil), // 4: bpfki.StatusResponse + (*FailKernRequestFrame)(nil), // 5: bpfki.FailKernRequest.frame +} +var file_bpfki_proto_depIdxs = []int32{ + 0, // 0: bpfki.FailKernRequest.ftype:type_name -> bpfki.FailKernRequest.FAILTYPE + 5, // 1: bpfki.FailKernRequest.callchain:type_name -> bpfki.FailKernRequest.frame + 1, // 2: bpfki.BPFKIService.SetTimeVal:input_type -> bpfki.BumpTimeRequest + 1, // 3: bpfki.BPFKIService.RecoverTimeVal:input_type -> bpfki.BumpTimeRequest + 1, // 4: bpfki.BPFKIService.SetTimeSpec:input_type -> bpfki.BumpTimeRequest + 1, // 5: bpfki.BPFKIService.RecoverTimeSpec:input_type -> bpfki.BumpTimeRequest + 2, // 6: bpfki.BPFKIService.FailMMOrBIO:input_type -> bpfki.FailKernRequest + 2, // 7: bpfki.BPFKIService.RecoverMMOrBIO:input_type -> bpfki.FailKernRequest + 3, // 8: bpfki.BPFKIService.FailSyscall:input_type -> bpfki.FailSyscallRequest + 3, // 9: bpfki.BPFKIService.RecoverSyscall:input_type -> bpfki.FailSyscallRequest + 4, // 10: bpfki.BPFKIService.SetTimeVal:output_type -> bpfki.StatusResponse + 4, // 11: bpfki.BPFKIService.RecoverTimeVal:output_type -> bpfki.StatusResponse + 4, // 12: bpfki.BPFKIService.SetTimeSpec:output_type -> bpfki.StatusResponse + 4, // 13: bpfki.BPFKIService.RecoverTimeSpec:output_type -> bpfki.StatusResponse + 4, // 14: bpfki.BPFKIService.FailMMOrBIO:output_type -> bpfki.StatusResponse + 4, // 15: bpfki.BPFKIService.RecoverMMOrBIO:output_type -> bpfki.StatusResponse + 4, // 16: bpfki.BPFKIService.FailSyscall:output_type -> bpfki.StatusResponse + 4, // 17: bpfki.BPFKIService.RecoverSyscall:output_type -> bpfki.StatusResponse + 10, // [10:18] is the sub-list for method output_type + 2, // [2:10] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_bpfki_proto_init() } +func file_bpfki_proto_init() { + if File_bpfki_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_bpfki_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BumpTimeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bpfki_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FailKernRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bpfki_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FailSyscallRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bpfki_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StatusResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bpfki_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FailKernRequestFrame); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_bpfki_proto_rawDesc, + NumEnums: 1, + NumMessages: 5, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_bpfki_proto_goTypes, + DependencyIndexes: file_bpfki_proto_depIdxs, + EnumInfos: file_bpfki_proto_enumTypes, + MessageInfos: file_bpfki_proto_msgTypes, + }.Build() + File_bpfki_proto = out.File + file_bpfki_proto_rawDesc = nil + file_bpfki_proto_goTypes = nil + file_bpfki_proto_depIdxs = nil } // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConn +var _ grpc.ClientConnInterface // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 +const _ = grpc.SupportPackageIsVersion6 // BPFKIServiceClient is the client API for BPFKIService service. // @@ -455,10 +696,10 @@ type BPFKIServiceClient interface { } type bPFKIServiceClient struct { - cc *grpc.ClientConn + cc grpc.ClientConnInterface } -func NewBPFKIServiceClient(cc *grpc.ClientConn) BPFKIServiceClient { +func NewBPFKIServiceClient(cc grpc.ClientConnInterface) BPFKIServiceClient { return &bPFKIServiceClient{cc} } @@ -550,28 +791,28 @@ type BPFKIServiceServer interface { type UnimplementedBPFKIServiceServer struct { } -func (*UnimplementedBPFKIServiceServer) SetTimeVal(ctx context.Context, req *BumpTimeRequest) (*StatusResponse, error) { +func (*UnimplementedBPFKIServiceServer) SetTimeVal(context.Context, *BumpTimeRequest) (*StatusResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SetTimeVal not implemented") } -func (*UnimplementedBPFKIServiceServer) RecoverTimeVal(ctx context.Context, req *BumpTimeRequest) (*StatusResponse, error) { +func (*UnimplementedBPFKIServiceServer) RecoverTimeVal(context.Context, *BumpTimeRequest) (*StatusResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RecoverTimeVal not implemented") } -func (*UnimplementedBPFKIServiceServer) SetTimeSpec(ctx context.Context, req *BumpTimeRequest) (*StatusResponse, error) { +func (*UnimplementedBPFKIServiceServer) SetTimeSpec(context.Context, *BumpTimeRequest) (*StatusResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SetTimeSpec not implemented") } -func (*UnimplementedBPFKIServiceServer) RecoverTimeSpec(ctx context.Context, req *BumpTimeRequest) (*StatusResponse, error) { +func (*UnimplementedBPFKIServiceServer) RecoverTimeSpec(context.Context, *BumpTimeRequest) (*StatusResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RecoverTimeSpec not implemented") } -func (*UnimplementedBPFKIServiceServer) FailMMOrBIO(ctx context.Context, req *FailKernRequest) (*StatusResponse, error) { +func (*UnimplementedBPFKIServiceServer) FailMMOrBIO(context.Context, *FailKernRequest) (*StatusResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method FailMMOrBIO not implemented") } -func (*UnimplementedBPFKIServiceServer) RecoverMMOrBIO(ctx context.Context, req *FailKernRequest) (*StatusResponse, error) { +func (*UnimplementedBPFKIServiceServer) RecoverMMOrBIO(context.Context, *FailKernRequest) (*StatusResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RecoverMMOrBIO not implemented") } -func (*UnimplementedBPFKIServiceServer) FailSyscall(ctx context.Context, req *FailSyscallRequest) (*StatusResponse, error) { +func (*UnimplementedBPFKIServiceServer) FailSyscall(context.Context, *FailSyscallRequest) (*StatusResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method FailSyscall not implemented") } -func (*UnimplementedBPFKIServiceServer) RecoverSyscall(ctx context.Context, req *FailSyscallRequest) (*StatusResponse, error) { +func (*UnimplementedBPFKIServiceServer) RecoverSyscall(context.Context, *FailSyscallRequest) (*StatusResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RecoverSyscall not implemented") } diff --git a/pkg/clientpool/client.go b/pkg/clientpool/client.go index 13130354d9..9e654cb269 100644 --- a/pkg/clientpool/client.go +++ b/pkg/clientpool/client.go @@ -1,25 +1,27 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package clientpool import ( - "errors" "net/http" "strings" "sync" - lru "github.com/hashicorp/golang-lru" + lru "github.com/hashicorp/golang-lru/v2" + "github.com/pkg/errors" "k8s.io/apimachinery/pkg/runtime" authorizationv1 "k8s.io/client-go/kubernetes/typed/authorization/v1" "k8s.io/client-go/rest" @@ -87,18 +89,18 @@ type ClientsPool struct { scheme *runtime.Scheme localConfig *rest.Config - clients *lru.Cache - authClients *lru.Cache + clients *lru.Cache[string, pkgclient.Client] + authClients *lru.Cache[string, *authorizationv1.AuthorizationV1Client] } // New creates a new Clients func NewClientPool(localConfig *rest.Config, scheme *runtime.Scheme, maxClientNum int) (Clients, error) { - clients, err := lru.New(maxClientNum) + clients, err := lru.New[string, pkgclient.Client](maxClientNum) if err != nil { return nil, err } - authClients, err := lru.New(maxClientNum) + authClients, err := lru.New[string, *authorizationv1.AuthorizationV1Client](maxClientNum) if err != nil { return nil, err } @@ -122,7 +124,7 @@ func (c *ClientsPool) Client(token string) (pkgclient.Client, error) { value, ok := c.clients.Get(token) if ok { - return value.(pkgclient.Client), nil + return value, nil } config := rest.CopyConfig(c.localConfig) @@ -157,7 +159,7 @@ func (c *ClientsPool) AuthClient(token string) (authorizationv1.AuthorizationV1I value, ok := c.authClients.Get(token) if ok { - return value.(authorizationv1.AuthorizationV1Interface), nil + return value, nil } config := rest.CopyConfig(c.localConfig) diff --git a/pkg/clientpool/client_test.go b/pkg/clientpool/client_test.go index 6f227d5e16..2f278450fc 100644 --- a/pkg/clientpool/client_test.go +++ b/pkg/clientpool/client_test.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package clientpool diff --git a/pkg/collector/collector.go b/pkg/collector/collector.go deleted file mode 100644 index 2401c58596..0000000000 --- a/pkg/collector/collector.go +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package collector - -import ( - "context" - "encoding/json" - "errors" - "fmt" - - "github.com/go-logr/logr" - "github.com/jinzhu/gorm" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/core" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -// ChaosCollector represents a collector for Chaos Object. -type ChaosCollector struct { - client.Client - Log logr.Logger - apiType runtime.Object - archive core.ExperimentStore - event core.EventStore -} - -// Reconcile reconciles a chaos collector. -func (r *ChaosCollector) Reconcile(req ctrl.Request) (ctrl.Result, error) { - if r.apiType == nil { - r.Log.Error(nil, "apiType has not been initialized") - return ctrl.Result{}, nil - } - ctx := context.Background() - - obj, ok := r.apiType.DeepCopyObject().(v1alpha1.InnerObject) - if !ok { - r.Log.Error(nil, "it's not a stateful object") - return ctrl.Result{}, nil - } - - err := r.Get(ctx, req.NamespacedName, obj) - if apierrors.IsNotFound(err) { - if err = r.archiveExperiment(req.Namespace, req.Name); err != nil { - r.Log.Error(err, "failed to archive experiment") - } - return ctrl.Result{}, nil - } - - if err != nil { - r.Log.Error(err, "failed to get chaos object", "request", req.NamespacedName) - return ctrl.Result{}, nil - } - - if obj.IsDeleted() { - if err = r.archiveExperiment(req.Namespace, req.Name); err != nil { - r.Log.Error(err, "failed to archive experiment") - } - return ctrl.Result{}, nil - } - - if err := r.setUnarchivedExperiment(req, obj); err != nil { - r.Log.Error(err, "failed to archive experiment") - // ignore error here - } - - if err := r.recordEvent(req, obj); err != nil { - r.Log.Error(err, "failed to record event") - } - - return ctrl.Result{}, nil -} - -// Setup setups collectors by Manager. -func (r *ChaosCollector) Setup(mgr ctrl.Manager, apiType runtime.Object) error { - r.apiType = apiType - - return ctrl.NewControllerManagedBy(mgr). - For(apiType). - Complete(r) -} - -func (r *ChaosCollector) recordEvent(req ctrl.Request, obj v1alpha1.InnerObject) error { - var ( - chaosMeta metav1.Object - ok bool - ) - - if chaosMeta, ok = obj.(metav1.Object); !ok { - return errors.New("failed to get chaos meta information") - } - - UID := chaosMeta.GetUID() - status := obj.GetStatus() - kind := obj.GetObjectKind().GroupVersionKind().Kind - - switch status.Experiment.Phase { - case v1alpha1.ExperimentPhaseRunning: - return r.createEvent(req, kind, status, string(UID)) - case v1alpha1.ExperimentPhaseFinished, v1alpha1.ExperimentPhasePaused, v1alpha1.ExperimentPhaseWaiting: - return r.updateOrCreateEvent(req, kind, status, string(UID)) - } - - return nil -} - -func (r *ChaosCollector) createEvent(req ctrl.Request, kind string, status *v1alpha1.ChaosStatus, UID string) error { - if status.Experiment.StartTime == nil { - r.Log.Info("failed to create event, because experiment startTime is empty") - return fmt.Errorf("failed to create event, because experiment startTime is empty") - } - - event := &core.Event{ - Experiment: req.Name, - Namespace: req.Namespace, - Kind: kind, - StartTime: &status.Experiment.StartTime.Time, - ExperimentID: UID, - // TODO: add state for each event - Message: status.FailedMessage, - } - - if _, err := r.event.FindByExperimentAndStartTime( - context.Background(), event.Experiment, event.Namespace, event.StartTime); err == nil { - r.Log.Info("event has been created") - return nil - } - - for _, pod := range status.Experiment.PodRecords { - podRecord := &core.PodRecord{ - EventID: event.ID, - PodIP: pod.PodIP, - PodName: pod.Name, - Namespace: pod.Namespace, - Message: pod.Message, - Action: pod.Action, - } - event.Pods = append(event.Pods, podRecord) - } - if err := r.event.Create(context.Background(), event); err != nil { - r.Log.Error(err, "failed to store event", "event", event) - return err - } - - return nil -} - -func (r *ChaosCollector) updateOrCreateEvent(req ctrl.Request, kind string, status *v1alpha1.ChaosStatus, UID string) error { - if status.Experiment.StartTime == nil || status.Experiment.EndTime == nil { - return fmt.Errorf("failed to get experiment time, startTime or endTime is empty") - } - - event := &core.Event{ - Experiment: req.Name, - Namespace: req.Namespace, - Kind: kind, - StartTime: &status.Experiment.StartTime.Time, - FinishTime: &status.Experiment.EndTime.Time, - Duration: status.Experiment.Duration, - ExperimentID: UID, - } - - if _, err := r.event.FindByExperimentAndStartTime( - context.Background(), event.Experiment, event.Namespace, event.StartTime); err != nil && gorm.IsRecordNotFoundError(err) { - if err := r.createEvent(req, kind, status, UID); err != nil { - return err - } - } - - if err := r.event.Update(context.Background(), event); err != nil { - r.Log.Error(err, "failed to update event", "event", event) - return err - } - - return nil -} - -func (r *ChaosCollector) setUnarchivedExperiment(req ctrl.Request, obj v1alpha1.InnerObject) error { - var ( - chaosMeta metav1.Object - ok bool - ) - - if chaosMeta, ok = obj.(metav1.Object); !ok { - r.Log.Error(nil, "failed to get chaos meta information") - } - UID := string(chaosMeta.GetUID()) - - archive := &core.Experiment{ - ExperimentMeta: core.ExperimentMeta{ - Namespace: req.Namespace, - Name: req.Name, - Kind: obj.GetObjectKind().GroupVersionKind().Kind, - UID: UID, - Archived: false, - }, - } - - switch chaos := obj.(type) { - case *v1alpha1.PodChaos: - archive.Action = string(chaos.Spec.Action) - case *v1alpha1.NetworkChaos: - archive.Action = string(chaos.Spec.Action) - case *v1alpha1.IoChaos: - archive.Action = string(chaos.Spec.Action) - case *v1alpha1.TimeChaos, *v1alpha1.KernelChaos, *v1alpha1.StressChaos: - archive.Action = "" - case *v1alpha1.DNSChaos: - archive.Action = string(chaos.Spec.Action) - default: - return errors.New("unsupported chaos type " + archive.Kind) - } - - archive.StartTime = chaosMeta.GetCreationTimestamp().Time - if chaosMeta.GetDeletionTimestamp() != nil { - archive.FinishTime = chaosMeta.GetDeletionTimestamp().Time - } - - data, err := json.Marshal(chaosMeta) - if err != nil { - r.Log.Error(err, "failed to marshal chaos", "kind", archive.Kind, - "namespace", archive.Namespace, "name", archive.Name) - return err - } - - archive.Experiment = string(data) - - find, err := r.archive.FindByUID(context.Background(), UID) - if err != nil && !gorm.IsRecordNotFoundError(err) { - r.Log.Error(err, "failed to find experiment", "UID", UID) - return err - } - - if find != nil { - archive.ID = find.ID - archive.CreatedAt = find.CreatedAt - archive.UpdatedAt = find.UpdatedAt - } - - if err := r.archive.Set(context.Background(), archive); err != nil { - r.Log.Error(err, "failed to update experiment", "archive", archive) - return err - } - - return nil -} - -func (r *ChaosCollector) archiveExperiment(ns, name string) error { - if err := r.event.UpdateIncompleteEvents(context.Background(), ns, name); err != nil { - r.Log.Error(err, "failed to update incomplete events", "namespace", ns, "name", name) - return err - } - - if err := r.archive.Archive(context.Background(), ns, name); err != nil { - r.Log.Error(err, "failed to archive experiment", "namespace", ns, "name", name) - return err - } - - return nil -} diff --git a/pkg/collector/server.go b/pkg/collector/server.go deleted file mode 100644 index d0fa020cdf..0000000000 --- a/pkg/collector/server.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package collector - -import ( - "os" - - "k8s.io/apimachinery/pkg/runtime" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/clientpool" - "github.com/chaos-mesh/chaos-mesh/pkg/config" - "github.com/chaos-mesh/chaos-mesh/pkg/core" -) - -var ( - scheme = runtime.NewScheme() - log = ctrl.Log.WithName("collector") -) - -func init() { - _ = clientgoscheme.AddToScheme(scheme) - - _ = v1alpha1.AddToScheme(scheme) -} - -// Server defines a server to manage collectors. -type Server struct { - Manager ctrl.Manager -} - -// NewServer returns a CollectorServer and Client. -func NewServer( - conf *config.ChaosDashboardConfig, - archive core.ExperimentStore, - event core.EventStore, -) (*Server, client.Client, client.Reader, *runtime.Scheme) { - s := &Server{} - - // namespace scoped - options := ctrl.Options{ - Scheme: scheme, - MetricsBindAddress: conf.MetricAddress, - LeaderElection: conf.EnableLeaderElection, - Port: 9443, - } - if conf.ClusterScoped { - log.Info("Chaos controller manager is running in cluster scoped mode.") - } else { - log.Info("Chaos controller manager is running in namespace scoped mode.", "targetNamespace", conf.TargetNamespace) - options.Namespace = conf.TargetNamespace - } - - var err error - - cfg := ctrl.GetConfigOrDie() - s.Manager, err = ctrl.NewManager(cfg, options) - if err != nil { - log.Error(err, "unable to start collector") - os.Exit(1) - } - - if conf.SecurityMode { - clientpool.K8sClients, err = clientpool.NewClientPool(cfg, scheme, 100) - if err != nil { - // this should never happen - log.Error(err, "fail to create client pool") - os.Exit(1) - } - } else { - clientpool.K8sClients, err = clientpool.NewLocalClient(cfg, scheme) - if err != nil { - log.Error(err, "fail to create client pool") - os.Exit(1) - } - } - - for kind, chaosKind := range v1alpha1.AllKinds() { - if err = (&ChaosCollector{ - Client: s.Manager.GetClient(), - Log: ctrl.Log.WithName("collector").WithName(kind), - archive: archive, - event: event, - }).Setup(s.Manager, chaosKind.Chaos); err != nil { - log.Error(err, "unable to create collector", "collector", kind) - os.Exit(1) - } - } - - return s, s.Manager.GetClient(), s.Manager.GetAPIReader(), s.Manager.GetScheme() -} - -// Register starts collectors manager. -func Register(s *Server, controllerRuntimeStopCh <-chan struct{}) { - go func() { - log.Info("Starting collector") - if err := s.Manager.Start(controllerRuntimeStopCh); err != nil { - log.Error(err, "could not start collector") - os.Exit(1) - } - }() -} diff --git a/pkg/command/command.go b/pkg/command/command.go new file mode 100644 index 0000000000..af4b5b791b --- /dev/null +++ b/pkg/command/command.go @@ -0,0 +1,152 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package command + +import ( + "os/exec" + "reflect" + "strings" + + "github.com/pkg/errors" +) + +// ExecTag stands for the path of executable file in command. +// If we want this util works , +// we must add Exec in the struct and use NewExec() to initialize it, +// because the default way to initialize Exec means None in code. +const ExecTag = "exec" + +// SubCommandTag stands for the sub command in common command. +// We can use it in struct fields as a tag. +// Just like MatchExtension below +// +// type Iptables Struct { +// Exec +// MatchExtension Match `sub_command:""` +// } +// +// type Match Struct { +// Exec +// Port string `para:"-p"` +// } +// +// Field with SubcommandTag needs to be a struct with Exec. +const SubCommandTag = "sub_command" + +// ParaTag stands for parameters in command. +// We can use it in struct fields as a tag. +// Just like Port below +// +// type Iptables Struct { +// Exec +// Port string `para:"-p"` +// } +// +// If the field is not string type or []string type , it will bring an error. +// If the tag value like "-p" is empty string , +// the para will just add the field value into the command just as some single value parameter in command. +// If the value of field is empty string or empty string slice or empty slice, the field and tag will all be skipped. +const ParaTag = "para" + +// Exec is the interface of a command. +// We need to inherit it in the struct of command. +// User must add ExecTag as the tag of Exec field. +// Example: +// +// type Iptables struct { +// Exec `exec:"iptables"` +// Tables string `para:"-t"` +// } +type Exec struct { + active bool +} + +func NewExec() Exec { + return Exec{active: true} +} + +func ToCommand(i interface{}) (*exec.Cmd, error) { + path, args, err := Marshal(i) + if err != nil { + return nil, err + } + return exec.Command(path, args...), nil +} + +func Marshal(i interface{}) (string, []string, error) { + value := reflect.ValueOf(i) + return marshal(value) +} + +func marshal(value reflect.Value) (string, []string, error) { + //var options []string + if path, ok := SearchKey(value); ok { + // Field(0).String is Exec.Path + + if path == "" { + return "", nil, nil + } + args := make([]string, 0) + for i := 0; i < value.NumField(); i++ { + if _, ok := value.Type().Field(i).Tag.Lookup(SubCommandTag); ok { + subPath, subArgs, err := marshal(value.Field(i)) + if err != nil { + return "", nil, err + } + if subPath != "" { + args = append(args, subPath) + } + args = append(args, subArgs...) + } + if paraName, ok := value.Type().Field(i).Tag.Lookup(ParaTag); ok { + if value.Type().Field(i).Type.Name() == "string" { + if value.Field(i).String() != "" { + if paraName != "" { + args = append(args, paraName) + } + args = append(args, value.Field(i).String()) + } + } else if value.Field(i).Kind() == reflect.Slice { + if slicePara, ok := value.Field(i).Interface().([]string); ok { + if strings.Join(slicePara, "") != "" { + if paraName != "" { + args = append(args, paraName) + } + args = append(args, slicePara...) + } + } else { + return "", nil, errors.Errorf("invalid parameter slice type %s :parameter slice must be string slice", value.Field(i).String()) + } + } else { + return "", nil, errors.Errorf("invalid parameter type %s : parameter must be string or string slice", value.Type().Field(i).Type.Name()) + } + } + } + return path, args, nil + } + return "", nil, nil +} + +func SearchKey(value reflect.Value) (string, bool) { + for i := 0; i < value.NumField(); i++ { + if path, ok := value.Type().Field(i).Tag.Lookup(ExecTag); ok { + if value.Field(i).Field(0).Bool() { + return path, ok + } + } + } + return "", false +} diff --git a/pkg/command/command_test.go b/pkg/command/command_test.go new file mode 100644 index 0000000000..4e71d45067 --- /dev/null +++ b/pkg/command/command_test.go @@ -0,0 +1,114 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package command + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +type IptablesTest struct { + Exec `exec:"iptables"` + Port string `para:"-p"` + Ports []string `para:"--ports"` + EPort string `para:"-ep"` + EPorts []string `para:"--e_ports"` + Match `sub_command:""` + Match_ `sub_command:""` +} + +type Match struct { + Exec `exec:"-m"` + Helper string `para:"--helper"` +} + +type Match_ struct { + Exec `exec:"-m"` + Helper string `para:"--helper"` +} + +func TestMarshal(t *testing.T) { + n := IptablesTest{ + NewExec(), + "20", + []string{"2021", "2023"}, + "", + []string{"", ""}, + Match{NewExec(), "help"}, + Match_{}, + } + path, args, err := Marshal(n) + assert.NoError(t, err, "nil") + assert.Equal(t, "iptables -p 20 --ports 2021 2023 -m --helper help", + path+" "+strings.Join(args, " ")) +} + +type Iptables struct { + Exec `exec:"iptables"` + Tables string `para:"-t"` + Command string `para:""` + Chain string `para:""` + JumpTarget string `para:"-j"` + Protocol string `para:"--protocol"` + MatchExtension string `para:"-m"` + SPorts string `para:"--source-ports"` + DPorts string `para:"--destination-ports"` + SPort string `para:"--source-port"` + DPort string `para:"--destination-port"` + TcpFlags string `para:"--tcp-flags"` +} + +type TestInvalidParaType struct { + Exec `exec:"test"` + P int `para:"-p"` +} + +type TestInvalidParaSliceType struct { + Exec `exec:"test"` + P []int `para:"-p"` +} + +func TestMarshalExample(t *testing.T) { + n := Iptables{ + Exec: NewExec(), + Command: "-A", + Chain: "Chaos_Chain", + JumpTarget: "Chaos_Target", + Protocol: "tcp", + MatchExtension: "multiport", + SPorts: "2021,2022", + TcpFlags: "SYN", + } + path, args, err := Marshal(n) + assert.NoError(t, err, "nil") + assert.Equal(t, "iptables -A Chaos_Chain -j Chaos_Target --protocol tcp -m multiport --source-ports 2021,2022 --tcp-flags SYN", + path+" "+strings.Join(args, " ")) + + p := TestInvalidParaType{ + Exec: NewExec(), + P: 2, + } + _, _, err = Marshal(p) + assert.EqualError(t, err, "invalid parameter type int : parameter must be string or string slice") + ps := TestInvalidParaSliceType{ + Exec: NewExec(), + P: nil, + } + _, _, err = Marshal(ps) + assert.EqualError(t, err, "invalid parameter slice type <[]int Value> :parameter slice must be string slice") +} diff --git a/pkg/config/controller.go b/pkg/config/controller.go index 8952beb8c0..b22d9d27c1 100644 --- a/pkg/config/controller.go +++ b/pkg/config/controller.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package config @@ -17,44 +19,72 @@ import ( "time" "github.com/kelseyhightower/envconfig" - - "github.com/chaos-mesh/chaos-mesh/pkg/webhook/config/watcher" ) -// TLSConfig defines the configuration for chaos-daemon tls client +// TLSConfig defines the configuration for chaos-daemon and chaosd tls client type TLSConfig struct { + // ChaosMeshCACert is the path of chaos daemon ca cert + ChaosMeshCACert string `envconfig:"CHAOS_MESH_CA_CERT" default:""` // ChaosDaemonClientCert is the path of chaos daemon certificate ChaosDaemonClientCert string `envconfig:"CHAOS_DAEMON_CLIENT_CERT" default:""` // ChaosDaemonClientKey is the path of chaos daemon certificate key ChaosDaemonClientKey string `envconfig:"CHAOS_DAEMON_CLIENT_KEY" default:""` - // ChaosMeshCACert is the path of chaos mesh ca cert - ChaosMeshCACert string `envconfig:"CHAOS_MESH_CA_CERT" default:""` + + // ChaosdCACert is the path of chaosd ca cert + ChaosdCACert string `envconfig:"CHAOSD_CA_CERT" default:""` + // ChaosdClientCert is the path of chaosd certificate + ChaosdClientCert string `envconfig:"CHAOSD_CLIENT_CERT" default:""` + // ChaosdClientKey is the path of chaosd certificate key + ChaosdClientKey string `envconfig:"CHAOSD_CLIENT_KEY" default:""` } // ChaosControllerConfig defines the configuration for Chaos Controller type ChaosControllerConfig struct { // ChaosDaemonPort is the port which grpc server listens on - ChaosDaemonPort int `envconfig:"CHAOS_DAEMON_PORT" default:"31767"` + ChaosDaemonPort int `envconfig:"CHAOS_DAEMON_SERVICE_PORT" default:"31767"` TLSConfig + // The QPS config for kubernetes client + QPS float32 `envconfig:"QPS" default:"30"` + // The Burst config for kubernetes client + Burst int `envconfig:"BURST" default:"50"` + // BPFKIPort is the port which BFFKI grpc server listens on BPFKIPort int `envconfig:"BPFKI_PORT" default:"50051"` - // MetricsAddr is the address the metric endpoint binds to - MetricsAddr string `envconfig:"METRICS_ADDR" default:":10080"` + // WebhookHost and WebhookPort are combined into an address the webhook server bind to + WebhookHost string `envconfig:"WEBHOOK_HOST" default:"0.0.0.0"` + WebhookPort int `envconfig:"WEBHOOK_PORT" default:"9443"` + // MetricsHost and MetricsPort are combined into an address the metric endpoint binds to + MetricsHost string `envconfig:"METRICS_HOST" default:"0.0.0.0"` + MetricsPort int `envconfig:"METRICS_PORT" default:"10080"` // PprofAddr is the address the pprof endpoint binds to. PprofAddr string `envconfig:"PPROF_ADDR" default:"0"` + + // CtrlAddr os the address the ctrlserver bind to + CtrlAddr string `envconfig:"CTRL_ADDR"` + // EnableLeaderElection enables leader election for controller manager // Enabling this will ensure there is only one active controller manager - EnableLeaderElection bool `envconfig:"ENABLE_LEADER_ELECTION" default:"false"` + EnableLeaderElection bool `envconfig:"ENABLE_LEADER_ELECTION" default:"true"` + // LeaderElectLeaseDuration is the duration that non-leader candidates will + // wait to force acquire leadership. This is measured against time of + // last observed ack. (default 15s) + LeaderElectLeaseDuration time.Duration `envconfig:"LEADER_ELECT_LEASE_DURATION" default:"15s"` + // LeaderElectRenewDeadline is the duration that the acting control-plane + // will retry refreshing leadership before giving up. (default 10s) + LeaderElectRenewDeadline time.Duration `envconfig:"LEADER_ELECT_RENEW_DEADLINE" default:"10s"` + // LeaderElectRetryPeriod is the duration the LeaderElector clients should wait + // between tries of actions. (default 2s) + LeaderElectRetryPeriod time.Duration `envconfig:"LEADER_ELECT_RETRY_PERIOD" default:"2s"` + // EnableFilterNamespace will filter namespace with annotation. Only the pods/containers in namespace // annotated with `chaos-mesh.org/inject=enabled` will be injected EnableFilterNamespace bool `envconfig:"ENABLE_FILTER_NAMESPACE" default:"false"` // CertsDir is the directory for storing certs key file and cert file CertsDir string `envconfig:"CERTS_DIR" default:"/etc/webhook/certs"` // RPCTimeout is timeout of RPC between controllers and chaos-operator - RPCTimeout time.Duration `envconfig:"RPC_TIMEOUT" default:"1m"` - WatcherConfig *watcher.Config + RPCTimeout time.Duration `envconfig:"RPC_TIMEOUT" default:"1m"` // ClusterScoped means control Chaos Object in cluster level(all namespace), ClusterScoped bool `envconfig:"CLUSTER_SCOPED" default:"true"` // TargetNamespace is the target namespace to injecting chaos. @@ -68,11 +98,24 @@ type ChaosControllerConfig struct { // SecurityMode is used for enable authority validation in admission webhook SecurityMode bool `envconfig:"SECURITY_MODE" default:"true" json:"security_mode"` + // ChaosdSecurityMode is used for enable mTLS connection between chaos-controller-manager and chaod + ChaosdSecurityMode bool `envconfig:"CHAOSD_SECURITY_MODE" default:"true" json:"chaosd_security_mode"` + // Namespace is the namespace which the controller manager run in Namespace string `envconfig:"NAMESPACE" default:""` // AllowHostNetworkTesting removes the restriction on chaos testing pods with `hostNetwork` set to true AllowHostNetworkTesting bool `envconfig:"ALLOW_HOST_NETWORK_TESTING" default:"false"` + + // PodFailurePauseImage is used to set a custom image for pod failure + PodFailurePauseImage string `envconfig:"POD_FAILURE_PAUSE_IMAGE" default:"gcr.io/google-containers/pause:latest"` + + EnabledControllers []string `envconfig:"ENABLED_CONTROLLERS" default:"*"` + EnabledWebhooks []string `envconfig:"ENABLED_WEBHOOKS" default:"*"` + + LocalHelmChartPath string `envconfig:"LOCAL_HELM_CHART_PATH" default:""` + + MaxEvents int `envconfig:"MAX_EVENTS" default:"100"` } // EnvironChaosController returns the settings from the environment. diff --git a/pkg/config/dashboard.go b/pkg/config/dashboard.go index 1778b95dfd..aa06ddebb7 100644 --- a/pkg/config/dashboard.go +++ b/pkg/config/dashboard.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package config @@ -17,76 +19,120 @@ import ( "time" "github.com/kelseyhightower/envconfig" - - "github.com/chaos-mesh/chaos-mesh/pkg/ttlcontroller" + "github.com/pkg/errors" ) // ChaosDashboardConfig defines the configuration for Chaos Dashboard type ChaosDashboardConfig struct { - ListenHost string `envconfig:"LISTEN_HOST" default:"0.0.0.0" json:"listen_host"` - ListenPort int `envconfig:"LISTEN_PORT" default:"2333" json:"listen_port"` - MetricAddress string `envconfig:"METRIC_ADDRESS" json:"-"` - EnableLeaderElection bool `envconfig:"ENABLE_LEADER_ELECTION" json:"-"` - Database *DatabaseConfig `json:"-"` - PersistTTL *PersistTTLConfig `json:"-"` - // ClusterScoped means control Chaos Object in cluster level(all namespace), + ListenHost string `envconfig:"LISTEN_HOST" default:"0.0.0.0" json:"listen_host"` + ListenPort int `envconfig:"LISTEN_PORT" default:"2333" json:"listen_port"` + MetricHost string `envconfig:"METRIC_HOST" default:"0.0.0.0" json:"-"` + MetricPort int `envconfig:"METRIC_PORT" default:"2334" json:"-"` + EnableLeaderElection bool `envconfig:"ENABLE_LEADER_ELECTION" json:"-"` + Database *DatabaseConfig `json:"-"` + PersistTTL *TTLConfigWithStringTime `json:"-"` + // ClusterScoped means control Chaos Object in cluster level(all namespace). ClusterScoped bool `envconfig:"CLUSTER_SCOPED" default:"true" json:"cluster_mode"` // TargetNamespace is the target namespace to injecting chaos. - // It only works with ClusterScoped is false; + // It only works with ClusterScoped is false. TargetNamespace string `envconfig:"TARGET_NAMESPACE" default:"" json:"target_namespace"` // EnableFilterNamespace will filter namespace with annotation. Only the pods/containers in namespace - // annotated with `chaos-mesh.org/inject=enabled` will be injected + // annotated with `chaos-mesh.org/inject=enabled` will be injected. EnableFilterNamespace bool `envconfig:"ENABLE_FILTER_NAMESPACE" default:"false"` - // SecurityMode will use the token login by the user if set to true - SecurityMode bool `envconfig:"SECURITY_MODE" default:"true" json:"security_mode"` - DNSServerCreate bool `envconfig:"DNS_SERVER_CREATE" default:"false" json:"dns_server_create"` + SecurityMode bool `envconfig:"SECURITY_MODE" default:"true" json:"security_mode"` + // GcpSecurityMode will use the gcloud authentication to login to GKE user + GcpSecurityMode bool `envconfig:"GCP_SECURITY_MODE" default:"false" json:"gcp_security_mode"` + GcpClientId string `envconfig:"GCP_CLIENT_ID" default:"" json:"-"` + GcpClientSecret string `envconfig:"GCP_CLIENT_SECRET" default:"" json:"-"` + + RootUrl string `envconfig:"ROOT_URL" default:"http://localhost:2333" json:"root_path"` + + // enableProfiling is a flag to enable pprof in controller-manager and chaos-daemon + EnableProfiling bool `envconfig:"ENABLE_PROFILING" default:"true" json:"-"` + + // After v2.5, the DNS server is created by default. + DNSServerCreate bool `envconfig:"DNS_SERVER_CREATE" default:"true" json:"dns_server_create"` Version string `json:"version"` -} -// PersistTTLConfig defines the configuration of ttl -type PersistTTLConfig struct { - SyncPeriod string `envconfig:"CLEAN_SYNC_PERIOD" default:"12h"` - Event string `envconfig:"TTL_EVENT" default:"168h"` // one week - Experiment string `envconfig:"TTL_EXPERIMENT" default:"336h"` // two weeks + // The QPS config for kubernetes client + QPS float32 `envconfig:"QPS" default:"200" json:"-"` + // The Burst config for kubernetes client + Burst int `envconfig:"BURST" default:"300" json:"-"` } // DatabaseConfig defines the configuration for databases type DatabaseConfig struct { - // Archive Chaos Experiments to DB - Archive bool - Driver string `envconfig:"DATABASE_DRIVER" default:"sqlite3"` + Driver string `envconfig:"DATABASE_DRIVER" default:"sqlite3"` + // Datasource is the connection string for database. + // For sqlite3, it is the path of the database file. + // For mysql, it is the DSN (https://github.com/go-sql-driver/mysql#dsn-data-source-name). Datasource string `envconfig:"DATABASE_DATASOURCE" default:"core.sqlite"` - Secret string `envconfig:"DATABASE_SECRET"` } -// EnvironChaosDashboard returns the settings from the environment. -func EnvironChaosDashboard() (*ChaosDashboardConfig, error) { - cfg := ChaosDashboardConfig{} - err := envconfig.Process("", &cfg) - return &cfg, err +// TTLConfig defines all the TTL-related configurations. +type TTLConfig struct { + // ResyncPeriod defines the period of cleaning data. + ResyncPeriod time.Duration + + // TTL of events. + EventTTL time.Duration + // TTL of experiments. + ExperimentTTL time.Duration + // TTL of schedules. + ScheduleTTL time.Duration + // TTL of workflows. + WorkflowTTL time.Duration } -// ParsePersistTTLConfig parse PersistTTLConfig to persistTTLConfigParsed. -func ParsePersistTTLConfig(config *PersistTTLConfig) (*ttlcontroller.TTLconfig, error) { - SyncPeriod, err := time.ParseDuration(config.SyncPeriod) +// TTLConfigWithStringTime defines all the TTL-related configurations with string type time. +type TTLConfigWithStringTime struct { + ResyncPeriod string `envconfig:"CLEAN_SYNC_PERIOD" default:"12h"` + + EventTTL string `envconfig:"TTL_EVENT" default:"168h"` // one week + ExperimentTTL string `envconfig:"TTL_EXPERIMENT" default:"336h"` // two weeks + ScheduleTTL string `envconfig:"TTL_SCHEDULE" default:"336h"` + WorkflowTTL string `envconfig:"TTL_WORKFLOW" default:"336h"` +} + +func (config *TTLConfigWithStringTime) Parse() (*TTLConfig, error) { + syncPeriod, err := time.ParseDuration(config.ResyncPeriod) + if err != nil { + return nil, errors.Wrap(err, "parse configuration sync period") + } + + eventTTL, err := time.ParseDuration(config.EventTTL) + if err != nil { + return nil, errors.Wrap(err, "parse configuration TTL for event") + } + + experimentTTL, err := time.ParseDuration(config.ExperimentTTL) if err != nil { - return nil, err + return nil, errors.Wrap(err, "parse configuration TTL for experiment") } - Event, err := time.ParseDuration(config.Event) + scheduleTTL, err := time.ParseDuration(config.ScheduleTTL) if err != nil { - return nil, err + return nil, errors.Wrap(err, "parse configuration TTL for schedule") } - Experiment, err := time.ParseDuration(config.Experiment) + workflowTTL, err := time.ParseDuration(config.WorkflowTTL) if err != nil { - return nil, err + return nil, errors.Wrap(err, "parse configuration TTL for workflow") } - return &ttlcontroller.TTLconfig{ - DatabaseTTLResyncPeriod: SyncPeriod, - EventTTL: Event, - ArchiveExperimentTTL: Experiment, + return &TTLConfig{ + ResyncPeriod: syncPeriod, + EventTTL: eventTTL, + ExperimentTTL: experimentTTL, + ScheduleTTL: scheduleTTL, + WorkflowTTL: workflowTTL, }, nil } + +// GetChaosDashboardEnv gets all env variables related to dashboard. +func GetChaosDashboardEnv() (*ChaosDashboardConfig, error) { + cfg := ChaosDashboardConfig{} + err := envconfig.Process("", &cfg) + return &cfg, err +} diff --git a/pkg/config/dashboard_test.go b/pkg/config/dashboard_test.go new file mode 100644 index 0000000000..820b59413a --- /dev/null +++ b/pkg/config/dashboard_test.go @@ -0,0 +1,108 @@ +// Copyright 2023 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package config + +import ( + "testing" + + "github.com/kelseyhightower/envconfig" +) + +func TestChaosDashboardConfig(t *testing.T) { + config := ChaosDashboardConfig{} + err := envconfig.Process("", &config) + if err != nil { + t.Fatal("Error parsing empty ChaosDashboardConfig", err) + } + + if config.ListenHost != "0.0.0.0" { + t.Error("ListenHost is not set") + } + + if config.ListenPort != 2333 { + t.Error("ListenPort is not set") + } + + if config.ClusterScoped != true { + t.Error("ClusterScoped is not set") + } + + if config.EnableFilterNamespace != false { + t.Error("EnableFilterNamespace is not set") + } + + if config.SecurityMode != true { + t.Error("SecurityMode is not set") + } + + if config.DNSServerCreate != true { + t.Error("DNSServerCreate is not set") + } +} + +func TestTTLConfigWithStringTime(t *testing.T) { + config := TTLConfigWithStringTime{} + err := envconfig.Process("", &config) + if err != nil { + t.Fatal("Error parsing empty TTLConfigWithStringTime", err) + } + + if config.ResyncPeriod != "12h" { + t.Error("ResyncPeriod is not set") + } + + if config.EventTTL != "168h" { + t.Error("EventTTL is not set") + } + + if config.ExperimentTTL != "336h" { + t.Error("ExperimentTTL is not set") + } + + if config.ScheduleTTL != "336h" { + t.Error("ScheduleTTL is not set") + } + + if config.WorkflowTTL != "336h" { + t.Error("WorkflowTTL is not set") + } + + parsed, err := config.Parse() + + if err != nil { + t.Fatal("Error parsing config", err) + } + + if parsed.ResyncPeriod.Hours() != 12 { + t.Errorf("ResyncPeriod is not 12h, but %v", parsed.ResyncPeriod) + } + + if parsed.EventTTL.Hours() != 168 { + t.Errorf("EventTTL is not 168h, but %v", parsed.EventTTL) + } + + if parsed.ExperimentTTL.Hours() != 336 { + t.Errorf("ExperimentTTL is not 336h, but %v", parsed.ExperimentTTL) + } + + if parsed.ScheduleTTL.Hours() != 336 { + t.Errorf("ScheduleTTL is not 336h, but %v", parsed.ScheduleTTL) + } + + if parsed.WorkflowTTL.Hours() != 336 { + t.Errorf("WorkflowTTL is not 336h, but %v", parsed.WorkflowTTL) + } +} diff --git a/pkg/core/common.go b/pkg/core/common.go deleted file mode 100644 index 50eeb3a90a..0000000000 --- a/pkg/core/common.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package core - -// TODO: using YAML in name might make confusion, because it is actually transferred by json. -// TODO: how about "raw"? - -// KubeObjectYAMLDescription defines the YAML structure of an object stored in kubernetes API. -type KubeObjectYAMLDescription struct { - APIVersion string `json:"apiVersion"` - Kind string `json:"kind"` - Metadata KubeObjectYAMLMetadata `json:"metadata"` - Spec interface{} `json:"spec"` -} - -// KubeObjectYAMLMetadata defines the metadata of KubeObjectYAMLDescription. -type KubeObjectYAMLMetadata struct { - Name string `json:"name"` - Namespace string `json:"namespace"` - Labels map[string]string `json:"labels"` - Annotations map[string]string `json:"annotations"` -} diff --git a/pkg/core/event.go b/pkg/core/event.go deleted file mode 100644 index da1f6be4af..0000000000 --- a/pkg/core/event.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package core - -import ( - "context" - "time" -) - -// EventStore defines operations for working with event. -type EventStore interface { - // List returns an event list from the datastore. - List(context.Context) ([]*Event, error) - - // ListByFilter returns an event list by podName, podNamespace, experimentName, experimentNamespace, uid, kind, startTime and finishTime. - ListByFilter(context.Context, Filter) ([]*Event, error) - - // ListByExperiment returns an event list by the name and namespace of the experiment. - ListByExperiment(context.Context, string, string) ([]*Event, error) - - // ListByNamespace returns an event list by the namespace of the pod. - ListByNamespace(context.Context, string) ([]*Event, error) - - // ListByPod returns an event list by the name and namespace of the pod. - ListByPod(context.Context, string, string) ([]*Event, error) - - // ListByUID returns an event list by the UID. - ListByUID(context.Context, string) ([]*Event, error) - - // ListByUIDs returns an event list by the UID list. - ListByUIDs(context.Context, []string) ([]*Event, error) - - // DryListByFilter returns an event list by experimentName, experimentNamespace, uid, kind, startTime and finishTime. - DryListByFilter(context.Context, Filter) ([]*Event, error) - - // Find returns an event from the datastore by ID. - Find(context.Context, uint) (*Event, error) - - // FindByExperimentAndStartTime returns an event by the experiment and start time. - FindByExperimentAndStartTime(context.Context, string, string, *time.Time) (*Event, error) - - // Create persists a new event to the datastore. - Create(context.Context, *Event) error - - // Update persists an updated event to the datastore. - Update(context.Context, *Event) error - - // DeleteIncompleteEvent deletes all incomplete events. - // If the chaos-dashboard was restarted, some incomplete events would be stored in datastore, - // which means the event would never save the finish_time. - // DeleteIncompleteEvent can be used to delete all incomplete events to avoid this case. - DeleteIncompleteEvents(context.Context) error - - // DeleteByFinishTime deletes events and podrecords whose time difference is greater than the given time from FinishTime. - DeleteByFinishTime(context.Context, time.Duration) error - - // DeleteByUID deletes events list by the UID. - DeleteByUID(context.Context, string) error - - // DeleteByUIDs deletes events list by the UID list. - DeleteByUIDs(context.Context, []string) error - - // UpdateIncompleteEvents updates the incomplete event by the namespace and name - // If chaos is deleted before an event is over, then the incomplete event would be stored in datastore, - // which means the event would never save the finish_time. - // UpdateIncompleteEvents can update the finish_time when the chaos is deleted. - UpdateIncompleteEvents(context.Context, string, string) error -} - -// Event represents an event instance. -type Event struct { - ID uint `gorm:"primary_key" json:"id"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - DeletedAt *time.Time `sql:"index" json:"deleted_at"` - Experiment string `gorm:"index:experiment" json:"experiment"` - Namespace string `json:"namespace"` - Kind string `json:"kind"` - Message string `json:"message"` - StartTime *time.Time `gorm:"index:start_time" json:"start_time"` - FinishTime *time.Time `json:"finish_time"` - Duration string `json:"duration"` - Pods []*PodRecord `gorm:"-" json:"pods"` - ExperimentID string `gorm:"index:experiment_id" json:"experiment_id"` -} - -// PodRecord represents a pod record with event ID. -type PodRecord struct { - ID uint `gorm:"primary_key" json:"id"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - DeletedAt *time.Time `sql:"index" json:"deleted_at"` - EventID uint `gorm:"index:event_id" json:"event_id"` - PodIP string `gorm:"index:pod_id" json:"pod_ip"` - PodName string `json:"pod_name"` - Namespace string `json:"namespace"` - Message string `json:"message"` - Action string `json:"action"` -} - -// Filter represents the filter to list events -type Filter struct { - PodName string - PodNamespace string - StartTimeStr string - FinishTimeStr string - ExperimentName string - ExperimentNamespace string - UID string - Kind string - LimitStr string -} diff --git a/pkg/core/experiment.go b/pkg/core/experiment.go deleted file mode 100644 index dd2730bb04..0000000000 --- a/pkg/core/experiment.go +++ /dev/null @@ -1,391 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package core - -import ( - "context" - "encoding/json" - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -// ExperimentStore defines operations for working with experiments. -type ExperimentStore interface { - // ListMeta returns experiment metadata list from the datastore. - ListMeta(ctx context.Context, kind, namespace, name string, archived bool) ([]*ExperimentMeta, error) - - // FindByUID returns an experiment by UID. - FindByUID(ctx context.Context, UID string) (*Experiment, error) - - // FindMetaByUID returns an experiment metadata by UID. - FindMetaByUID(context.Context, string) (*ExperimentMeta, error) - - // Set saves the experiment to datastore. - Set(context.Context, *Experiment) error - - // Archive archives experiments which "archived" field is false. - Archive(ctx context.Context, namespace, name string) error - - // Delete deletes the archive from the datastore. - Delete(context.Context, *Experiment) error - - // DeleteByFinishTime deletes archives which time difference is greater than the given time from FinishTime. - DeleteByFinishTime(context.Context, time.Duration) error - - // DeleteByUIDs deletes archives by the uid list. - DeleteByUIDs(context.Context, []string) error - - // DeleteIncompleteExperiments deletes all incomplete experiments. - // If the chaos-dashboard was restarted and the experiment is completed during the restart, - // which means the experiment would never save the finish_time. - // DeleteIncompleteExperiments can be used to delete all incomplete experiments to avoid this case. - DeleteIncompleteExperiments(context.Context) error -} - -// Experiment represents an experiment instance. Use in db. -type Experiment struct { - ExperimentMeta - Experiment string `gorm:"size:2048"` // JSON string -} - -// ExperimentMeta defines the metadata of an experiment. Use in db. -type ExperimentMeta struct { - ID uint `gorm:"primary_key" json:"id"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - DeletedAt *time.Time `sql:"index" json:"deleted_at"` - UID string `gorm:"index:uid" json:"uid"` - Kind string `json:"kind"` - Name string `json:"name"` - Namespace string `json:"namespace"` - Action string `json:"action"` - StartTime time.Time `json:"start_time"` - FinishTime time.Time `json:"finish_time"` - Archived bool `json:"archived"` -} - -// ExperimentInfo defines a form data of Experiment from API. -type ExperimentInfo struct { - Name string `json:"name" binding:"required,NameValid"` - Namespace string `json:"namespace" binding:"required,NameValid"` - Labels map[string]string `json:"labels" binding:"MapSelectorsValid"` - Annotations map[string]string `json:"annotations" binding:"MapSelectorsValid"` - Scope ScopeInfo `json:"scope"` - Target TargetInfo `json:"target"` - Scheduler SchedulerInfo `json:"scheduler"` -} - -// ScopeInfo defines the scope of the Experiment. -type ScopeInfo struct { - SelectorInfo - Mode string `json:"mode" binding:"oneof='' 'one' 'all' 'fixed' 'fixed-percent' 'random-max-percent'"` - Value string `json:"value" binding:"ValueValid"` -} - -// SelectorInfo defines the selector options of the Experiment. -type SelectorInfo struct { - NamespaceSelectors []string `json:"namespace_selectors" binding:"NamespaceSelectorsValid"` - LabelSelectors map[string]string `json:"label_selectors" binding:"MapSelectorsValid"` - ExpressionSelectors []metav1.LabelSelectorRequirement `json:"expression_selectors" binding:"RequirementSelectorsValid"` - AnnotationSelectors map[string]string `json:"annotation_selectors" binding:"MapSelectorsValid"` - FieldSelectors map[string]string `json:"field_selectors" binding:"MapSelectorsValid"` - PhaseSelector []string `json:"phase_selectors" binding:"PhaseSelectorsValid"` - - // Pods is a map of string keys and a set values that used to select pods. - // The key defines the namespace which pods belong, - // and the each values is a set of pod names. - Pods map[string][]string `json:"pods" binding:"PodsValid"` -} - -// ParseSelector parses SelectorInfo to v1alpha1.SelectorSpec -func (s *SelectorInfo) ParseSelector() v1alpha1.SelectorSpec { - selector := v1alpha1.SelectorSpec{} - selector.Namespaces = append(selector.Namespaces, s.NamespaceSelectors...) - - selector.LabelSelectors = make(map[string]string) - for key, val := range s.LabelSelectors { - selector.LabelSelectors[key] = val - } - - selector.ExpressionSelectors = append(selector.ExpressionSelectors, s.ExpressionSelectors...) - - selector.AnnotationSelectors = make(map[string]string) - for key, val := range s.AnnotationSelectors { - selector.AnnotationSelectors[key] = val - } - - selector.FieldSelectors = make(map[string]string) - for key, val := range s.FieldSelectors { - selector.FieldSelectors[key] = val - } - - selector.PodPhaseSelectors = append(selector.PodPhaseSelectors, s.PhaseSelector...) - - if s.Pods != nil { - selector.Pods = s.Pods - } - - return selector -} - -// TargetInfo defines the information of target objects. -type TargetInfo struct { - Kind string `json:"kind" binding:"required,oneof=PodChaos NetworkChaos IoChaos KernelChaos TimeChaos StressChaos DNSChaos AwsChaos"` - PodChaos *PodChaosInfo `json:"pod_chaos,omitempty" binding:"RequiredFieldEqual=Kind:PodChaos"` - NetworkChaos *NetworkChaosInfo `json:"network_chaos,omitempty" binding:"RequiredFieldEqual=Kind:NetworkChaos"` - IOChaos *IOChaosInfo `json:"io_chaos,omitempty" binding:"RequiredFieldEqual=Kind:IoChaos"` - KernelChaos *KernelChaosInfo `json:"kernel_chaos,omitempty" binding:"RequiredFieldEqual=Kind:KernelChaos"` - TimeChaos *TimeChaosInfo `json:"time_chaos,omitempty" binding:"RequiredFieldEqual=Kind:TimeChaos"` - StressChaos *StressChaosInfo `json:"stress_chaos,omitempty" binding:"RequiredFieldEqual=Kind:StressChaos"` - DNSChaos *DNSChaosInfo `json:"dns_chaos,omitempty" binding:"RequiredFieldEqual=Kind:DNSChaos"` - AwsChaos *AwsChaosInfo `json:"aws_chaos,omitempty" binding:"RequiredFieldEqual=Kind:AwsChaos"` -} - -// SchedulerInfo defines the scheduler information. -type SchedulerInfo struct { - Cron string `json:"cron" binding:"CronValid"` - Duration string `json:"duration" binding:"DurationValid"` -} - -// PodChaosInfo defines the basic information of pod chaos for creating a new PodChaos. -type PodChaosInfo struct { - Action string `json:"action" binding:"oneof='' 'pod-kill' 'pod-failure' 'container-kill'"` - ContainerName string `json:"container_name"` - GracePeriod int64 `json:"grace_period"` -} - -// NetworkChaosInfo defines the basic information of network chaos for creating a new NetworkChaos. -type NetworkChaosInfo struct { - Action string `json:"action" binding:"oneof='' 'netem' 'delay' 'loss' 'duplicate' 'corrupt' 'partition' 'bandwidth'"` - Delay *v1alpha1.DelaySpec `json:"delay" binding:"RequiredFieldEqual=Action:delay"` - Loss *v1alpha1.LossSpec `json:"loss" binding:"RequiredFieldEqual=Action:loss"` - Duplicate *v1alpha1.DuplicateSpec `json:"duplicate" binding:"RequiredFieldEqual=Action:duplicate"` - Corrupt *v1alpha1.CorruptSpec `json:"corrupt" binding:"RequiredFieldEqual=Action:corrupt"` - Bandwidth *v1alpha1.BandwidthSpec `json:"bandwidth" binding:"RequiredFieldEqual=Action:bandwidth"` - Direction string `json:"direction" binding:"oneof='' 'to' 'from' 'both'"` - TargetScope *ScopeInfo `json:"target_scope"` - ExternalTargets []string `json:"external_targets"` -} - -// IOChaosInfo defines the basic information of io chaos for creating a new IOChaos. -type IOChaosInfo struct { - Action string `json:"action" binding:"oneof='' 'latency' 'fault' 'attrOverride'"` - Delay string `json:"delay"` - Errno uint32 `json:"errno"` - Attr *v1alpha1.AttrOverrideSpec `json:"attr"` - Mistake *v1alpha1.MistakeSpec `json:"mistake"` - Path string `json:"path"` - Percent int `json:"percent"` - Methods []v1alpha1.IoMethod `json:"methods"` - VolumePath string `json:"volume_path"` - ContainerName string `json:"container_name"` -} - -// KernelChaosInfo defines the basic information of kernel chaos for creating a new KernelChaos. -type KernelChaosInfo struct { - FailKernRequest v1alpha1.FailKernRequest `json:"fail_kern_request"` -} - -// TimeChaosInfo defines the basic information of time chaos for creating a new TimeChaos. -type TimeChaosInfo struct { - TimeOffset string `json:"time_offset"` - ClockIDs []string `json:"clock_ids"` - ContainerNames []string `json:"container_names"` -} - -// StressChaosInfo defines the basic information of stress chaos for creating a new StressChaos. -type StressChaosInfo struct { - Stressors *v1alpha1.Stressors `json:"stressors"` - StressngStressors string `json:"stressng_stressors,omitempty"` - ContainerName *string `json:"container_name,omitempty"` -} - -// DNSChaosInfo defines the basic information of dns chaos for creating a new DNSChaos. -type DNSChaosInfo struct { - Action string `json:"action" binding:"oneof='error' 'random'"` - DomainNamePatterns []string `json:"patterns"` -} - -// AwsChaosInfo defines the basic information of aws chaos for creating a new AwsChaos. -type AwsChaosInfo struct { - Action string `json:"action" binding:"oneof='ec2-stop' 'ec2-restart' 'detach-volume'"` - SecretName *string `json:"secretName,omitempty"` - AwsRegion string `json:"awsRegion"` - Ec2Instance string `json:"ec2Instance"` - EbsVolume *string `json:"volumeID,omitempty"` - DeviceName *string `json:"deviceName,omitempty"` -} - -// ParsePodChaos Parse PodChaos JSON string into KubeObjectYAMLDescription. -func (e *Experiment) ParsePodChaos() (KubeObjectYAMLDescription, error) { - chaos := &v1alpha1.PodChaos{} - if err := json.Unmarshal([]byte(e.Experiment), &chaos); err != nil { - return KubeObjectYAMLDescription{}, err - } - - return KubeObjectYAMLDescription{ - APIVersion: chaos.APIVersion, - Kind: chaos.Kind, - Metadata: KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, nil -} - -// ParseNetworkChaos Parse NetworkChaos JSON string into KubeObjectYAMLDescription. -func (e *Experiment) ParseNetworkChaos() (KubeObjectYAMLDescription, error) { - chaos := &v1alpha1.NetworkChaos{} - if err := json.Unmarshal([]byte(e.Experiment), &chaos); err != nil { - return KubeObjectYAMLDescription{}, err - } - - return KubeObjectYAMLDescription{ - APIVersion: chaos.APIVersion, - Kind: chaos.Kind, - Metadata: KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, nil -} - -// ParseIOChaos Parse IOChaos JSON string into KubeObjectYAMLDescription. -func (e *Experiment) ParseIOChaos() (KubeObjectYAMLDescription, error) { - chaos := &v1alpha1.IoChaos{} - if err := json.Unmarshal([]byte(e.Experiment), &chaos); err != nil { - return KubeObjectYAMLDescription{}, err - } - - return KubeObjectYAMLDescription{ - APIVersion: chaos.APIVersion, - Kind: chaos.Kind, - Metadata: KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, nil -} - -// ParseTimeChaos Parse TimeChaos JSON string into KubeObjectYAMLDescription. -func (e *Experiment) ParseTimeChaos() (KubeObjectYAMLDescription, error) { - chaos := &v1alpha1.TimeChaos{} - if err := json.Unmarshal([]byte(e.Experiment), &chaos); err != nil { - return KubeObjectYAMLDescription{}, err - } - - return KubeObjectYAMLDescription{ - APIVersion: chaos.APIVersion, - Kind: chaos.Kind, - Metadata: KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, nil -} - -// ParseKernelChaos Parse KernelChaos JSON string into KubeObjectYAMLDescription. -func (e *Experiment) ParseKernelChaos() (KubeObjectYAMLDescription, error) { - chaos := &v1alpha1.KernelChaos{} - if err := json.Unmarshal([]byte(e.Experiment), &chaos); err != nil { - return KubeObjectYAMLDescription{}, err - } - - return KubeObjectYAMLDescription{ - APIVersion: chaos.APIVersion, - Kind: chaos.Kind, - Metadata: KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, nil -} - -// ParseStressChaos Parse StressChaos JSON string into KubeObjectYAMLDescription. -func (e *Experiment) ParseStressChaos() (KubeObjectYAMLDescription, error) { - chaos := &v1alpha1.StressChaos{} - if err := json.Unmarshal([]byte(e.Experiment), &chaos); err != nil { - return KubeObjectYAMLDescription{}, err - } - - return KubeObjectYAMLDescription{ - APIVersion: chaos.APIVersion, - Kind: chaos.Kind, - Metadata: KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, nil -} - -// ParseDNSChaos Parse DNSChaos JSON string into KubeObjectYAMLDescription. -func (e *Experiment) ParseDNSChaos() (KubeObjectYAMLDescription, error) { - chaos := &v1alpha1.DNSChaos{} - if err := json.Unmarshal([]byte(e.Experiment), &chaos); err != nil { - return KubeObjectYAMLDescription{}, err - } - - return KubeObjectYAMLDescription{ - APIVersion: chaos.APIVersion, - Kind: chaos.Kind, - Metadata: KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, nil -} - -// ParseDNSChaos Parse AwsChaos JSON string into ExperimentYAMLDescription. -func (e *Experiment) ParseAwsChaos() (KubeObjectYAMLDescription, error) { - chaos := &v1alpha1.AwsChaos{} - if err := json.Unmarshal([]byte(e.Experiment), &chaos); err != nil { - return KubeObjectYAMLDescription{}, err - } - - return KubeObjectYAMLDescription{ - APIVersion: chaos.APIVersion, - Kind: chaos.Kind, - Metadata: KubeObjectYAMLMetadata{ - Name: chaos.Name, - Namespace: chaos.Namespace, - Labels: chaos.Labels, - Annotations: chaos.Annotations, - }, - Spec: chaos.Spec, - }, nil -} diff --git a/pkg/core/workflow.go b/pkg/core/workflow.go deleted file mode 100644 index 3613432211..0000000000 --- a/pkg/core/workflow.go +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package core - -import ( - "context" - - "github.com/mitchellh/mapstructure" - - "github.com/pkg/errors" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - wfcontrollers "github.com/chaos-mesh/chaos-mesh/pkg/workflow/controllers" -) - -type WorkflowRepository interface { - CreateWorkflowWithRaw(ctx context.Context, raw KubeObjectYAMLDescription) (WorkflowDetail, error) - UpdateWorkflowWithRaw(ctx context.Context, raw KubeObjectYAMLDescription) (WorkflowDetail, error) - ListWorkflowWithNamespace(ctx context.Context, namespace string) ([]Workflow, error) - ListWorkflowFromAllNamespace(ctx context.Context) ([]Workflow, error) - GetWorkflowByNamespacedName(ctx context.Context, namespace, name string) (WorkflowDetail, error) - DeleteWorkflowByNamespacedName(ctx context.Context, namespace, name string) error -} - -// Workflow defines the root structure of a workflow. -type Workflow struct { - Namespace string `json:"namespace"` - Name string `json:"name"` - Entry string `json:"entry"` // the entry node name -} - -type WorkflowDetail struct { - Workflow `json:",inline"` - Topology Topology `json:"topology"` - Yaml KubeObjectYAMLDescription `json:"yaml,omitempty"` -} - -// Topology describes the process of a workflow. -type Topology struct { - Nodes []Node `json:"nodes"` -} - -type NodeState string - -const ( - NodeRunning NodeState = "Running" - NodeSucceed NodeState = "Succeed" - NodeFailed NodeState = "Failed" -) - -// Node defines the single step of a workflow. -type Node struct { - Name string `json:"name"` - Type NodeType `json:"type"` - State NodeState `json:"state"` - Serial NodeSerial `json:"serial,omitempty"` - Parallel NodeParallel `json:"parallel,omitempty"` - Template string `json:"template"` -} - -// NodeSerial defines SerialNode's specific fields. -type NodeSerial struct { - Tasks []string `json:"tasks"` -} - -// NodeParallel defines ParallelNode's specific fields. -type NodeParallel struct { - Tasks []string `json:"tasks"` -} - -// NodeType defines the type of a workflow node. -// -// There will be five types can be referred as NodeType: Chaos, Serial, Parallel, Suspend, Task. -// -// Const definitions can be found below this type. -type NodeType string - -const ( - // ChaosNode represents a node will perform a single Chaos Experiment. - ChaosNode NodeType = "ChaosNode" - - // SerialNode represents a node that will perform continuous templates. - SerialNode NodeType = "SerialNode" - - // ParallelNode represents a node that will perform parallel templates. - ParallelNode NodeType = "ParallelNode" - - // SuspendNode represents a node that will perform wait operation. - SuspendNode NodeType = "SuspendNode" - - // TaskNode represents a node that will perform user-defined task. - TaskNode NodeType = "TaskNode" -) - -var nodeTypeTemplateTypeMapping = map[v1alpha1.TemplateType]NodeType{ - v1alpha1.TypeSerial: SerialNode, - v1alpha1.TypeParallel: ParallelNode, - v1alpha1.TypeSuspend: SuspendNode, - v1alpha1.TypeTask: TaskNode, -} - -// Detail defines the detail of a workflow. -type Detail struct { - WorkflowUID string `json:"workflow_uid"` - Templates []Template `json:"templates"` -} - -// Template defines a complete structure of a template. -type Template struct { - Name string `json:"name"` - Type string `json:"type"` - Duration string `json:"duration,omitempty"` - Spec interface{} `json:"spec"` -} - -type KubeWorkflowRepository struct { - kubeclient client.Client -} - -func (it *KubeWorkflowRepository) CreateWorkflowWithRaw(ctx context.Context, raw KubeObjectYAMLDescription) (WorkflowDetail, error) { - workflow := v1alpha1.Workflow{ - ObjectMeta: metav1.ObjectMeta{ - Name: raw.Metadata.Name, - Namespace: raw.Metadata.Namespace, - Labels: raw.Metadata.Labels, - Annotations: raw.Metadata.Annotations, - }, - Spec: v1alpha1.WorkflowSpec{}, - } - - err := mapstructure.Decode(raw.Spec, &workflow.Spec) - if err != nil { - return WorkflowDetail{}, err - } - - // TODO: we need decode the inlined field again, it's better to resolve that in a common methods - // TODO: same issue in UpdateWorkflowWithRaw, and http api with experiments - for index := range workflow.Spec.Templates { - switch parsed := raw.Spec.(type) { - case map[string]interface{}: - switch templates := parsed["templates"].(type) { - case []interface{}: - target := v1alpha1.EmbedChaos{} - err := mapstructure.Decode(templates[index], &target) - if err != nil { - return WorkflowDetail{}, err - } - } - - } - } - - err = it.kubeclient.Create(ctx, &workflow) - if err != nil { - return WorkflowDetail{}, err - } - return it.GetWorkflowByNamespacedName(ctx, workflow.Namespace, workflow.Name) -} - -func (it *KubeWorkflowRepository) UpdateWorkflowWithRaw(ctx context.Context, raw KubeObjectYAMLDescription) (WorkflowDetail, error) { - workflow := v1alpha1.Workflow{} - - err := mapstructure.Decode(raw.Spec, &workflow.Spec) - if err != nil { - return WorkflowDetail{}, err - } - - for index := range workflow.Spec.Templates { - switch parsed := raw.Spec.(type) { - case map[string]interface{}: - switch templates := parsed["templates"].(type) { - case []interface{}: - target := v1alpha1.EmbedChaos{} - err := mapstructure.Decode(templates[index], &target) - if err != nil { - return WorkflowDetail{}, err - } - } - - } - } - - err = it.kubeclient.Update(ctx, &workflow) - if err != nil { - return WorkflowDetail{}, err - } - return it.GetWorkflowByNamespacedName(ctx, workflow.Namespace, workflow.Name) -} - -func NewKubeWorkflowRepository(kubeclient client.Client) *KubeWorkflowRepository { - return &KubeWorkflowRepository{kubeclient: kubeclient} -} - -func (it *KubeWorkflowRepository) ListWorkflowWithNamespace(ctx context.Context, namespace string) ([]Workflow, error) { - workflowList := v1alpha1.WorkflowList{} - err := it.kubeclient.List(ctx, &workflowList, &client.ListOptions{ - Namespace: namespace, - }) - if err != nil { - return nil, err - } - - var result []Workflow - for _, item := range workflowList.Items { - result = append(result, conversionWorkflow(item)) - } - - return result, nil -} - -func (it *KubeWorkflowRepository) ListWorkflowFromAllNamespace(ctx context.Context) ([]Workflow, error) { - return it.ListWorkflowWithNamespace(ctx, "") -} - -func (it *KubeWorkflowRepository) GetWorkflowByNamespacedName(ctx context.Context, namespace, name string) (WorkflowDetail, error) { - kubeWorkflow := v1alpha1.Workflow{} - err := it.kubeclient.Get(ctx, types.NamespacedName{ - Namespace: namespace, - Name: name, - }, &kubeWorkflow) - - if err != nil { - return WorkflowDetail{}, err - } - - workflowNodes := v1alpha1.WorkflowNodeList{} - - // labeling workflow nodes, see pkg/workflow/controllers/new_node.go - selector, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{ - MatchLabels: map[string]string{ - v1alpha1.LabelWorkflow: kubeWorkflow.Name, - }, - }) - if err != nil { - return WorkflowDetail{}, err - } - err = it.kubeclient.List(ctx, &workflowNodes, &client.ListOptions{ - Namespace: namespace, - LabelSelector: selector, - }) - if err != nil { - return WorkflowDetail{}, err - } - - return conversionWorkflowDetail(kubeWorkflow, workflowNodes.Items) -} - -func (it *KubeWorkflowRepository) DeleteWorkflowByNamespacedName(ctx context.Context, namespace, name string) error { - kubeWorkflow := v1alpha1.Workflow{} - err := it.kubeclient.Get(ctx, types.NamespacedName{ - Namespace: namespace, - Name: name, - }, &kubeWorkflow) - if err != nil { - return err - } - return it.kubeclient.Delete(ctx, &kubeWorkflow) -} - -func conversionWorkflow(kubeWorkflow v1alpha1.Workflow) Workflow { - result := Workflow{ - Namespace: kubeWorkflow.Namespace, - Name: kubeWorkflow.Name, - Entry: kubeWorkflow.Spec.Entry, - } - return result -} - -func conversionWorkflowDetail(kubeWorkflow v1alpha1.Workflow, kubeNodes []v1alpha1.WorkflowNode) (WorkflowDetail, error) { - nodes := make([]Node, 0) - - for _, item := range kubeNodes { - node, err := conversionWorkflowNode(item) - if err != nil { - return WorkflowDetail{}, nil - } - nodes = append(nodes, node) - } - - result := WorkflowDetail{ - Workflow: conversionWorkflow(kubeWorkflow), - Topology: Topology{ - Nodes: nodes, - }, - } - return result, nil -} - -func conversionWorkflowNode(kubeWorkflowNode v1alpha1.WorkflowNode) (Node, error) { - templateType, err := mappingTemplateType(kubeWorkflowNode.Spec.Type) - if err != nil { - return Node{}, err - } - result := Node{ - Name: kubeWorkflowNode.Name, - Type: templateType, - Serial: NodeSerial{Tasks: []string{}}, - Parallel: NodeParallel{Tasks: []string{}}, - Template: kubeWorkflowNode.Spec.TemplateName, - } - - if kubeWorkflowNode.Spec.Type == v1alpha1.TypeSerial { - result.Serial.Tasks = kubeWorkflowNode.Spec.Tasks - } else if kubeWorkflowNode.Spec.Type == v1alpha1.TypeParallel { - result.Parallel.Tasks = kubeWorkflowNode.Spec.Tasks - } - - // TODO: refactor this - if wfcontrollers.ConditionEqualsTo(kubeWorkflowNode.Status, v1alpha1.ConditionAccomplished, corev1.ConditionTrue) || - wfcontrollers.ConditionEqualsTo(kubeWorkflowNode.Status, v1alpha1.ConditionDeadlineExceed, corev1.ConditionTrue) { - result.State = NodeSucceed - } else { - result.State = NodeRunning - } - - return result, nil -} - -func mappingTemplateType(templateType v1alpha1.TemplateType) (NodeType, error) { - if v1alpha1.IsChoasTemplateType(templateType) { - return ChaosNode, nil - } else if target, ok := nodeTypeTemplateTypeMapping[templateType]; ok { - return target, nil - } else { - return "", errors.Errorf("can not resolve such type called %s", templateType) - } -} diff --git a/pkg/core/workflow_test.go b/pkg/core/workflow_test.go deleted file mode 100644 index 1876d8661f..0000000000 --- a/pkg/core/workflow_test.go +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package core - -import ( - "reflect" - "testing" - - corev1 "k8s.io/api/core/v1" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -func Test_conversionWorkflow(t *testing.T) { - type args struct { - kubeWorkflow v1alpha1.Workflow - } - tests := []struct { - name string - args args - want Workflow - }{ - { - name: "simple workflow", - args: args{ - v1alpha1.Workflow{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "fake-namespace", - Name: "fake-workflow-0", - }, - Spec: v1alpha1.WorkflowSpec{ - Entry: "an-entry", - }, - Status: v1alpha1.WorkflowStatus{}, - }, - }, - want: Workflow{ - Namespace: "fake-namespace", - Name: "fake-workflow-0", - Entry: "an-entry", - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := conversionWorkflow(tt.args.kubeWorkflow); !reflect.DeepEqual(got, tt.want) { - t.Errorf("conversionWorkflow() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_conversionWorkflowDetail(t *testing.T) { - type args struct { - kubeWorkflow v1alpha1.Workflow - kubeNodes []v1alpha1.WorkflowNode - } - tests := []struct { - name string - args args - want WorkflowDetail - wantErr bool - }{ - { - name: "simple workflow detail with no nodes", - args: args{ - kubeWorkflow: v1alpha1.Workflow{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "another-namespace", - Name: "another-fake-workflow", - }, - Spec: v1alpha1.WorkflowSpec{ - Entry: "another-entry", - Templates: nil, - }, - Status: v1alpha1.WorkflowStatus{}, - }, - kubeNodes: nil, - }, - want: WorkflowDetail{ - Workflow: Workflow{ - Namespace: "another-namespace", - Name: "another-fake-workflow", - Entry: "another-entry", - }, - Topology: Topology{ - Nodes: []Node{}, - }, - }, - }, - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := conversionWorkflowDetail(tt.args.kubeWorkflow, tt.args.kubeNodes) - if (err != nil) != tt.wantErr { - t.Errorf("conversionWorkflowDetail() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("conversionWorkflowDetail() got = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_conversionWorkflowNode(t *testing.T) { - type args struct { - kubeWorkflowNode v1alpha1.WorkflowNode - } - tests := []struct { - name string - args args - want Node - wantErr bool - }{ - { - name: "simple node", - args: args{kubeWorkflowNode: v1alpha1.WorkflowNode{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "fake-namespace", - Name: "fake-node-0", - }, - Spec: v1alpha1.WorkflowNodeSpec{ - WorkflowName: "fake-workflow-0", - TemplateName: "fake-template-0", - Type: v1alpha1.TypeJVMChaos, - }, - Status: v1alpha1.WorkflowNodeStatus{}, - }}, - want: Node{ - Name: "fake-node-0", - Type: ChaosNode, - Serial: NodeSerial{[]string{}}, - Parallel: NodeParallel{[]string{}}, - Template: "fake-template-0", - State: NodeRunning, - }, - }, { - name: "serial node", - args: args{ - kubeWorkflowNode: v1alpha1.WorkflowNode{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "fake-namespace", - Name: "fake-serial-node-0", - }, - Spec: v1alpha1.WorkflowNodeSpec{ - TemplateName: "fake-serial-node", - WorkflowName: "fake-workflow-0", - Type: v1alpha1.TypeSerial, - Tasks: []string{"child-0", "child-1"}, - }, - Status: v1alpha1.WorkflowNodeStatus{}, - }, - }, - want: Node{ - Name: "fake-serial-node-0", - Type: SerialNode, - Serial: NodeSerial{ - Tasks: []string{"child-0", "child-1"}, - }, - Parallel: NodeParallel{[]string{}}, - Template: "fake-serial-node", - State: NodeRunning, - }, - }, - { - name: "parallel node", - args: args{ - kubeWorkflowNode: v1alpha1.WorkflowNode{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "fake-namespace", - Name: "parallel-node-0", - }, - Spec: v1alpha1.WorkflowNodeSpec{ - TemplateName: "parallel-node", - WorkflowName: "another-fake-workflow", - Type: v1alpha1.TypeParallel, - Tasks: []string{"child-1", "child-0"}, - }, - Status: v1alpha1.WorkflowNodeStatus{}, - }, - }, - want: Node{ - Name: "parallel-node-0", - Type: ParallelNode, - Serial: NodeSerial{[]string{}}, - Parallel: NodeParallel{ - Tasks: []string{"child-1", "child-0"}, - }, - Template: "parallel-node", - State: NodeRunning, - }, - }, - { - name: "some chaos", - args: args{ - kubeWorkflowNode: v1alpha1.WorkflowNode{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "fake-namespace", - Name: "io-chaos-0", - }, - Spec: v1alpha1.WorkflowNodeSpec{ - TemplateName: "io-chaos", - WorkflowName: "another-workflow-0", - Type: v1alpha1.TypeIoChaos, - EmbedChaos: &v1alpha1.EmbedChaos{ - IoChaos: &v1alpha1.IoChaosSpec{ - Mode: v1alpha1.OnePodMode, - Action: "delay", - Delay: "100ms", - Path: "/fake/path", - Percent: 100, - VolumePath: "/fake/path", - }, - }, - }, - Status: v1alpha1.WorkflowNodeStatus{}, - }, - }, - want: Node{ - Name: "io-chaos-0", - Type: ChaosNode, - Serial: NodeSerial{[]string{}}, - Parallel: NodeParallel{[]string{}}, - Template: "io-chaos", - State: NodeRunning, - }, - }, - { - name: "accomplished node", - args: args{ - kubeWorkflowNode: v1alpha1.WorkflowNode{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "fake-namespace", - Name: "the-entry-0", - }, - Spec: v1alpha1.WorkflowNodeSpec{ - TemplateName: "the-entry", - WorkflowName: "fake-workflow-0", - Type: v1alpha1.TypeSerial, - Tasks: []string{"unimportant-task-0"}, - }, - Status: v1alpha1.WorkflowNodeStatus{ - Conditions: []v1alpha1.WorkflowNodeCondition{ - { - Type: v1alpha1.ConditionAccomplished, - Status: corev1.ConditionTrue, - Reason: "unit test mocked true", - }, - }, - }, - }, - }, - want: Node{ - Name: "the-entry-0", - Type: SerialNode, - State: NodeSucceed, - Serial: NodeSerial{ - Tasks: []string{"unimportant-task-0"}, - }, - Parallel: NodeParallel{ - Tasks: []string{}, - }, - Template: "the-entry", - }, - }, - { - name: "deadline exceed node", - args: args{kubeWorkflowNode: v1alpha1.WorkflowNode{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "fake-namespace", - Name: "deadline-exceed-node-0", - }, - Spec: v1alpha1.WorkflowNodeSpec{ - TemplateName: "deadline-exceed-node", - WorkflowName: "some-workflow", - Type: v1alpha1.TypePodChaos, - }, - Status: v1alpha1.WorkflowNodeStatus{ - Conditions: []v1alpha1.WorkflowNodeCondition{ - { - Type: v1alpha1.ConditionDeadlineExceed, - Status: corev1.ConditionTrue, - Reason: "unit test mocked true", - }, - }, - }, - }}, - want: Node{ - Name: "deadline-exceed-node-0", - Type: ChaosNode, - State: NodeSucceed, - Serial: NodeSerial{ - Tasks: []string{}, - }, - Parallel: NodeParallel{ - Tasks: []string{}, - }, - Template: "deadline-exceed-node", - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := conversionWorkflowNode(tt.args.kubeWorkflowNode) - if (err != nil) != tt.wantErr { - t.Errorf("conversionWorkflowNode() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("conversionWorkflowNode() got = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/ctrl/client/ctrlclient.go b/pkg/ctrl/client/ctrlclient.go new file mode 100644 index 0000000000..606b6eb0f5 --- /dev/null +++ b/pkg/ctrl/client/ctrlclient.go @@ -0,0 +1,54 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package client + +import ( + "context" + + "github.com/hasura/go-graphql-client" +) + +type CtrlClient struct { + QueryClient *graphql.Client + SubscriptionClient *graphql.SubscriptionClient +} + +func NewCtrlClient(url string) *CtrlClient { + return &CtrlClient{ + QueryClient: graphql.NewClient(url, nil), + SubscriptionClient: graphql.NewSubscriptionClient(url), + } +} + +func (c *CtrlClient) ListNamespace(ctx context.Context) ([]string, error) { + namespaceQuery := new(struct { + Namespace []struct { + Ns string + } + }) + + err := c.QueryClient.Query(ctx, namespaceQuery, nil) + if err != nil { + return nil, err + } + + var namespaces []string + for _, ns := range namespaceQuery.Namespace { + namespaces = append(namespaces, ns.Ns) + } + + return namespaces, nil +} diff --git a/pkg/ctrl/client/forward.go b/pkg/ctrl/client/forward.go new file mode 100644 index 0000000000..31c8258abf --- /dev/null +++ b/pkg/ctrl/client/forward.go @@ -0,0 +1,68 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package client + +import ( + "context" + + "github.com/pkg/errors" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client/config" + + "github.com/chaos-mesh/chaos-mesh/pkg/log" + "github.com/chaos-mesh/chaos-mesh/pkg/portforward" +) + +const ( + CtrlServerPort = 10082 +) + +// CommonRestClientGetter is used for non-e2e test environment. +// It's basically do the same thing as genericclioptions.ConfigFlags, but it load rest config from incluster or .kubeconfig file +type CommonRestClientGetter struct { + *genericclioptions.ConfigFlags +} + +func NewCommonRestClientGetter() *CommonRestClientGetter { + innerConfigFlags := genericclioptions.NewConfigFlags(false) + return &CommonRestClientGetter{innerConfigFlags} +} + +func (it *CommonRestClientGetter) ToRESTConfig() (*rest.Config, error) { + return config.GetConfig() +} + +func ForwardSvcPorts(ctx context.Context, ns, svc string, port uint16) (context.CancelFunc, uint16, error) { + commonRestClientGetter := NewCommonRestClientGetter() + logger, err := log.NewDefaultZapLogger() + if err != nil { + return nil, 0, errors.Wrap(err, "failed to create logger") + } + fw, err := portforward.NewPortForwarder(ctx, commonRestClientGetter, false, logger) + if err != nil { + return nil, 0, errors.Wrap(err, "failed to create port forwarder") + } + _, localPort, pfCancel, err := portforward.ForwardOnePort(fw, ns, svc, port) + + // disable error handler in k8s runtime to prevent complaining from port forwarder + DisableRuntimeErrorHandler() + return pfCancel, localPort, err +} + +func ForwardCtrlServer(ctx context.Context, ns, managerSvc string) (context.CancelFunc, uint16, error) { + return ForwardSvcPorts(ctx, ns, "svc/"+managerSvc, CtrlServerPort) +} diff --git a/pkg/ctrl/client/hack.go b/pkg/ctrl/client/hack.go new file mode 100644 index 0000000000..0956f78a32 --- /dev/null +++ b/pkg/ctrl/client/hack.go @@ -0,0 +1,24 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package client + +import "k8s.io/apimachinery/pkg/util/runtime" + +// disable error handler in k8s runtime +// TODO: ignore specific errors only +func DisableRuntimeErrorHandler() { + runtime.ErrorHandlers = nil +} diff --git a/pkg/ctrl/client/iptables.go b/pkg/ctrl/client/iptables.go new file mode 100644 index 0000000000..3457824f8d --- /dev/null +++ b/pkg/ctrl/client/iptables.go @@ -0,0 +1,47 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package client + +import ( + "context" + + "github.com/hasura/go-graphql-client" + "github.com/pkg/errors" +) + +func (c *CtrlClient) CleanIptables(ctx context.Context, namespace, name string, chains []string) ([]string, error) { + var graphqlChains []graphql.String + for _, chain := range chains { + graphqlChains = append(graphqlChains, graphql.String(chain)) + } + var mutation struct { + Pod struct { + CleanIptables []string `graphql:"cleanIptables(chains: $chains)"` + } `graphql:"pod(ns: $ns, name: $name)"` + } + + err := c.QueryClient.Mutate(ctx, &mutation, map[string]interface{}{ + "chains": graphqlChains, + "ns": graphql.String(namespace), + "name": graphql.String(name), + }) + + if err != nil { + return nil, errors.Wrapf(err, "cleaned iptables rules for chains %v", chains) + } + + return mutation.Pod.CleanIptables, nil +} diff --git a/pkg/ctrl/client/process.go b/pkg/ctrl/client/process.go new file mode 100644 index 0000000000..903dad63a2 --- /dev/null +++ b/pkg/ctrl/client/process.go @@ -0,0 +1,53 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package client + +import ( + "context" + + "github.com/hasura/go-graphql-client" + "github.com/pkg/errors" +) + +func (c *CtrlClient) KillProcesses(ctx context.Context, namespace, name string, pids []string) ([]string, error) { + var graphqlPids []graphql.String + for _, p := range pids { + graphqlPids = append(graphqlPids, graphql.String(p)) + } + var mutation struct { + Pod struct { + KillProcesses []struct { + Pid, Command string + } `graphql:"killProcesses(pids: $pids)"` + } `graphql:"pod(ns: $ns, name: $name)"` + } + + err := c.QueryClient.Mutate(ctx, &mutation, map[string]interface{}{ + "pids": graphqlPids, + "ns": graphql.String(namespace), + "name": graphql.String(name), + }) + + if err != nil { + return nil, errors.Wrapf(err, "kill processes(%v)", pids) + } + + var killedPids []string + for _, p := range mutation.Pod.KillProcesses { + killedPids = append(killedPids, p.Pid) + } + return killedPids, nil +} diff --git a/pkg/ctrl/client/tcs.go b/pkg/ctrl/client/tcs.go new file mode 100644 index 0000000000..8f40af7730 --- /dev/null +++ b/pkg/ctrl/client/tcs.go @@ -0,0 +1,47 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package client + +import ( + "context" + + "github.com/hasura/go-graphql-client" + "github.com/pkg/errors" +) + +func (c *CtrlClient) CleanTcs(ctx context.Context, namespace, name string, devices []string) ([]string, error) { + var graphqlDevices []graphql.String + for _, dev := range devices { + graphqlDevices = append(graphqlDevices, graphql.String(dev)) + } + var mutation struct { + Pod struct { + CleanTcs []string `graphql:"cleanTcs(devices: $devices)"` + } `graphql:"pod(ns: $ns, name: $name)"` + } + + err := c.QueryClient.Mutate(ctx, &mutation, map[string]interface{}{ + "devices": graphqlDevices, + "ns": graphql.String(namespace), + "name": graphql.String(name), + }) + + if err != nil { + return nil, errors.Wrapf(err, "cleaned tc rules for device %v", devices) + } + + return mutation.Pod.CleanTcs, nil +} diff --git a/pkg/ctrl/gqlgen.yml b/pkg/ctrl/gqlgen.yml new file mode 100644 index 0000000000..9085d0e23e --- /dev/null +++ b/pkg/ctrl/gqlgen.yml @@ -0,0 +1,72 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Where are all the schema files located? globs are supported eg src/**/*.graphqls +schema: + - server/*.graphqls + +# Where should the generated server code go? +exec: + filename: server/generated/generated.go + package: generated + +# Uncomment to enable federation +# federation: +# filename: graph/generated/federation.go +# package: generated + +# Where should any generated models go? +model: + filename: server/model/models_gen.go + package: model + +# Where should the resolver implementations go? +resolver: + layout: follow-schema + dir: server + package: server + +# Optional: turn on use `gqlgen:"fieldName"` tags in your models +# struct_tag: json + +# Optional: turn on to use []Thing instead of []*Thing +# omit_slice_element_pointers: false + +# Optional: set to speed up generation time by not performing a final validation pass. +# skip_validation: true + +# gqlgen will search for any type names in the schema in these go packages +# if they match it will use them, otherwise it will generate them. +autobind: + +# This section declares type mapping between the GraphQL and go type systems +# +# The first line in each type will be used as defaults for resolver arguments and +# modelgen, the others will be allowed when binding to fields. Configure them to +# your liking +models: + ID: + model: + - github.com/99designs/gqlgen/graphql.ID + - github.com/99designs/gqlgen/graphql.Int + - github.com/99designs/gqlgen/graphql.Int64 + - github.com/99designs/gqlgen/graphql.Int32 + Int: + model: + - github.com/99designs/gqlgen/graphql.Int + - github.com/99designs/gqlgen/graphql.Int64 + - github.com/99designs/gqlgen/graphql.Int32 + Int64: + model: + - github.com/99designs/gqlgen/graphql.Int64 diff --git a/pkg/ctrl/server.go b/pkg/ctrl/server.go new file mode 100644 index 0000000000..68047dd208 --- /dev/null +++ b/pkg/ctrl/server.go @@ -0,0 +1,49 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package ctrl + +import ( + "github.com/99designs/gqlgen/graphql/handler" + "github.com/go-logr/logr" + "go.uber.org/fx" + "k8s.io/client-go/kubernetes" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon" + "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server" + "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/generated" +) + +type ServerParams struct { + fx.In + + NoCacheReader client.Reader `name:"no-cache"` + Logger logr.Logger + Client client.Client + Clientset *kubernetes.Clientset + DaemonClientBuilder *chaosdaemon.ChaosDaemonClientBuilder +} + +func New(param ServerParams) *handler.Server { + resolvers := &server.Resolver{ + DaemonHelper: &server.DaemonHelper{Builder: param.DaemonClientBuilder}, + Log: param.Logger.WithName("ctrl-server"), + Client: param.Client, + Clientset: param.Clientset, + NoCacheReader: param.NoCacheReader, + } + return handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: resolvers})) +} diff --git a/pkg/ctrl/server/cgroup.go b/pkg/ctrl/server/cgroup.go new file mode 100644 index 0000000000..03e028ae26 --- /dev/null +++ b/pkg/ctrl/server/cgroup.go @@ -0,0 +1,154 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package server + +import ( + "context" + "fmt" + "regexp" + "strconv" + "strings" + + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/pkg/bpm" + "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/model" +) + +// GetCgroups returns result of cat /proc/cgroups +func (r *Resolver) GetCgroups(ctx context.Context, obj *model.PodStressChaos) (*model.Cgroups, error) { + cmd := "cat /proc/cgroups" + + // the raw looks like: + // ``` + // #subsys_name hierarchy num_cgroups enabled + // cpuset 0 127 1 + // cpu 0 127 1 + // cpuacct 0 127 1 + // blkio 0 127 1 + // memory 0 127 1 + // devices 0 127 1 + // freezer 0 127 1 + // net_cls 0 127 1 + // perf_event 0 127 1 + // net_prio 0 127 1 + // hugetlb 0 127 1 + // pids 0 127 1 + // rdma 0 127 1 + // misc 0 127 1 + // ``` + raw, err := r.ExecBypass(ctx, obj.Pod, cmd, bpm.PidNS, bpm.MountNS) + + if err != nil { + return nil, err + } + + cgroups := &model.Cgroups{ + Raw: raw, + } + + // no more info for StressngStressors + if obj.StressChaos.Spec.StressngStressors != "" || obj.StressChaos.Spec.Stressors == nil { + return cgroups, nil + } + + isCPU := true + if obj.StressChaos.Spec.Stressors.CPUStressor == nil { + isCPU = false + } + + if isCPU { + var cpuMountType string + if regexp.MustCompile("(cpu,cpuacct)").MatchString(string(raw)) { + cpuMountType = "cpu,cpuacct" + } else { + // cgroup does not support cpuacct sub-system + cpuMountType = "cpu" + } + cgroups.CPU = &model.CgroupsCPU{} + cgroups.CPU.Quota, err = r.GetCPUQuota(ctx, obj.Pod, cpuMountType) + if err != nil { + return nil, err + } + cgroups.CPU.Period, err = r.GetCPUPeriod(ctx, obj.Pod, cpuMountType) + if err != nil { + return nil, err + } + } else { + cgroups.Memory = &model.CgroupsMemory{} + cgroups.Memory.Limit, err = r.GetMemoryLimit(ctx, obj.Pod) + if err != nil { + return nil, err + } + } + + return cgroups, nil +} + +// GetCgroup returns result of cat /proc/:pid/cgroup +// The output looks like: +// ``` +// 11:freezer:/ +// 10:hugetlb:/ +// 9:memory:/system.slice/sshd.service +// 8:pids:/system.slice/sshd.service +// 7:perf_event:/ +// 6:net_cls,net_prio:/ +// 5:devices:/system.slice/sshd.service +// 4:blkio:/system.slice/sshd.service +// 3:cpu,cpuacct:/system.slice/sshd.service +// 2:cpuset:/ +// 1:name=systemd:/system.slice/sshd.service +// ``` +func (r *Resolver) GetCgroup(ctx context.Context, obj *v1.Pod, pid string) (string, error) { + cmd := fmt.Sprintf("cat /proc/%s/cgroup", pid) + return r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.MountNS) +} + +// GetCPUQuota returns result of cat /sys/fs/cgroup/:cpuMountType/cpu.cfs_quota_us +func (r *Resolver) GetCPUQuota(ctx context.Context, obj *v1.Pod, cpuMountType string) (int, error) { + cmd := fmt.Sprintf("cat /sys/fs/cgroup/%s/cpu.cfs_quota_us", cpuMountType) + out, err := r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.MountNS) + if err != nil { + return 0, err + } + return strconv.Atoi(strings.TrimSuffix(string(out), "\n")) +} + +// GetCPUPeriod returns result of cat /sys/fs/cgroup/:cpuMountType/cpu.cfs_period_us +func (r *Resolver) GetCPUPeriod(ctx context.Context, obj *v1.Pod, cpuMountType string) (int, error) { + cmd := fmt.Sprintf("cat /sys/fs/cgroup/%s/cpu.cfs_period_us", cpuMountType) + out, err := r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.MountNS) + if err != nil { + return 0, err + } + return strconv.Atoi(strings.TrimSuffix(string(out), "\n")) +} + +// GetMemoryLimit returns result of cat /sys/fs/cgroup/memory/memory.limit_in_bytes +func (r *Resolver) GetMemoryLimit(ctx context.Context, obj *v1.Pod) (int64, error) { + cmd := "cat /sys/fs/cgroup/memory/memory.limit_in_bytes" + rawLimit, err := r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.MountNS) + if err != nil { + return 0, errors.Wrap(err, "could not get memory.limit_in_bytes") + } + limit, err := strconv.ParseUint(strings.TrimSuffix(rawLimit, "\n"), 10, 64) + if err != nil { + return 0, errors.Wrap(err, "could not parse memory.limit_in_bytes") + } + return int64(limit), nil +} diff --git a/pkg/ctrl/server/daemon.go b/pkg/ctrl/server/daemon.go new file mode 100644 index 0000000000..ca17ff4461 --- /dev/null +++ b/pkg/ctrl/server/daemon.go @@ -0,0 +1,56 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package server + +import ( + "context" + + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" +) + +type DaemonHelper struct { + Builder *chaosdaemon.ChaosDaemonClientBuilder +} + +// GetPidFromPod returns pid given containerd ID in pod +func (h *DaemonHelper) GetPidFromPod(ctx context.Context, pod *v1.Pod) (uint32, error) { + daemonClient, err := h.Builder.Build(ctx, pod, nil) + if err != nil { + return 0, errors.Wrapf(err, "failed to craete new chaos daemon client of pod(%s/%s)", pod.Namespace, pod.Name) + } + defer daemonClient.Close() + + if len(pod.Status.ContainerStatuses) == 0 { + err = errors.Wrapf(utils.ErrContainerNotFound, "pod %s/%s has empty container status", pod.Namespace, pod.Name) + return 0, err + } + + res, err := daemonClient.ContainerGetPid(ctx, &pb.ContainerRequest{ + Action: &pb.ContainerAction{ + Action: pb.ContainerAction_GETPID, + }, + ContainerId: pod.Status.ContainerStatuses[0].ContainerID, + }) + if err != nil { + return 0, errors.Wrapf(err, "failed get pid from pod %s/%s", pod.GetNamespace(), pod.GetName()) + } + return res.Pid, nil +} diff --git a/pkg/ctrl/server/exec.go b/pkg/ctrl/server/exec.go new file mode 100644 index 0000000000..8cd608228e --- /dev/null +++ b/pkg/ctrl/server/exec.go @@ -0,0 +1,109 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package server + +import ( + "bytes" + "context" + "io" + "strings" + + "github.com/pkg/errors" + "google.golang.org/grpc/grpclog" + v1 "k8s.io/api/core/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/remotecommand" + kubectlscheme "k8s.io/kubectl/pkg/scheme" + "sigs.k8s.io/controller-runtime/pkg/client/config" + + "github.com/chaos-mesh/chaos-mesh/pkg/bpm" +) + +// exec executes certain command and returns the result +// Only commands in chaos-mesh components should use this way +// for target pod, use ExecBypass +func exec(ctx context.Context, pod *v1.Pod, cmd string, c *kubernetes.Clientset) (string, error) { + name := pod.GetObjectMeta().GetName() + namespace := pod.GetObjectMeta().GetNamespace() + // TODO: if `containerNames` is set and specific container is injected chaos, + // need to use THE name rather than the first one. + // till 20/11/10 only podchaos and kernelchaos support `containerNames`, so not set it for now + containerName := pod.Spec.Containers[0].Name + + req := c.CoreV1().RESTClient().Post(). + Resource("pods"). + Name(name). + Namespace(namespace). + SubResource("exec") + + req.VersionedParams(&v1.PodExecOptions{ + Container: containerName, + Command: []string{"/bin/sh", "-c", cmd}, + Stdin: false, + Stdout: true, + Stderr: true, + TTY: false, + }, kubectlscheme.ParameterCodec) + + var stdout, stderr bytes.Buffer + exec, err := remotecommand.NewSPDYExecutor(config.GetConfigOrDie(), "POST", req.URL()) + if err != nil { + return "", errors.Wrapf(err, "error in creating NewSPDYExecutor for pod %s/%s", pod.GetNamespace(), pod.GetName()) + } + err = exec.StreamWithContext(ctx, remotecommand.StreamOptions{ + Stdin: nil, + Stdout: &stdout, + Stderr: &stderr, + }) + if err != nil { + if stderr.String() != "" { + return "", errors.Errorf("error: %s\npod: %s\ncommand: %s", strings.TrimSuffix(stderr.String(), "\n"), pod.Name, cmd) + } + return "", errors.Wrapf(err, "error in streaming remotecommand: pod: %s/%s, command: %s", pod.GetNamespace(), pod.Name, cmd) + } + if stderr.String() != "" { + return "", errors.Errorf("error of command %s: %s", cmd, stderr.String()) + } + return stdout.String(), nil +} + +// ExecBypass use chaos-daemon to enter namespace and execute command in target pod +func (r *Resolver) ExecBypass(ctx context.Context, pod *v1.Pod, cmd string, nsTypes ...bpm.NsType) (string, error) { + // To disable printing irrelevant log from grpc/clientconn.go + // See grpc/grpc-go#3918 for detail. Could be resolved in the future + grpclog.SetLoggerV2(grpclog.NewLoggerV2(io.Discard, io.Discard, io.Discard)) + pid, err := r.GetPidFromPod(ctx, pod) + if err != nil { + return "", err + } + + podResolver := &podResolver{Resolver: r} + daemon, err := podResolver.Daemon(ctx, pod) + if err != nil { + return "", err + } + + cmdBuilder := bpm.DefaultProcessBuilder(cmd) + for _, nsType := range nsTypes { + cmdBuilder = cmdBuilder.SetNS(pid, nsType) + } + + return exec( + ctx, daemon, + cmdBuilder.EnableLocalMnt().SetContext(ctx).Build(ctx).Cmd.String(), + r.Clientset, + ) +} diff --git a/pkg/ctrl/server/fd.go b/pkg/ctrl/server/fd.go new file mode 100644 index 0000000000..7075615025 --- /dev/null +++ b/pkg/ctrl/server/fd.go @@ -0,0 +1,60 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package server + +import ( + "context" + "fmt" + "strings" + + "github.com/chaos-mesh/chaos-mesh/pkg/bpm" + "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/model" +) + +// GetFdsOfProcess returns fd-target pairs. +// The output looks like: +// ``` +// total 0 +// lrwx------ 1 docker docker 64 Mar 3 16:11 0 -> /dev/pts/0 +// lrwx------ 1 docker docker 64 Mar 3 16:11 1 -> /dev/pts/0 +// lrwx------ 1 docker docker 64 Mar 3 16:11 2 -> /dev/pts/0 +// lr-x------ 1 docker docker 64 Mar 3 16:11 3 -> /proc/642108/fd +// ``` +func (r *Resolver) GetFdsOfProcess(ctx context.Context, process *model.Process) []*model.Fd { + cmd := fmt.Sprintf("ls -l /proc/%s/fd", process.Pid) + out, err := r.ExecBypass(ctx, process.Pod, cmd, bpm.PidNS, bpm.MountNS) + if err != nil { + // errors often occur on some short-life process, ignored + r.Log.Error(err, "get fds of process", "pid", process.Pid) + return nil + } + var fds []*model.Fd + for _, line := range strings.Split(out, "\n") { + fields := strings.Fields(line) + length := len(fields) + if length < 3 { + // skip + continue + } + fd := &model.Fd{ + Fd: fields[length-3], + Target: fields[length-1], + } + fds = append(fds, fd) + } + + return fds +} diff --git a/pkg/ctrl/server/generated/generated.go b/pkg/ctrl/server/generated/generated.go new file mode 100644 index 0000000000..af4bc82f39 --- /dev/null +++ b/pkg/ctrl/server/generated/generated.go @@ -0,0 +1,32009 @@ +// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. + +package generated + +import ( + "bytes" + "context" + "errors" + "io" + "strconv" + "sync" + "sync/atomic" + "time" + + "github.com/99designs/gqlgen/graphql" + "github.com/99designs/gqlgen/graphql/introspection" + gqlparser "github.com/vektah/gqlparser/v2" + "github.com/vektah/gqlparser/v2/ast" + v1 "k8s.io/api/core/v1" + v11 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/model" +) + +// region ************************** generated!.gotpl ************************** + +// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. +func NewExecutableSchema(cfg Config) graphql.ExecutableSchema { + return &executableSchema{ + resolvers: cfg.Resolvers, + directives: cfg.Directives, + complexity: cfg.Complexity, + } +} + +type Config struct { + Resolvers ResolverRoot + Directives DirectiveRoot + Complexity ComplexityRoot +} + +type ResolverRoot interface { + AttrOverrideSpec() AttrOverrideSpecResolver + BandwidthSpec() BandwidthSpecResolver + ChaosCondition() ChaosConditionResolver + CidrAndPort() CidrAndPortResolver + ContainerStateRunning() ContainerStateRunningResolver + ContainerStateTerminated() ContainerStateTerminatedResolver + ExperimentStatus() ExperimentStatusResolver + HTTPChaos() HTTPChaosResolver + HTTPChaosSpec() HTTPChaosSpecResolver + HTTPChaosStatus() HTTPChaosStatusResolver + IOChaos() IOChaosResolver + IOChaosAction() IOChaosActionResolver + IOChaosSpec() IOChaosSpecResolver + IOChaosStatus() IOChaosStatusResolver + IoFault() IoFaultResolver + Logger() LoggerResolver + MistakeSpec() MistakeSpecResolver + MutablePod() MutablePodResolver + Mutation() MutationResolver + Namespace() NamespaceResolver + NetworkChaos() NetworkChaosResolver + OwnerReference() OwnerReferenceResolver + Pod() PodResolver + PodCondition() PodConditionResolver + PodHTTPChaos() PodHTTPChaosResolver + PodHttpChaosReplaceActions() PodHttpChaosReplaceActionsResolver + PodHttpChaosRule() PodHttpChaosRuleResolver + PodHttpChaosSelector() PodHttpChaosSelectorResolver + PodIOChaos() PodIOChaosResolver + PodNetworkChaos() PodNetworkChaosResolver + PodSelectorSpec() PodSelectorSpecResolver + PodStatus() PodStatusResolver + PodStressChaos() PodStressChaosResolver + Process() ProcessResolver + Query() QueryResolver + RawIPSet() RawIPSetResolver + RawIptables() RawIptablesResolver + RawTrafficControl() RawTrafficControlResolver + Record() RecordResolver + StressChaos() StressChaosResolver + StressChaosSpec() StressChaosSpecResolver + StressChaosStatus() StressChaosStatusResolver +} + +type DirectiveRoot struct { +} + +type ComplexityRoot struct { + AttrOverrideSpec struct { + Atime func(childComplexity int) int + Blocks func(childComplexity int) int + Ctime func(childComplexity int) int + Gid func(childComplexity int) int + Ino func(childComplexity int) int + Kind func(childComplexity int) int + Mtime func(childComplexity int) int + Nlink func(childComplexity int) int + Perm func(childComplexity int) int + Rdev func(childComplexity int) int + Size func(childComplexity int) int + UID func(childComplexity int) int + } + + BandwidthSpec struct { + Buffer func(childComplexity int) int + Limit func(childComplexity int) int + Minburst func(childComplexity int) int + Peakrate func(childComplexity int) int + Rate func(childComplexity int) int + } + + CPUStressor struct { + Load func(childComplexity int) int + Options func(childComplexity int) int + Workers func(childComplexity int) int + } + + Cgroups struct { + CPU func(childComplexity int) int + Memory func(childComplexity int) int + Raw func(childComplexity int) int + } + + CgroupsCpu struct { + Period func(childComplexity int) int + Quota func(childComplexity int) int + } + + CgroupsMemory struct { + Limit func(childComplexity int) int + } + + ChaosCondition struct { + Reason func(childComplexity int) int + Status func(childComplexity int) int + Type func(childComplexity int) int + } + + CidrAndPort struct { + Cidr func(childComplexity int) int + Port func(childComplexity int) int + } + + ContainerState struct { + Running func(childComplexity int) int + Terminated func(childComplexity int) int + Waiting func(childComplexity int) int + } + + ContainerStateRunning struct { + StartedAt func(childComplexity int) int + } + + ContainerStateTerminated struct { + ContainerID func(childComplexity int) int + ExitCode func(childComplexity int) int + FinishedAt func(childComplexity int) int + Message func(childComplexity int) int + Reason func(childComplexity int) int + Signal func(childComplexity int) int + StartedAt func(childComplexity int) int + } + + ContainerStateWaiting struct { + Message func(childComplexity int) int + Reason func(childComplexity int) int + } + + ContainerStatus struct { + ContainerID func(childComplexity int) int + Image func(childComplexity int) int + ImageID func(childComplexity int) int + LastTerminationState func(childComplexity int) int + Name func(childComplexity int) int + Ready func(childComplexity int) int + RestartCount func(childComplexity int) int + Started func(childComplexity int) int + State func(childComplexity int) int + } + + CorruptSpec struct { + Correlation func(childComplexity int) int + Corrupt func(childComplexity int) int + } + + DelaySpec struct { + Correlation func(childComplexity int) int + Jitter func(childComplexity int) int + Latency func(childComplexity int) int + Reorder func(childComplexity int) int + } + + DuplicateSpec struct { + Correlation func(childComplexity int) int + Duplicate func(childComplexity int) int + } + + ExperimentStatus struct { + DesiredPhase func(childComplexity int) int + Records func(childComplexity int) int + } + + Fd struct { + Fd func(childComplexity int) int + Target func(childComplexity int) int + } + + HTTPChaos struct { + APIVersion func(childComplexity int) int + Annotations func(childComplexity int) int + CreationTimestamp func(childComplexity int) int + DeletionGracePeriodSeconds func(childComplexity int) int + DeletionTimestamp func(childComplexity int) int + Finalizers func(childComplexity int) int + GenerateName func(childComplexity int) int + Generation func(childComplexity int) int + Kind func(childComplexity int) int + Labels func(childComplexity int) int + Name func(childComplexity int) int + Namespace func(childComplexity int) int + OwnerReferences func(childComplexity int) int + Podhttp func(childComplexity int) int + ResourceVersion func(childComplexity int) int + SelfLink func(childComplexity int) int + Spec func(childComplexity int) int + Status func(childComplexity int) int + UID func(childComplexity int) int + } + + HTTPChaosSpec struct { + Abort func(childComplexity int) int + Code func(childComplexity int) int + Delay func(childComplexity int) int + Duration func(childComplexity int) int + Method func(childComplexity int) int + Mode func(childComplexity int) int + Patch func(childComplexity int) int + Path func(childComplexity int) int + Port func(childComplexity int) int + Replace func(childComplexity int) int + RequestHeaders func(childComplexity int) int + ResponseHeaders func(childComplexity int) int + Selector func(childComplexity int) int + Target func(childComplexity int) int + Value func(childComplexity int) int + } + + HTTPChaosStatus struct { + Conditions func(childComplexity int) int + Experiment func(childComplexity int) int + Instances func(childComplexity int) int + } + + IOChaos struct { + APIVersion func(childComplexity int) int + Annotations func(childComplexity int) int + CreationTimestamp func(childComplexity int) int + DeletionGracePeriodSeconds func(childComplexity int) int + DeletionTimestamp func(childComplexity int) int + Finalizers func(childComplexity int) int + GenerateName func(childComplexity int) int + Generation func(childComplexity int) int + Kind func(childComplexity int) int + Labels func(childComplexity int) int + Name func(childComplexity int) int + Namespace func(childComplexity int) int + OwnerReferences func(childComplexity int) int + Podios func(childComplexity int) int + ResourceVersion func(childComplexity int) int + SelfLink func(childComplexity int) int + Spec func(childComplexity int) int + Status func(childComplexity int) int + UID func(childComplexity int) int + } + + IOChaosAction struct { + Atime func(childComplexity int) int + Blocks func(childComplexity int) int + Ctime func(childComplexity int) int + Faults func(childComplexity int) int + Filling func(childComplexity int) int + Gid func(childComplexity int) int + Ino func(childComplexity int) int + Kind func(childComplexity int) int + Latency func(childComplexity int) int + MaxLength func(childComplexity int) int + MaxOccurrences func(childComplexity int) int + Methods func(childComplexity int) int + Mtime func(childComplexity int) int + Nlink func(childComplexity int) int + Path func(childComplexity int) int + Percent func(childComplexity int) int + Perm func(childComplexity int) int + Rdev func(childComplexity int) int + Size func(childComplexity int) int + Source func(childComplexity int) int + Type func(childComplexity int) int + UID func(childComplexity int) int + } + + IOChaosSpec struct { + Action func(childComplexity int) int + Attr func(childComplexity int) int + ContainerNames func(childComplexity int) int + Delay func(childComplexity int) int + Duration func(childComplexity int) int + Errno func(childComplexity int) int + Methods func(childComplexity int) int + Mistake func(childComplexity int) int + Mode func(childComplexity int) int + Path func(childComplexity int) int + Percent func(childComplexity int) int + Selector func(childComplexity int) int + Value func(childComplexity int) int + VolumePath func(childComplexity int) int + } + + IOChaosStatus struct { + Conditions func(childComplexity int) int + Experiment func(childComplexity int) int + Instances func(childComplexity int) int + } + + IoFault struct { + Errno func(childComplexity int) int + Weight func(childComplexity int) int + } + + KillProcessResult struct { + Command func(childComplexity int) int + Pid func(childComplexity int) int + } + + Logger struct { + Component func(childComplexity int, ns string, component model.Component) int + Pod func(childComplexity int, ns string, name string) int + } + + LossSpec struct { + Correlation func(childComplexity int) int + Loss func(childComplexity int) int + } + + MemoryStressor struct { + Options func(childComplexity int) int + Size func(childComplexity int) int + Workers func(childComplexity int) int + } + + MistakeSpec struct { + Filling func(childComplexity int) int + MaxLength func(childComplexity int) int + MaxOccurrences func(childComplexity int) int + } + + MutablePod struct { + CleanIptables func(childComplexity int, chains []string) int + CleanTcs func(childComplexity int, devices []string) int + KillProcesses func(childComplexity int, pids []string) int + Pod func(childComplexity int) int + } + + Mutation struct { + Pod func(childComplexity int, ns string, name string) int + } + + Namespace struct { + Component func(childComplexity int, component model.Component) int + Httpchaos func(childComplexity int, name *string) int + Iochaos func(childComplexity int, name *string) int + Networkchaos func(childComplexity int, name *string) int + Ns func(childComplexity int) int + Pod func(childComplexity int, name *string) int + Podhttpchaos func(childComplexity int, name *string) int + Podiochaos func(childComplexity int, name *string) int + Podnetworkchaos func(childComplexity int, name *string) int + Stresschaos func(childComplexity int, name *string) int + } + + NetworkChaos struct { + APIVersion func(childComplexity int) int + Annotations func(childComplexity int) int + CreationTimestamp func(childComplexity int) int + DeletionGracePeriodSeconds func(childComplexity int) int + DeletionTimestamp func(childComplexity int) int + Finalizers func(childComplexity int) int + GenerateName func(childComplexity int) int + Generation func(childComplexity int) int + Kind func(childComplexity int) int + Labels func(childComplexity int) int + Name func(childComplexity int) int + Namespace func(childComplexity int) int + OwnerReferences func(childComplexity int) int + Podnetwork func(childComplexity int) int + ResourceVersion func(childComplexity int) int + SelfLink func(childComplexity int) int + UID func(childComplexity int) int + } + + OwnerReference struct { + APIVersion func(childComplexity int) int + BlockOwnerDeletion func(childComplexity int) int + Controller func(childComplexity int) int + Kind func(childComplexity int) int + Name func(childComplexity int) int + UID func(childComplexity int) int + } + + Pod struct { + APIVersion func(childComplexity int) int + Annotations func(childComplexity int) int + CreationTimestamp func(childComplexity int) int + Daemon func(childComplexity int) int + DeletionGracePeriodSeconds func(childComplexity int) int + DeletionTimestamp func(childComplexity int) int + Finalizers func(childComplexity int) int + GenerateName func(childComplexity int) int + Generation func(childComplexity int) int + Ipset func(childComplexity int) int + Iptables func(childComplexity int) int + Kind func(childComplexity int) int + Labels func(childComplexity int) int + Logs func(childComplexity int) int + Mounts func(childComplexity int) int + Name func(childComplexity int) int + Namespace func(childComplexity int) int + OwnerReferences func(childComplexity int) int + Processes func(childComplexity int) int + ResourceVersion func(childComplexity int) int + SelfLink func(childComplexity int) int + Spec func(childComplexity int) int + Status func(childComplexity int) int + TcQdisc func(childComplexity int) int + UID func(childComplexity int) int + } + + PodCondition struct { + LastProbeTime func(childComplexity int) int + LastTransitionTime func(childComplexity int) int + Message func(childComplexity int) int + Reason func(childComplexity int) int + Status func(childComplexity int) int + Type func(childComplexity int) int + } + + PodHTTPChaos struct { + APIVersion func(childComplexity int) int + Annotations func(childComplexity int) int + CreationTimestamp func(childComplexity int) int + DeletionGracePeriodSeconds func(childComplexity int) int + DeletionTimestamp func(childComplexity int) int + Finalizers func(childComplexity int) int + GenerateName func(childComplexity int) int + Generation func(childComplexity int) int + Kind func(childComplexity int) int + Labels func(childComplexity int) int + Name func(childComplexity int) int + Namespace func(childComplexity int) int + OwnerReferences func(childComplexity int) int + Pod func(childComplexity int) int + ResourceVersion func(childComplexity int) int + SelfLink func(childComplexity int) int + Spec func(childComplexity int) int + Status func(childComplexity int) int + UID func(childComplexity int) int + } + + PodHttpChaosActions struct { + Abort func(childComplexity int) int + Delay func(childComplexity int) int + Patch func(childComplexity int) int + Replace func(childComplexity int) int + } + + PodHttpChaosPatchActions struct { + Body func(childComplexity int) int + Headers func(childComplexity int) int + Queries func(childComplexity int) int + } + + PodHttpChaosPatchBodyAction struct { + Type func(childComplexity int) int + Value func(childComplexity int) int + } + + PodHttpChaosReplaceActions struct { + Body func(childComplexity int) int + Code func(childComplexity int) int + Headers func(childComplexity int) int + Method func(childComplexity int) int + Path func(childComplexity int) int + Queries func(childComplexity int) int + } + + PodHttpChaosRule struct { + Actions func(childComplexity int) int + Port func(childComplexity int) int + Selector func(childComplexity int) int + Source func(childComplexity int) int + Target func(childComplexity int) int + } + + PodHttpChaosSelector struct { + Code func(childComplexity int) int + Method func(childComplexity int) int + Path func(childComplexity int) int + Port func(childComplexity int) int + RequestHeaders func(childComplexity int) int + ResponseHeaders func(childComplexity int) int + } + + PodHttpChaosSpec struct { + Rules func(childComplexity int) int + TLS func(childComplexity int) int + } + + PodHttpChaosStatus struct { + FailedMessage func(childComplexity int) int + ObservedGeneration func(childComplexity int) int + Pid func(childComplexity int) int + StartTime func(childComplexity int) int + } + + PodHttpChaosTLS struct { + CAName func(childComplexity int) int + CertName func(childComplexity int) int + KeyName func(childComplexity int) int + SecretName func(childComplexity int) int + SecretNamespace func(childComplexity int) int + } + + PodIOChaos struct { + APIVersion func(childComplexity int) int + Annotations func(childComplexity int) int + CreationTimestamp func(childComplexity int) int + DeletionGracePeriodSeconds func(childComplexity int) int + DeletionTimestamp func(childComplexity int) int + Finalizers func(childComplexity int) int + GenerateName func(childComplexity int) int + Generation func(childComplexity int) int + Ios func(childComplexity int) int + Kind func(childComplexity int) int + Labels func(childComplexity int) int + Name func(childComplexity int) int + Namespace func(childComplexity int) int + OwnerReferences func(childComplexity int) int + Pod func(childComplexity int) int + ResourceVersion func(childComplexity int) int + SelfLink func(childComplexity int) int + Spec func(childComplexity int) int + Status func(childComplexity int) int + UID func(childComplexity int) int + } + + PodIOChaosSpec struct { + Actions func(childComplexity int) int + Container func(childComplexity int) int + VolumeMountPath func(childComplexity int) int + } + + PodIOChaosStatus struct { + FailedMessage func(childComplexity int) int + ObservedGeneration func(childComplexity int) int + Pid func(childComplexity int) int + StartTime func(childComplexity int) int + } + + PodIP struct { + IP func(childComplexity int) int + } + + PodNetworkChaos struct { + APIVersion func(childComplexity int) int + Annotations func(childComplexity int) int + CreationTimestamp func(childComplexity int) int + DeletionGracePeriodSeconds func(childComplexity int) int + DeletionTimestamp func(childComplexity int) int + Finalizers func(childComplexity int) int + GenerateName func(childComplexity int) int + Generation func(childComplexity int) int + Kind func(childComplexity int) int + Labels func(childComplexity int) int + Name func(childComplexity int) int + Namespace func(childComplexity int) int + OwnerReferences func(childComplexity int) int + Pod func(childComplexity int) int + ResourceVersion func(childComplexity int) int + SelfLink func(childComplexity int) int + Spec func(childComplexity int) int + Status func(childComplexity int) int + UID func(childComplexity int) int + } + + PodNetworkChaosSpec struct { + IPSets func(childComplexity int) int + Iptables func(childComplexity int) int + TrafficControls func(childComplexity int) int + } + + PodNetworkChaosStatus struct { + FailedMessage func(childComplexity int) int + ObservedGeneration func(childComplexity int) int + } + + PodSelectorSpec struct { + AnnotationSelectors func(childComplexity int) int + FieldSelectors func(childComplexity int) int + LabelSelectors func(childComplexity int) int + Namespaces func(childComplexity int) int + NodeSelectors func(childComplexity int) int + Nodes func(childComplexity int) int + PodPhaseSelectors func(childComplexity int) int + Pods func(childComplexity int) int + } + + PodSpec struct { + NodeName func(childComplexity int) int + } + + PodStatus struct { + Conditions func(childComplexity int) int + ContainerStatuses func(childComplexity int) int + EphemeralContainerStatuses func(childComplexity int) int + HostIP func(childComplexity int) int + InitContainerStatuses func(childComplexity int) int + Message func(childComplexity int) int + NominatedNodeName func(childComplexity int) int + Phase func(childComplexity int) int + PodIP func(childComplexity int) int + PodIPs func(childComplexity int) int + QosClass func(childComplexity int) int + Reason func(childComplexity int) int + StartTime func(childComplexity int) int + } + + PodStressChaos struct { + Cgroups func(childComplexity int) int + Pod func(childComplexity int) int + ProcessStress func(childComplexity int) int + StressChaos func(childComplexity int) int + } + + Process struct { + Command func(childComplexity int) int + Fds func(childComplexity int) int + Pid func(childComplexity int) int + Pod func(childComplexity int) int + } + + ProcessStress struct { + Cgroup func(childComplexity int) int + Process func(childComplexity int) int + } + + Query struct { + Namespace func(childComplexity int, ns *string) int + Pods func(childComplexity int, selector model.PodSelectorInput) int + } + + RateSpec struct { + Rate func(childComplexity int) int + } + + RawIPSet struct { + CidrAndPorts func(childComplexity int) int + Cidrs func(childComplexity int) int + IPSetType func(childComplexity int) int + Name func(childComplexity int) int + SetNames func(childComplexity int) int + Source func(childComplexity int) int + } + + RawIptables struct { + Device func(childComplexity int) int + Direction func(childComplexity int) int + IPSets func(childComplexity int) int + Name func(childComplexity int) int + Source func(childComplexity int) int + } + + RawTrafficControl struct { + Bandwidth func(childComplexity int) int + Corrupt func(childComplexity int) int + Delay func(childComplexity int) int + Device func(childComplexity int) int + Duplicate func(childComplexity int) int + IPSet func(childComplexity int) int + Loss func(childComplexity int) int + Rate func(childComplexity int) int + Source func(childComplexity int) int + Type func(childComplexity int) int + } + + Record struct { + Id func(childComplexity int) int + Phase func(childComplexity int) int + SelectorKey func(childComplexity int) int + } + + ReorderSpec struct { + Correlation func(childComplexity int) int + Gap func(childComplexity int) int + Reorder func(childComplexity int) int + } + + StressChaos struct { + APIVersion func(childComplexity int) int + Annotations func(childComplexity int) int + CreationTimestamp func(childComplexity int) int + DeletionGracePeriodSeconds func(childComplexity int) int + DeletionTimestamp func(childComplexity int) int + Finalizers func(childComplexity int) int + GenerateName func(childComplexity int) int + Generation func(childComplexity int) int + Kind func(childComplexity int) int + Labels func(childComplexity int) int + Name func(childComplexity int) int + Namespace func(childComplexity int) int + OwnerReferences func(childComplexity int) int + Podstress func(childComplexity int) int + ResourceVersion func(childComplexity int) int + SelfLink func(childComplexity int) int + Spec func(childComplexity int) int + UID func(childComplexity int) int + } + + StressChaosSpec struct { + ContainerNames func(childComplexity int) int + Duration func(childComplexity int) int + Mode func(childComplexity int) int + Selector func(childComplexity int) int + StressngStressors func(childComplexity int) int + Stressors func(childComplexity int) int + Value func(childComplexity int) int + } + + StressChaosStatus struct { + Conditions func(childComplexity int) int + Experiment func(childComplexity int) int + Instances func(childComplexity int) int + } + + Stressors struct { + CPUStressor func(childComplexity int) int + MemoryStressor func(childComplexity int) int + } + + Timespec struct { + Nsec func(childComplexity int) int + Sec func(childComplexity int) int + } +} + +type AttrOverrideSpecResolver interface { + Ino(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) + Size(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) + Blocks(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) + + Kind(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*string, error) + Perm(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) + Nlink(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) + UID(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) + Gid(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) + Rdev(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) +} +type BandwidthSpecResolver interface { + Limit(ctx context.Context, obj *v1alpha1.BandwidthSpec) (int, error) + Buffer(ctx context.Context, obj *v1alpha1.BandwidthSpec) (int, error) + Peakrate(ctx context.Context, obj *v1alpha1.BandwidthSpec) (*int, error) + Minburst(ctx context.Context, obj *v1alpha1.BandwidthSpec) (*int, error) +} +type ChaosConditionResolver interface { + Type(ctx context.Context, obj *v1alpha1.ChaosCondition) (string, error) + Status(ctx context.Context, obj *v1alpha1.ChaosCondition) (string, error) +} +type CidrAndPortResolver interface { + Port(ctx context.Context, obj *v1alpha1.CidrAndPort) (int, error) +} +type ContainerStateRunningResolver interface { + StartedAt(ctx context.Context, obj *v1.ContainerStateRunning) (*time.Time, error) +} +type ContainerStateTerminatedResolver interface { + StartedAt(ctx context.Context, obj *v1.ContainerStateTerminated) (*time.Time, error) + FinishedAt(ctx context.Context, obj *v1.ContainerStateTerminated) (*time.Time, error) +} +type ExperimentStatusResolver interface { + DesiredPhase(ctx context.Context, obj *v1alpha1.ExperimentStatus) (string, error) +} +type HTTPChaosResolver interface { + UID(ctx context.Context, obj *v1alpha1.HTTPChaos) (string, error) + + CreationTimestamp(ctx context.Context, obj *v1alpha1.HTTPChaos) (*time.Time, error) + DeletionTimestamp(ctx context.Context, obj *v1alpha1.HTTPChaos) (*time.Time, error) + + Labels(ctx context.Context, obj *v1alpha1.HTTPChaos) (map[string]interface{}, error) + Annotations(ctx context.Context, obj *v1alpha1.HTTPChaos) (map[string]interface{}, error) + + Podhttp(ctx context.Context, obj *v1alpha1.HTTPChaos) ([]*v1alpha1.PodHttpChaos, error) +} +type HTTPChaosSpecResolver interface { + Mode(ctx context.Context, obj *v1alpha1.HTTPChaosSpec) (string, error) + + Target(ctx context.Context, obj *v1alpha1.HTTPChaosSpec) (string, error) + + RequestHeaders(ctx context.Context, obj *v1alpha1.HTTPChaosSpec) (map[string]interface{}, error) + ResponseHeaders(ctx context.Context, obj *v1alpha1.HTTPChaosSpec) (map[string]interface{}, error) +} +type HTTPChaosStatusResolver interface { + Instances(ctx context.Context, obj *v1alpha1.HTTPChaosStatus) (map[string]interface{}, error) +} +type IOChaosResolver interface { + UID(ctx context.Context, obj *v1alpha1.IOChaos) (string, error) + + CreationTimestamp(ctx context.Context, obj *v1alpha1.IOChaos) (*time.Time, error) + DeletionTimestamp(ctx context.Context, obj *v1alpha1.IOChaos) (*time.Time, error) + + Labels(ctx context.Context, obj *v1alpha1.IOChaos) (map[string]interface{}, error) + Annotations(ctx context.Context, obj *v1alpha1.IOChaos) (map[string]interface{}, error) + + Podios(ctx context.Context, obj *v1alpha1.IOChaos) ([]*v1alpha1.PodIOChaos, error) +} +type IOChaosActionResolver interface { + Type(ctx context.Context, obj *v1alpha1.IOChaosAction) (string, error) + + Methods(ctx context.Context, obj *v1alpha1.IOChaosAction) ([]string, error) + + Ino(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) + Size(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) + Blocks(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) + Atime(ctx context.Context, obj *v1alpha1.IOChaosAction) (*v1alpha1.Timespec, error) + Mtime(ctx context.Context, obj *v1alpha1.IOChaosAction) (*v1alpha1.Timespec, error) + Ctime(ctx context.Context, obj *v1alpha1.IOChaosAction) (*v1alpha1.Timespec, error) + Kind(ctx context.Context, obj *v1alpha1.IOChaosAction) (*string, error) + Perm(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int, error) + Nlink(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) + UID(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) + Gid(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) + Rdev(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) + Filling(ctx context.Context, obj *v1alpha1.IOChaosAction) (*string, error) + MaxOccurrences(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) + MaxLength(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) +} +type IOChaosSpecResolver interface { + Mode(ctx context.Context, obj *v1alpha1.IOChaosSpec) (string, error) + + Action(ctx context.Context, obj *v1alpha1.IOChaosSpec) (string, error) + + Errno(ctx context.Context, obj *v1alpha1.IOChaosSpec) (*int, error) + + Methods(ctx context.Context, obj *v1alpha1.IOChaosSpec) ([]string, error) +} +type IOChaosStatusResolver interface { + Instances(ctx context.Context, obj *v1alpha1.IOChaosStatus) (map[string]interface{}, error) +} +type IoFaultResolver interface { + Errno(ctx context.Context, obj *v1alpha1.IoFault) (int, error) +} +type LoggerResolver interface { + Component(ctx context.Context, ns string, component model.Component) (<-chan string, error) + Pod(ctx context.Context, ns string, name string) (<-chan string, error) +} +type MistakeSpecResolver interface { + Filling(ctx context.Context, obj *v1alpha1.MistakeSpec) (*string, error) +} +type MutablePodResolver interface { + KillProcesses(ctx context.Context, obj *model.MutablePod, pids []string) ([]*model.KillProcessResult, error) + CleanTcs(ctx context.Context, obj *model.MutablePod, devices []string) ([]string, error) + CleanIptables(ctx context.Context, obj *model.MutablePod, chains []string) ([]string, error) +} +type MutationResolver interface { + Pod(ctx context.Context, ns string, name string) (*model.MutablePod, error) +} +type NamespaceResolver interface { + Component(ctx context.Context, obj *model.Namespace, component model.Component) ([]*v1.Pod, error) + Pod(ctx context.Context, obj *model.Namespace, name *string) ([]*v1.Pod, error) + Stresschaos(ctx context.Context, obj *model.Namespace, name *string) ([]*v1alpha1.StressChaos, error) + Iochaos(ctx context.Context, obj *model.Namespace, name *string) ([]*v1alpha1.IOChaos, error) + Podiochaos(ctx context.Context, obj *model.Namespace, name *string) ([]*v1alpha1.PodIOChaos, error) + Httpchaos(ctx context.Context, obj *model.Namespace, name *string) ([]*v1alpha1.HTTPChaos, error) + Podhttpchaos(ctx context.Context, obj *model.Namespace, name *string) ([]*v1alpha1.PodHttpChaos, error) + Networkchaos(ctx context.Context, obj *model.Namespace, name *string) ([]*v1alpha1.NetworkChaos, error) + Podnetworkchaos(ctx context.Context, obj *model.Namespace, name *string) ([]*v1alpha1.PodNetworkChaos, error) +} +type NetworkChaosResolver interface { + UID(ctx context.Context, obj *v1alpha1.NetworkChaos) (string, error) + + CreationTimestamp(ctx context.Context, obj *v1alpha1.NetworkChaos) (*time.Time, error) + DeletionTimestamp(ctx context.Context, obj *v1alpha1.NetworkChaos) (*time.Time, error) + + Labels(ctx context.Context, obj *v1alpha1.NetworkChaos) (map[string]interface{}, error) + Annotations(ctx context.Context, obj *v1alpha1.NetworkChaos) (map[string]interface{}, error) + + Podnetwork(ctx context.Context, obj *v1alpha1.NetworkChaos) ([]*v1alpha1.PodNetworkChaos, error) +} +type OwnerReferenceResolver interface { + UID(ctx context.Context, obj *v11.OwnerReference) (string, error) +} +type PodResolver interface { + UID(ctx context.Context, obj *v1.Pod) (string, error) + + CreationTimestamp(ctx context.Context, obj *v1.Pod) (*time.Time, error) + DeletionTimestamp(ctx context.Context, obj *v1.Pod) (*time.Time, error) + + Labels(ctx context.Context, obj *v1.Pod) (map[string]interface{}, error) + Annotations(ctx context.Context, obj *v1.Pod) (map[string]interface{}, error) + + Logs(ctx context.Context, obj *v1.Pod) (string, error) + Daemon(ctx context.Context, obj *v1.Pod) (*v1.Pod, error) + Processes(ctx context.Context, obj *v1.Pod) ([]*model.Process, error) + Mounts(ctx context.Context, obj *v1.Pod) ([]string, error) + Ipset(ctx context.Context, obj *v1.Pod) (string, error) + TcQdisc(ctx context.Context, obj *v1.Pod) ([]string, error) + Iptables(ctx context.Context, obj *v1.Pod) ([]string, error) +} +type PodConditionResolver interface { + Type(ctx context.Context, obj *v1.PodCondition) (string, error) + Status(ctx context.Context, obj *v1.PodCondition) (string, error) + LastProbeTime(ctx context.Context, obj *v1.PodCondition) (*time.Time, error) + LastTransitionTime(ctx context.Context, obj *v1.PodCondition) (*time.Time, error) +} +type PodHTTPChaosResolver interface { + UID(ctx context.Context, obj *v1alpha1.PodHttpChaos) (string, error) + + CreationTimestamp(ctx context.Context, obj *v1alpha1.PodHttpChaos) (*time.Time, error) + DeletionTimestamp(ctx context.Context, obj *v1alpha1.PodHttpChaos) (*time.Time, error) + + Labels(ctx context.Context, obj *v1alpha1.PodHttpChaos) (map[string]interface{}, error) + Annotations(ctx context.Context, obj *v1alpha1.PodHttpChaos) (map[string]interface{}, error) + + Pod(ctx context.Context, obj *v1alpha1.PodHttpChaos) (*v1.Pod, error) +} +type PodHttpChaosReplaceActionsResolver interface { + Body(ctx context.Context, obj *v1alpha1.PodHttpChaosReplaceActions) (*string, error) + Queries(ctx context.Context, obj *v1alpha1.PodHttpChaosReplaceActions) (map[string]interface{}, error) + Headers(ctx context.Context, obj *v1alpha1.PodHttpChaosReplaceActions) (map[string]interface{}, error) +} +type PodHttpChaosRuleResolver interface { + Target(ctx context.Context, obj *v1alpha1.PodHttpChaosRule) (string, error) +} +type PodHttpChaosSelectorResolver interface { + RequestHeaders(ctx context.Context, obj *v1alpha1.PodHttpChaosSelector) (map[string]interface{}, error) + ResponseHeaders(ctx context.Context, obj *v1alpha1.PodHttpChaosSelector) (map[string]interface{}, error) +} +type PodIOChaosResolver interface { + UID(ctx context.Context, obj *v1alpha1.PodIOChaos) (string, error) + + CreationTimestamp(ctx context.Context, obj *v1alpha1.PodIOChaos) (*time.Time, error) + DeletionTimestamp(ctx context.Context, obj *v1alpha1.PodIOChaos) (*time.Time, error) + + Labels(ctx context.Context, obj *v1alpha1.PodIOChaos) (map[string]interface{}, error) + Annotations(ctx context.Context, obj *v1alpha1.PodIOChaos) (map[string]interface{}, error) + + Pod(ctx context.Context, obj *v1alpha1.PodIOChaos) (*v1.Pod, error) + Ios(ctx context.Context, obj *v1alpha1.PodIOChaos) ([]*v1alpha1.IOChaos, error) +} +type PodNetworkChaosResolver interface { + UID(ctx context.Context, obj *v1alpha1.PodNetworkChaos) (string, error) + + CreationTimestamp(ctx context.Context, obj *v1alpha1.PodNetworkChaos) (*time.Time, error) + DeletionTimestamp(ctx context.Context, obj *v1alpha1.PodNetworkChaos) (*time.Time, error) + + Labels(ctx context.Context, obj *v1alpha1.PodNetworkChaos) (map[string]interface{}, error) + Annotations(ctx context.Context, obj *v1alpha1.PodNetworkChaos) (map[string]interface{}, error) + + Pod(ctx context.Context, obj *v1alpha1.PodNetworkChaos) (*v1.Pod, error) +} +type PodSelectorSpecResolver interface { + Pods(ctx context.Context, obj *v1alpha1.PodSelectorSpec) (map[string]interface{}, error) + NodeSelectors(ctx context.Context, obj *v1alpha1.PodSelectorSpec) (map[string]interface{}, error) + FieldSelectors(ctx context.Context, obj *v1alpha1.PodSelectorSpec) (map[string]interface{}, error) + LabelSelectors(ctx context.Context, obj *v1alpha1.PodSelectorSpec) (map[string]interface{}, error) + AnnotationSelectors(ctx context.Context, obj *v1alpha1.PodSelectorSpec) (map[string]interface{}, error) +} +type PodStatusResolver interface { + Phase(ctx context.Context, obj *v1.PodStatus) (string, error) + + StartTime(ctx context.Context, obj *v1.PodStatus) (*time.Time, error) + + QosClass(ctx context.Context, obj *v1.PodStatus) (string, error) +} +type PodStressChaosResolver interface { + Cgroups(ctx context.Context, obj *model.PodStressChaos) (*model.Cgroups, error) + ProcessStress(ctx context.Context, obj *model.PodStressChaos) ([]*model.ProcessStress, error) +} +type ProcessResolver interface { + Fds(ctx context.Context, obj *model.Process) ([]*model.Fd, error) +} +type QueryResolver interface { + Namespace(ctx context.Context, ns *string) ([]*model.Namespace, error) + Pods(ctx context.Context, selector model.PodSelectorInput) ([]*v1.Pod, error) +} +type RawIPSetResolver interface { + IPSetType(ctx context.Context, obj *v1alpha1.RawIPSet) (string, error) +} +type RawIptablesResolver interface { + Direction(ctx context.Context, obj *v1alpha1.RawIptables) (string, error) +} +type RawTrafficControlResolver interface { + Type(ctx context.Context, obj *v1alpha1.RawTrafficControl) (string, error) +} +type RecordResolver interface { + Phase(ctx context.Context, obj *v1alpha1.Record) (string, error) +} +type StressChaosResolver interface { + UID(ctx context.Context, obj *v1alpha1.StressChaos) (string, error) + + CreationTimestamp(ctx context.Context, obj *v1alpha1.StressChaos) (*time.Time, error) + DeletionTimestamp(ctx context.Context, obj *v1alpha1.StressChaos) (*time.Time, error) + + Labels(ctx context.Context, obj *v1alpha1.StressChaos) (map[string]interface{}, error) + Annotations(ctx context.Context, obj *v1alpha1.StressChaos) (map[string]interface{}, error) + + Podstress(ctx context.Context, obj *v1alpha1.StressChaos) ([]*model.PodStressChaos, error) +} +type StressChaosSpecResolver interface { + Mode(ctx context.Context, obj *v1alpha1.StressChaosSpec) (string, error) +} +type StressChaosStatusResolver interface { + Instances(ctx context.Context, obj *v1alpha1.StressChaosStatus) (map[string]interface{}, error) +} + +type executableSchema struct { + resolvers ResolverRoot + directives DirectiveRoot + complexity ComplexityRoot +} + +func (e *executableSchema) Schema() *ast.Schema { + return parsedSchema +} + +func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) { + ec := executionContext{nil, e} + _ = ec + switch typeName + "." + field { + + case "AttrOverrideSpec.atime": + if e.complexity.AttrOverrideSpec.Atime == nil { + break + } + + return e.complexity.AttrOverrideSpec.Atime(childComplexity), true + + case "AttrOverrideSpec.blocks": + if e.complexity.AttrOverrideSpec.Blocks == nil { + break + } + + return e.complexity.AttrOverrideSpec.Blocks(childComplexity), true + + case "AttrOverrideSpec.ctime": + if e.complexity.AttrOverrideSpec.Ctime == nil { + break + } + + return e.complexity.AttrOverrideSpec.Ctime(childComplexity), true + + case "AttrOverrideSpec.gid": + if e.complexity.AttrOverrideSpec.Gid == nil { + break + } + + return e.complexity.AttrOverrideSpec.Gid(childComplexity), true + + case "AttrOverrideSpec.ino": + if e.complexity.AttrOverrideSpec.Ino == nil { + break + } + + return e.complexity.AttrOverrideSpec.Ino(childComplexity), true + + case "AttrOverrideSpec.kind": + if e.complexity.AttrOverrideSpec.Kind == nil { + break + } + + return e.complexity.AttrOverrideSpec.Kind(childComplexity), true + + case "AttrOverrideSpec.mtime": + if e.complexity.AttrOverrideSpec.Mtime == nil { + break + } + + return e.complexity.AttrOverrideSpec.Mtime(childComplexity), true + + case "AttrOverrideSpec.nlink": + if e.complexity.AttrOverrideSpec.Nlink == nil { + break + } + + return e.complexity.AttrOverrideSpec.Nlink(childComplexity), true + + case "AttrOverrideSpec.perm": + if e.complexity.AttrOverrideSpec.Perm == nil { + break + } + + return e.complexity.AttrOverrideSpec.Perm(childComplexity), true + + case "AttrOverrideSpec.rdev": + if e.complexity.AttrOverrideSpec.Rdev == nil { + break + } + + return e.complexity.AttrOverrideSpec.Rdev(childComplexity), true + + case "AttrOverrideSpec.size": + if e.complexity.AttrOverrideSpec.Size == nil { + break + } + + return e.complexity.AttrOverrideSpec.Size(childComplexity), true + + case "AttrOverrideSpec.uid": + if e.complexity.AttrOverrideSpec.UID == nil { + break + } + + return e.complexity.AttrOverrideSpec.UID(childComplexity), true + + case "BandwidthSpec.buffer": + if e.complexity.BandwidthSpec.Buffer == nil { + break + } + + return e.complexity.BandwidthSpec.Buffer(childComplexity), true + + case "BandwidthSpec.limit": + if e.complexity.BandwidthSpec.Limit == nil { + break + } + + return e.complexity.BandwidthSpec.Limit(childComplexity), true + + case "BandwidthSpec.minburst": + if e.complexity.BandwidthSpec.Minburst == nil { + break + } + + return e.complexity.BandwidthSpec.Minburst(childComplexity), true + + case "BandwidthSpec.peakrate": + if e.complexity.BandwidthSpec.Peakrate == nil { + break + } + + return e.complexity.BandwidthSpec.Peakrate(childComplexity), true + + case "BandwidthSpec.rate": + if e.complexity.BandwidthSpec.Rate == nil { + break + } + + return e.complexity.BandwidthSpec.Rate(childComplexity), true + + case "CPUStressor.load": + if e.complexity.CPUStressor.Load == nil { + break + } + + return e.complexity.CPUStressor.Load(childComplexity), true + + case "CPUStressor.options": + if e.complexity.CPUStressor.Options == nil { + break + } + + return e.complexity.CPUStressor.Options(childComplexity), true + + case "CPUStressor.workers": + if e.complexity.CPUStressor.Workers == nil { + break + } + + return e.complexity.CPUStressor.Workers(childComplexity), true + + case "Cgroups.cpu": + if e.complexity.Cgroups.CPU == nil { + break + } + + return e.complexity.Cgroups.CPU(childComplexity), true + + case "Cgroups.memory": + if e.complexity.Cgroups.Memory == nil { + break + } + + return e.complexity.Cgroups.Memory(childComplexity), true + + case "Cgroups.raw": + if e.complexity.Cgroups.Raw == nil { + break + } + + return e.complexity.Cgroups.Raw(childComplexity), true + + case "CgroupsCpu.period": + if e.complexity.CgroupsCpu.Period == nil { + break + } + + return e.complexity.CgroupsCpu.Period(childComplexity), true + + case "CgroupsCpu.quota": + if e.complexity.CgroupsCpu.Quota == nil { + break + } + + return e.complexity.CgroupsCpu.Quota(childComplexity), true + + case "CgroupsMemory.limit": + if e.complexity.CgroupsMemory.Limit == nil { + break + } + + return e.complexity.CgroupsMemory.Limit(childComplexity), true + + case "ChaosCondition.reason": + if e.complexity.ChaosCondition.Reason == nil { + break + } + + return e.complexity.ChaosCondition.Reason(childComplexity), true + + case "ChaosCondition.status": + if e.complexity.ChaosCondition.Status == nil { + break + } + + return e.complexity.ChaosCondition.Status(childComplexity), true + + case "ChaosCondition.type": + if e.complexity.ChaosCondition.Type == nil { + break + } + + return e.complexity.ChaosCondition.Type(childComplexity), true + + case "CidrAndPort.cidr": + if e.complexity.CidrAndPort.Cidr == nil { + break + } + + return e.complexity.CidrAndPort.Cidr(childComplexity), true + + case "CidrAndPort.port": + if e.complexity.CidrAndPort.Port == nil { + break + } + + return e.complexity.CidrAndPort.Port(childComplexity), true + + case "ContainerState.running": + if e.complexity.ContainerState.Running == nil { + break + } + + return e.complexity.ContainerState.Running(childComplexity), true + + case "ContainerState.terminated": + if e.complexity.ContainerState.Terminated == nil { + break + } + + return e.complexity.ContainerState.Terminated(childComplexity), true + + case "ContainerState.waiting": + if e.complexity.ContainerState.Waiting == nil { + break + } + + return e.complexity.ContainerState.Waiting(childComplexity), true + + case "ContainerStateRunning.startedAt": + if e.complexity.ContainerStateRunning.StartedAt == nil { + break + } + + return e.complexity.ContainerStateRunning.StartedAt(childComplexity), true + + case "ContainerStateTerminated.containerID": + if e.complexity.ContainerStateTerminated.ContainerID == nil { + break + } + + return e.complexity.ContainerStateTerminated.ContainerID(childComplexity), true + + case "ContainerStateTerminated.exitCode": + if e.complexity.ContainerStateTerminated.ExitCode == nil { + break + } + + return e.complexity.ContainerStateTerminated.ExitCode(childComplexity), true + + case "ContainerStateTerminated.finishedAt": + if e.complexity.ContainerStateTerminated.FinishedAt == nil { + break + } + + return e.complexity.ContainerStateTerminated.FinishedAt(childComplexity), true + + case "ContainerStateTerminated.message": + if e.complexity.ContainerStateTerminated.Message == nil { + break + } + + return e.complexity.ContainerStateTerminated.Message(childComplexity), true + + case "ContainerStateTerminated.reason": + if e.complexity.ContainerStateTerminated.Reason == nil { + break + } + + return e.complexity.ContainerStateTerminated.Reason(childComplexity), true + + case "ContainerStateTerminated.signal": + if e.complexity.ContainerStateTerminated.Signal == nil { + break + } + + return e.complexity.ContainerStateTerminated.Signal(childComplexity), true + + case "ContainerStateTerminated.startedAt": + if e.complexity.ContainerStateTerminated.StartedAt == nil { + break + } + + return e.complexity.ContainerStateTerminated.StartedAt(childComplexity), true + + case "ContainerStateWaiting.message": + if e.complexity.ContainerStateWaiting.Message == nil { + break + } + + return e.complexity.ContainerStateWaiting.Message(childComplexity), true + + case "ContainerStateWaiting.reason": + if e.complexity.ContainerStateWaiting.Reason == nil { + break + } + + return e.complexity.ContainerStateWaiting.Reason(childComplexity), true + + case "ContainerStatus.containerID": + if e.complexity.ContainerStatus.ContainerID == nil { + break + } + + return e.complexity.ContainerStatus.ContainerID(childComplexity), true + + case "ContainerStatus.image": + if e.complexity.ContainerStatus.Image == nil { + break + } + + return e.complexity.ContainerStatus.Image(childComplexity), true + + case "ContainerStatus.imageID": + if e.complexity.ContainerStatus.ImageID == nil { + break + } + + return e.complexity.ContainerStatus.ImageID(childComplexity), true + + case "ContainerStatus.lastTerminationState": + if e.complexity.ContainerStatus.LastTerminationState == nil { + break + } + + return e.complexity.ContainerStatus.LastTerminationState(childComplexity), true + + case "ContainerStatus.name": + if e.complexity.ContainerStatus.Name == nil { + break + } + + return e.complexity.ContainerStatus.Name(childComplexity), true + + case "ContainerStatus.ready": + if e.complexity.ContainerStatus.Ready == nil { + break + } + + return e.complexity.ContainerStatus.Ready(childComplexity), true + + case "ContainerStatus.restartCount": + if e.complexity.ContainerStatus.RestartCount == nil { + break + } + + return e.complexity.ContainerStatus.RestartCount(childComplexity), true + + case "ContainerStatus.started": + if e.complexity.ContainerStatus.Started == nil { + break + } + + return e.complexity.ContainerStatus.Started(childComplexity), true + + case "ContainerStatus.State": + if e.complexity.ContainerStatus.State == nil { + break + } + + return e.complexity.ContainerStatus.State(childComplexity), true + + case "CorruptSpec.correlation": + if e.complexity.CorruptSpec.Correlation == nil { + break + } + + return e.complexity.CorruptSpec.Correlation(childComplexity), true + + case "CorruptSpec.corrupt": + if e.complexity.CorruptSpec.Corrupt == nil { + break + } + + return e.complexity.CorruptSpec.Corrupt(childComplexity), true + + case "DelaySpec.correlation": + if e.complexity.DelaySpec.Correlation == nil { + break + } + + return e.complexity.DelaySpec.Correlation(childComplexity), true + + case "DelaySpec.jitter": + if e.complexity.DelaySpec.Jitter == nil { + break + } + + return e.complexity.DelaySpec.Jitter(childComplexity), true + + case "DelaySpec.latency": + if e.complexity.DelaySpec.Latency == nil { + break + } + + return e.complexity.DelaySpec.Latency(childComplexity), true + + case "DelaySpec.reorder": + if e.complexity.DelaySpec.Reorder == nil { + break + } + + return e.complexity.DelaySpec.Reorder(childComplexity), true + + case "DuplicateSpec.correlation": + if e.complexity.DuplicateSpec.Correlation == nil { + break + } + + return e.complexity.DuplicateSpec.Correlation(childComplexity), true + + case "DuplicateSpec.duplicate": + if e.complexity.DuplicateSpec.Duplicate == nil { + break + } + + return e.complexity.DuplicateSpec.Duplicate(childComplexity), true + + case "ExperimentStatus.desiredPhase": + if e.complexity.ExperimentStatus.DesiredPhase == nil { + break + } + + return e.complexity.ExperimentStatus.DesiredPhase(childComplexity), true + + case "ExperimentStatus.Records": + if e.complexity.ExperimentStatus.Records == nil { + break + } + + return e.complexity.ExperimentStatus.Records(childComplexity), true + + case "Fd.fd": + if e.complexity.Fd.Fd == nil { + break + } + + return e.complexity.Fd.Fd(childComplexity), true + + case "Fd.target": + if e.complexity.Fd.Target == nil { + break + } + + return e.complexity.Fd.Target(childComplexity), true + + case "HTTPChaos.apiVersion": + if e.complexity.HTTPChaos.APIVersion == nil { + break + } + + return e.complexity.HTTPChaos.APIVersion(childComplexity), true + + case "HTTPChaos.annotations": + if e.complexity.HTTPChaos.Annotations == nil { + break + } + + return e.complexity.HTTPChaos.Annotations(childComplexity), true + + case "HTTPChaos.creationTimestamp": + if e.complexity.HTTPChaos.CreationTimestamp == nil { + break + } + + return e.complexity.HTTPChaos.CreationTimestamp(childComplexity), true + + case "HTTPChaos.deletionGracePeriodSeconds": + if e.complexity.HTTPChaos.DeletionGracePeriodSeconds == nil { + break + } + + return e.complexity.HTTPChaos.DeletionGracePeriodSeconds(childComplexity), true + + case "HTTPChaos.deletionTimestamp": + if e.complexity.HTTPChaos.DeletionTimestamp == nil { + break + } + + return e.complexity.HTTPChaos.DeletionTimestamp(childComplexity), true + + case "HTTPChaos.finalizers": + if e.complexity.HTTPChaos.Finalizers == nil { + break + } + + return e.complexity.HTTPChaos.Finalizers(childComplexity), true + + case "HTTPChaos.generateName": + if e.complexity.HTTPChaos.GenerateName == nil { + break + } + + return e.complexity.HTTPChaos.GenerateName(childComplexity), true + + case "HTTPChaos.generation": + if e.complexity.HTTPChaos.Generation == nil { + break + } + + return e.complexity.HTTPChaos.Generation(childComplexity), true + + case "HTTPChaos.kind": + if e.complexity.HTTPChaos.Kind == nil { + break + } + + return e.complexity.HTTPChaos.Kind(childComplexity), true + + case "HTTPChaos.labels": + if e.complexity.HTTPChaos.Labels == nil { + break + } + + return e.complexity.HTTPChaos.Labels(childComplexity), true + + case "HTTPChaos.name": + if e.complexity.HTTPChaos.Name == nil { + break + } + + return e.complexity.HTTPChaos.Name(childComplexity), true + + case "HTTPChaos.namespace": + if e.complexity.HTTPChaos.Namespace == nil { + break + } + + return e.complexity.HTTPChaos.Namespace(childComplexity), true + + case "HTTPChaos.ownerReferences": + if e.complexity.HTTPChaos.OwnerReferences == nil { + break + } + + return e.complexity.HTTPChaos.OwnerReferences(childComplexity), true + + case "HTTPChaos.podhttp": + if e.complexity.HTTPChaos.Podhttp == nil { + break + } + + return e.complexity.HTTPChaos.Podhttp(childComplexity), true + + case "HTTPChaos.resourceVersion": + if e.complexity.HTTPChaos.ResourceVersion == nil { + break + } + + return e.complexity.HTTPChaos.ResourceVersion(childComplexity), true + + case "HTTPChaos.selfLink": + if e.complexity.HTTPChaos.SelfLink == nil { + break + } + + return e.complexity.HTTPChaos.SelfLink(childComplexity), true + + case "HTTPChaos.spec": + if e.complexity.HTTPChaos.Spec == nil { + break + } + + return e.complexity.HTTPChaos.Spec(childComplexity), true + + case "HTTPChaos.status": + if e.complexity.HTTPChaos.Status == nil { + break + } + + return e.complexity.HTTPChaos.Status(childComplexity), true + + case "HTTPChaos.uid": + if e.complexity.HTTPChaos.UID == nil { + break + } + + return e.complexity.HTTPChaos.UID(childComplexity), true + + case "HTTPChaosSpec.abort": + if e.complexity.HTTPChaosSpec.Abort == nil { + break + } + + return e.complexity.HTTPChaosSpec.Abort(childComplexity), true + + case "HTTPChaosSpec.code": + if e.complexity.HTTPChaosSpec.Code == nil { + break + } + + return e.complexity.HTTPChaosSpec.Code(childComplexity), true + + case "HTTPChaosSpec.delay": + if e.complexity.HTTPChaosSpec.Delay == nil { + break + } + + return e.complexity.HTTPChaosSpec.Delay(childComplexity), true + + case "HTTPChaosSpec.duration": + if e.complexity.HTTPChaosSpec.Duration == nil { + break + } + + return e.complexity.HTTPChaosSpec.Duration(childComplexity), true + + case "HTTPChaosSpec.method": + if e.complexity.HTTPChaosSpec.Method == nil { + break + } + + return e.complexity.HTTPChaosSpec.Method(childComplexity), true + + case "HTTPChaosSpec.mode": + if e.complexity.HTTPChaosSpec.Mode == nil { + break + } + + return e.complexity.HTTPChaosSpec.Mode(childComplexity), true + + case "HTTPChaosSpec.patch": + if e.complexity.HTTPChaosSpec.Patch == nil { + break + } + + return e.complexity.HTTPChaosSpec.Patch(childComplexity), true + + case "HTTPChaosSpec.path": + if e.complexity.HTTPChaosSpec.Path == nil { + break + } + + return e.complexity.HTTPChaosSpec.Path(childComplexity), true + + case "HTTPChaosSpec.port": + if e.complexity.HTTPChaosSpec.Port == nil { + break + } + + return e.complexity.HTTPChaosSpec.Port(childComplexity), true + + case "HTTPChaosSpec.replace": + if e.complexity.HTTPChaosSpec.Replace == nil { + break + } + + return e.complexity.HTTPChaosSpec.Replace(childComplexity), true + + case "HTTPChaosSpec.requestHeaders": + if e.complexity.HTTPChaosSpec.RequestHeaders == nil { + break + } + + return e.complexity.HTTPChaosSpec.RequestHeaders(childComplexity), true + + case "HTTPChaosSpec.responseHeaders": + if e.complexity.HTTPChaosSpec.ResponseHeaders == nil { + break + } + + return e.complexity.HTTPChaosSpec.ResponseHeaders(childComplexity), true + + case "HTTPChaosSpec.selector": + if e.complexity.HTTPChaosSpec.Selector == nil { + break + } + + return e.complexity.HTTPChaosSpec.Selector(childComplexity), true + + case "HTTPChaosSpec.target": + if e.complexity.HTTPChaosSpec.Target == nil { + break + } + + return e.complexity.HTTPChaosSpec.Target(childComplexity), true + + case "HTTPChaosSpec.value": + if e.complexity.HTTPChaosSpec.Value == nil { + break + } + + return e.complexity.HTTPChaosSpec.Value(childComplexity), true + + case "HTTPChaosStatus.conditions": + if e.complexity.HTTPChaosStatus.Conditions == nil { + break + } + + return e.complexity.HTTPChaosStatus.Conditions(childComplexity), true + + case "HTTPChaosStatus.experiment": + if e.complexity.HTTPChaosStatus.Experiment == nil { + break + } + + return e.complexity.HTTPChaosStatus.Experiment(childComplexity), true + + case "HTTPChaosStatus.instances": + if e.complexity.HTTPChaosStatus.Instances == nil { + break + } + + return e.complexity.HTTPChaosStatus.Instances(childComplexity), true + + case "IOChaos.apiVersion": + if e.complexity.IOChaos.APIVersion == nil { + break + } + + return e.complexity.IOChaos.APIVersion(childComplexity), true + + case "IOChaos.annotations": + if e.complexity.IOChaos.Annotations == nil { + break + } + + return e.complexity.IOChaos.Annotations(childComplexity), true + + case "IOChaos.creationTimestamp": + if e.complexity.IOChaos.CreationTimestamp == nil { + break + } + + return e.complexity.IOChaos.CreationTimestamp(childComplexity), true + + case "IOChaos.deletionGracePeriodSeconds": + if e.complexity.IOChaos.DeletionGracePeriodSeconds == nil { + break + } + + return e.complexity.IOChaos.DeletionGracePeriodSeconds(childComplexity), true + + case "IOChaos.deletionTimestamp": + if e.complexity.IOChaos.DeletionTimestamp == nil { + break + } + + return e.complexity.IOChaos.DeletionTimestamp(childComplexity), true + + case "IOChaos.finalizers": + if e.complexity.IOChaos.Finalizers == nil { + break + } + + return e.complexity.IOChaos.Finalizers(childComplexity), true + + case "IOChaos.generateName": + if e.complexity.IOChaos.GenerateName == nil { + break + } + + return e.complexity.IOChaos.GenerateName(childComplexity), true + + case "IOChaos.generation": + if e.complexity.IOChaos.Generation == nil { + break + } + + return e.complexity.IOChaos.Generation(childComplexity), true + + case "IOChaos.kind": + if e.complexity.IOChaos.Kind == nil { + break + } + + return e.complexity.IOChaos.Kind(childComplexity), true + + case "IOChaos.labels": + if e.complexity.IOChaos.Labels == nil { + break + } + + return e.complexity.IOChaos.Labels(childComplexity), true + + case "IOChaos.name": + if e.complexity.IOChaos.Name == nil { + break + } + + return e.complexity.IOChaos.Name(childComplexity), true + + case "IOChaos.namespace": + if e.complexity.IOChaos.Namespace == nil { + break + } + + return e.complexity.IOChaos.Namespace(childComplexity), true + + case "IOChaos.ownerReferences": + if e.complexity.IOChaos.OwnerReferences == nil { + break + } + + return e.complexity.IOChaos.OwnerReferences(childComplexity), true + + case "IOChaos.podios": + if e.complexity.IOChaos.Podios == nil { + break + } + + return e.complexity.IOChaos.Podios(childComplexity), true + + case "IOChaos.resourceVersion": + if e.complexity.IOChaos.ResourceVersion == nil { + break + } + + return e.complexity.IOChaos.ResourceVersion(childComplexity), true + + case "IOChaos.selfLink": + if e.complexity.IOChaos.SelfLink == nil { + break + } + + return e.complexity.IOChaos.SelfLink(childComplexity), true + + case "IOChaos.spec": + if e.complexity.IOChaos.Spec == nil { + break + } + + return e.complexity.IOChaos.Spec(childComplexity), true + + case "IOChaos.status": + if e.complexity.IOChaos.Status == nil { + break + } + + return e.complexity.IOChaos.Status(childComplexity), true + + case "IOChaos.uid": + if e.complexity.IOChaos.UID == nil { + break + } + + return e.complexity.IOChaos.UID(childComplexity), true + + case "IOChaosAction.atime": + if e.complexity.IOChaosAction.Atime == nil { + break + } + + return e.complexity.IOChaosAction.Atime(childComplexity), true + + case "IOChaosAction.blocks": + if e.complexity.IOChaosAction.Blocks == nil { + break + } + + return e.complexity.IOChaosAction.Blocks(childComplexity), true + + case "IOChaosAction.ctime": + if e.complexity.IOChaosAction.Ctime == nil { + break + } + + return e.complexity.IOChaosAction.Ctime(childComplexity), true + + case "IOChaosAction.faults": + if e.complexity.IOChaosAction.Faults == nil { + break + } + + return e.complexity.IOChaosAction.Faults(childComplexity), true + + case "IOChaosAction.filling": + if e.complexity.IOChaosAction.Filling == nil { + break + } + + return e.complexity.IOChaosAction.Filling(childComplexity), true + + case "IOChaosAction.gid": + if e.complexity.IOChaosAction.Gid == nil { + break + } + + return e.complexity.IOChaosAction.Gid(childComplexity), true + + case "IOChaosAction.ino": + if e.complexity.IOChaosAction.Ino == nil { + break + } + + return e.complexity.IOChaosAction.Ino(childComplexity), true + + case "IOChaosAction.kind": + if e.complexity.IOChaosAction.Kind == nil { + break + } + + return e.complexity.IOChaosAction.Kind(childComplexity), true + + case "IOChaosAction.latency": + if e.complexity.IOChaosAction.Latency == nil { + break + } + + return e.complexity.IOChaosAction.Latency(childComplexity), true + + case "IOChaosAction.maxLength": + if e.complexity.IOChaosAction.MaxLength == nil { + break + } + + return e.complexity.IOChaosAction.MaxLength(childComplexity), true + + case "IOChaosAction.maxOccurrences": + if e.complexity.IOChaosAction.MaxOccurrences == nil { + break + } + + return e.complexity.IOChaosAction.MaxOccurrences(childComplexity), true + + case "IOChaosAction.methods": + if e.complexity.IOChaosAction.Methods == nil { + break + } + + return e.complexity.IOChaosAction.Methods(childComplexity), true + + case "IOChaosAction.mtime": + if e.complexity.IOChaosAction.Mtime == nil { + break + } + + return e.complexity.IOChaosAction.Mtime(childComplexity), true + + case "IOChaosAction.nlink": + if e.complexity.IOChaosAction.Nlink == nil { + break + } + + return e.complexity.IOChaosAction.Nlink(childComplexity), true + + case "IOChaosAction.path": + if e.complexity.IOChaosAction.Path == nil { + break + } + + return e.complexity.IOChaosAction.Path(childComplexity), true + + case "IOChaosAction.percent": + if e.complexity.IOChaosAction.Percent == nil { + break + } + + return e.complexity.IOChaosAction.Percent(childComplexity), true + + case "IOChaosAction.perm": + if e.complexity.IOChaosAction.Perm == nil { + break + } + + return e.complexity.IOChaosAction.Perm(childComplexity), true + + case "IOChaosAction.rdev": + if e.complexity.IOChaosAction.Rdev == nil { + break + } + + return e.complexity.IOChaosAction.Rdev(childComplexity), true + + case "IOChaosAction.size": + if e.complexity.IOChaosAction.Size == nil { + break + } + + return e.complexity.IOChaosAction.Size(childComplexity), true + + case "IOChaosAction.source": + if e.complexity.IOChaosAction.Source == nil { + break + } + + return e.complexity.IOChaosAction.Source(childComplexity), true + + case "IOChaosAction.type": + if e.complexity.IOChaosAction.Type == nil { + break + } + + return e.complexity.IOChaosAction.Type(childComplexity), true + + case "IOChaosAction.uid": + if e.complexity.IOChaosAction.UID == nil { + break + } + + return e.complexity.IOChaosAction.UID(childComplexity), true + + case "IOChaosSpec.action": + if e.complexity.IOChaosSpec.Action == nil { + break + } + + return e.complexity.IOChaosSpec.Action(childComplexity), true + + case "IOChaosSpec.attr": + if e.complexity.IOChaosSpec.Attr == nil { + break + } + + return e.complexity.IOChaosSpec.Attr(childComplexity), true + + case "IOChaosSpec.containerNames": + if e.complexity.IOChaosSpec.ContainerNames == nil { + break + } + + return e.complexity.IOChaosSpec.ContainerNames(childComplexity), true + + case "IOChaosSpec.delay": + if e.complexity.IOChaosSpec.Delay == nil { + break + } + + return e.complexity.IOChaosSpec.Delay(childComplexity), true + + case "IOChaosSpec.duration": + if e.complexity.IOChaosSpec.Duration == nil { + break + } + + return e.complexity.IOChaosSpec.Duration(childComplexity), true + + case "IOChaosSpec.errno": + if e.complexity.IOChaosSpec.Errno == nil { + break + } + + return e.complexity.IOChaosSpec.Errno(childComplexity), true + + case "IOChaosSpec.methods": + if e.complexity.IOChaosSpec.Methods == nil { + break + } + + return e.complexity.IOChaosSpec.Methods(childComplexity), true + + case "IOChaosSpec.mistake": + if e.complexity.IOChaosSpec.Mistake == nil { + break + } + + return e.complexity.IOChaosSpec.Mistake(childComplexity), true + + case "IOChaosSpec.mode": + if e.complexity.IOChaosSpec.Mode == nil { + break + } + + return e.complexity.IOChaosSpec.Mode(childComplexity), true + + case "IOChaosSpec.path": + if e.complexity.IOChaosSpec.Path == nil { + break + } + + return e.complexity.IOChaosSpec.Path(childComplexity), true + + case "IOChaosSpec.percent": + if e.complexity.IOChaosSpec.Percent == nil { + break + } + + return e.complexity.IOChaosSpec.Percent(childComplexity), true + + case "IOChaosSpec.selector": + if e.complexity.IOChaosSpec.Selector == nil { + break + } + + return e.complexity.IOChaosSpec.Selector(childComplexity), true + + case "IOChaosSpec.value": + if e.complexity.IOChaosSpec.Value == nil { + break + } + + return e.complexity.IOChaosSpec.Value(childComplexity), true + + case "IOChaosSpec.volumePath": + if e.complexity.IOChaosSpec.VolumePath == nil { + break + } + + return e.complexity.IOChaosSpec.VolumePath(childComplexity), true + + case "IOChaosStatus.conditions": + if e.complexity.IOChaosStatus.Conditions == nil { + break + } + + return e.complexity.IOChaosStatus.Conditions(childComplexity), true + + case "IOChaosStatus.experiment": + if e.complexity.IOChaosStatus.Experiment == nil { + break + } + + return e.complexity.IOChaosStatus.Experiment(childComplexity), true + + case "IOChaosStatus.instances": + if e.complexity.IOChaosStatus.Instances == nil { + break + } + + return e.complexity.IOChaosStatus.Instances(childComplexity), true + + case "IoFault.errno": + if e.complexity.IoFault.Errno == nil { + break + } + + return e.complexity.IoFault.Errno(childComplexity), true + + case "IoFault.weight": + if e.complexity.IoFault.Weight == nil { + break + } + + return e.complexity.IoFault.Weight(childComplexity), true + + case "KillProcessResult.command": + if e.complexity.KillProcessResult.Command == nil { + break + } + + return e.complexity.KillProcessResult.Command(childComplexity), true + + case "KillProcessResult.pid": + if e.complexity.KillProcessResult.Pid == nil { + break + } + + return e.complexity.KillProcessResult.Pid(childComplexity), true + + case "Logger.component": + if e.complexity.Logger.Component == nil { + break + } + + args, err := ec.field_Logger_component_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Logger.Component(childComplexity, args["ns"].(string), args["component"].(model.Component)), true + + case "Logger.pod": + if e.complexity.Logger.Pod == nil { + break + } + + args, err := ec.field_Logger_pod_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Logger.Pod(childComplexity, args["ns"].(string), args["name"].(string)), true + + case "LossSpec.correlation": + if e.complexity.LossSpec.Correlation == nil { + break + } + + return e.complexity.LossSpec.Correlation(childComplexity), true + + case "LossSpec.loss": + if e.complexity.LossSpec.Loss == nil { + break + } + + return e.complexity.LossSpec.Loss(childComplexity), true + + case "MemoryStressor.options": + if e.complexity.MemoryStressor.Options == nil { + break + } + + return e.complexity.MemoryStressor.Options(childComplexity), true + + case "MemoryStressor.size": + if e.complexity.MemoryStressor.Size == nil { + break + } + + return e.complexity.MemoryStressor.Size(childComplexity), true + + case "MemoryStressor.workers": + if e.complexity.MemoryStressor.Workers == nil { + break + } + + return e.complexity.MemoryStressor.Workers(childComplexity), true + + case "MistakeSpec.filling": + if e.complexity.MistakeSpec.Filling == nil { + break + } + + return e.complexity.MistakeSpec.Filling(childComplexity), true + + case "MistakeSpec.maxLength": + if e.complexity.MistakeSpec.MaxLength == nil { + break + } + + return e.complexity.MistakeSpec.MaxLength(childComplexity), true + + case "MistakeSpec.maxOccurrences": + if e.complexity.MistakeSpec.MaxOccurrences == nil { + break + } + + return e.complexity.MistakeSpec.MaxOccurrences(childComplexity), true + + case "MutablePod.cleanIptables": + if e.complexity.MutablePod.CleanIptables == nil { + break + } + + args, err := ec.field_MutablePod_cleanIptables_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.MutablePod.CleanIptables(childComplexity, args["chains"].([]string)), true + + case "MutablePod.cleanTcs": + if e.complexity.MutablePod.CleanTcs == nil { + break + } + + args, err := ec.field_MutablePod_cleanTcs_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.MutablePod.CleanTcs(childComplexity, args["devices"].([]string)), true + + case "MutablePod.killProcesses": + if e.complexity.MutablePod.KillProcesses == nil { + break + } + + args, err := ec.field_MutablePod_killProcesses_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.MutablePod.KillProcesses(childComplexity, args["pids"].([]string)), true + + case "MutablePod.pod": + if e.complexity.MutablePod.Pod == nil { + break + } + + return e.complexity.MutablePod.Pod(childComplexity), true + + case "Mutation.pod": + if e.complexity.Mutation.Pod == nil { + break + } + + args, err := ec.field_Mutation_pod_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.Pod(childComplexity, args["ns"].(string), args["name"].(string)), true + + case "Namespace.component": + if e.complexity.Namespace.Component == nil { + break + } + + args, err := ec.field_Namespace_component_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Namespace.Component(childComplexity, args["component"].(model.Component)), true + + case "Namespace.httpchaos": + if e.complexity.Namespace.Httpchaos == nil { + break + } + + args, err := ec.field_Namespace_httpchaos_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Namespace.Httpchaos(childComplexity, args["name"].(*string)), true + + case "Namespace.iochaos": + if e.complexity.Namespace.Iochaos == nil { + break + } + + args, err := ec.field_Namespace_iochaos_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Namespace.Iochaos(childComplexity, args["name"].(*string)), true + + case "Namespace.networkchaos": + if e.complexity.Namespace.Networkchaos == nil { + break + } + + args, err := ec.field_Namespace_networkchaos_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Namespace.Networkchaos(childComplexity, args["name"].(*string)), true + + case "Namespace.ns": + if e.complexity.Namespace.Ns == nil { + break + } + + return e.complexity.Namespace.Ns(childComplexity), true + + case "Namespace.pod": + if e.complexity.Namespace.Pod == nil { + break + } + + args, err := ec.field_Namespace_pod_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Namespace.Pod(childComplexity, args["name"].(*string)), true + + case "Namespace.podhttpchaos": + if e.complexity.Namespace.Podhttpchaos == nil { + break + } + + args, err := ec.field_Namespace_podhttpchaos_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Namespace.Podhttpchaos(childComplexity, args["name"].(*string)), true + + case "Namespace.podiochaos": + if e.complexity.Namespace.Podiochaos == nil { + break + } + + args, err := ec.field_Namespace_podiochaos_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Namespace.Podiochaos(childComplexity, args["name"].(*string)), true + + case "Namespace.podnetworkchaos": + if e.complexity.Namespace.Podnetworkchaos == nil { + break + } + + args, err := ec.field_Namespace_podnetworkchaos_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Namespace.Podnetworkchaos(childComplexity, args["name"].(*string)), true + + case "Namespace.stresschaos": + if e.complexity.Namespace.Stresschaos == nil { + break + } + + args, err := ec.field_Namespace_stresschaos_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Namespace.Stresschaos(childComplexity, args["name"].(*string)), true + + case "NetworkChaos.apiVersion": + if e.complexity.NetworkChaos.APIVersion == nil { + break + } + + return e.complexity.NetworkChaos.APIVersion(childComplexity), true + + case "NetworkChaos.annotations": + if e.complexity.NetworkChaos.Annotations == nil { + break + } + + return e.complexity.NetworkChaos.Annotations(childComplexity), true + + case "NetworkChaos.creationTimestamp": + if e.complexity.NetworkChaos.CreationTimestamp == nil { + break + } + + return e.complexity.NetworkChaos.CreationTimestamp(childComplexity), true + + case "NetworkChaos.deletionGracePeriodSeconds": + if e.complexity.NetworkChaos.DeletionGracePeriodSeconds == nil { + break + } + + return e.complexity.NetworkChaos.DeletionGracePeriodSeconds(childComplexity), true + + case "NetworkChaos.deletionTimestamp": + if e.complexity.NetworkChaos.DeletionTimestamp == nil { + break + } + + return e.complexity.NetworkChaos.DeletionTimestamp(childComplexity), true + + case "NetworkChaos.finalizers": + if e.complexity.NetworkChaos.Finalizers == nil { + break + } + + return e.complexity.NetworkChaos.Finalizers(childComplexity), true + + case "NetworkChaos.generateName": + if e.complexity.NetworkChaos.GenerateName == nil { + break + } + + return e.complexity.NetworkChaos.GenerateName(childComplexity), true + + case "NetworkChaos.generation": + if e.complexity.NetworkChaos.Generation == nil { + break + } + + return e.complexity.NetworkChaos.Generation(childComplexity), true + + case "NetworkChaos.kind": + if e.complexity.NetworkChaos.Kind == nil { + break + } + + return e.complexity.NetworkChaos.Kind(childComplexity), true + + case "NetworkChaos.labels": + if e.complexity.NetworkChaos.Labels == nil { + break + } + + return e.complexity.NetworkChaos.Labels(childComplexity), true + + case "NetworkChaos.name": + if e.complexity.NetworkChaos.Name == nil { + break + } + + return e.complexity.NetworkChaos.Name(childComplexity), true + + case "NetworkChaos.namespace": + if e.complexity.NetworkChaos.Namespace == nil { + break + } + + return e.complexity.NetworkChaos.Namespace(childComplexity), true + + case "NetworkChaos.ownerReferences": + if e.complexity.NetworkChaos.OwnerReferences == nil { + break + } + + return e.complexity.NetworkChaos.OwnerReferences(childComplexity), true + + case "NetworkChaos.podnetwork": + if e.complexity.NetworkChaos.Podnetwork == nil { + break + } + + return e.complexity.NetworkChaos.Podnetwork(childComplexity), true + + case "NetworkChaos.resourceVersion": + if e.complexity.NetworkChaos.ResourceVersion == nil { + break + } + + return e.complexity.NetworkChaos.ResourceVersion(childComplexity), true + + case "NetworkChaos.selfLink": + if e.complexity.NetworkChaos.SelfLink == nil { + break + } + + return e.complexity.NetworkChaos.SelfLink(childComplexity), true + + case "NetworkChaos.uid": + if e.complexity.NetworkChaos.UID == nil { + break + } + + return e.complexity.NetworkChaos.UID(childComplexity), true + + case "OwnerReference.apiVersion": + if e.complexity.OwnerReference.APIVersion == nil { + break + } + + return e.complexity.OwnerReference.APIVersion(childComplexity), true + + case "OwnerReference.blockOwnerDeletion": + if e.complexity.OwnerReference.BlockOwnerDeletion == nil { + break + } + + return e.complexity.OwnerReference.BlockOwnerDeletion(childComplexity), true + + case "OwnerReference.controller": + if e.complexity.OwnerReference.Controller == nil { + break + } + + return e.complexity.OwnerReference.Controller(childComplexity), true + + case "OwnerReference.kind": + if e.complexity.OwnerReference.Kind == nil { + break + } + + return e.complexity.OwnerReference.Kind(childComplexity), true + + case "OwnerReference.name": + if e.complexity.OwnerReference.Name == nil { + break + } + + return e.complexity.OwnerReference.Name(childComplexity), true + + case "OwnerReference.uid": + if e.complexity.OwnerReference.UID == nil { + break + } + + return e.complexity.OwnerReference.UID(childComplexity), true + + case "Pod.apiVersion": + if e.complexity.Pod.APIVersion == nil { + break + } + + return e.complexity.Pod.APIVersion(childComplexity), true + + case "Pod.annotations": + if e.complexity.Pod.Annotations == nil { + break + } + + return e.complexity.Pod.Annotations(childComplexity), true + + case "Pod.creationTimestamp": + if e.complexity.Pod.CreationTimestamp == nil { + break + } + + return e.complexity.Pod.CreationTimestamp(childComplexity), true + + case "Pod.daemon": + if e.complexity.Pod.Daemon == nil { + break + } + + return e.complexity.Pod.Daemon(childComplexity), true + + case "Pod.deletionGracePeriodSeconds": + if e.complexity.Pod.DeletionGracePeriodSeconds == nil { + break + } + + return e.complexity.Pod.DeletionGracePeriodSeconds(childComplexity), true + + case "Pod.deletionTimestamp": + if e.complexity.Pod.DeletionTimestamp == nil { + break + } + + return e.complexity.Pod.DeletionTimestamp(childComplexity), true + + case "Pod.finalizers": + if e.complexity.Pod.Finalizers == nil { + break + } + + return e.complexity.Pod.Finalizers(childComplexity), true + + case "Pod.generateName": + if e.complexity.Pod.GenerateName == nil { + break + } + + return e.complexity.Pod.GenerateName(childComplexity), true + + case "Pod.generation": + if e.complexity.Pod.Generation == nil { + break + } + + return e.complexity.Pod.Generation(childComplexity), true + + case "Pod.ipset": + if e.complexity.Pod.Ipset == nil { + break + } + + return e.complexity.Pod.Ipset(childComplexity), true + + case "Pod.iptables": + if e.complexity.Pod.Iptables == nil { + break + } + + return e.complexity.Pod.Iptables(childComplexity), true + + case "Pod.kind": + if e.complexity.Pod.Kind == nil { + break + } + + return e.complexity.Pod.Kind(childComplexity), true + + case "Pod.labels": + if e.complexity.Pod.Labels == nil { + break + } + + return e.complexity.Pod.Labels(childComplexity), true + + case "Pod.logs": + if e.complexity.Pod.Logs == nil { + break + } + + return e.complexity.Pod.Logs(childComplexity), true + + case "Pod.mounts": + if e.complexity.Pod.Mounts == nil { + break + } + + return e.complexity.Pod.Mounts(childComplexity), true + + case "Pod.name": + if e.complexity.Pod.Name == nil { + break + } + + return e.complexity.Pod.Name(childComplexity), true + + case "Pod.namespace": + if e.complexity.Pod.Namespace == nil { + break + } + + return e.complexity.Pod.Namespace(childComplexity), true + + case "Pod.ownerReferences": + if e.complexity.Pod.OwnerReferences == nil { + break + } + + return e.complexity.Pod.OwnerReferences(childComplexity), true + + case "Pod.processes": + if e.complexity.Pod.Processes == nil { + break + } + + return e.complexity.Pod.Processes(childComplexity), true + + case "Pod.resourceVersion": + if e.complexity.Pod.ResourceVersion == nil { + break + } + + return e.complexity.Pod.ResourceVersion(childComplexity), true + + case "Pod.selfLink": + if e.complexity.Pod.SelfLink == nil { + break + } + + return e.complexity.Pod.SelfLink(childComplexity), true + + case "Pod.spec": + if e.complexity.Pod.Spec == nil { + break + } + + return e.complexity.Pod.Spec(childComplexity), true + + case "Pod.status": + if e.complexity.Pod.Status == nil { + break + } + + return e.complexity.Pod.Status(childComplexity), true + + case "Pod.tcQdisc": + if e.complexity.Pod.TcQdisc == nil { + break + } + + return e.complexity.Pod.TcQdisc(childComplexity), true + + case "Pod.uid": + if e.complexity.Pod.UID == nil { + break + } + + return e.complexity.Pod.UID(childComplexity), true + + case "PodCondition.lastProbeTime": + if e.complexity.PodCondition.LastProbeTime == nil { + break + } + + return e.complexity.PodCondition.LastProbeTime(childComplexity), true + + case "PodCondition.lastTransitionTime": + if e.complexity.PodCondition.LastTransitionTime == nil { + break + } + + return e.complexity.PodCondition.LastTransitionTime(childComplexity), true + + case "PodCondition.message": + if e.complexity.PodCondition.Message == nil { + break + } + + return e.complexity.PodCondition.Message(childComplexity), true + + case "PodCondition.reason": + if e.complexity.PodCondition.Reason == nil { + break + } + + return e.complexity.PodCondition.Reason(childComplexity), true + + case "PodCondition.status": + if e.complexity.PodCondition.Status == nil { + break + } + + return e.complexity.PodCondition.Status(childComplexity), true + + case "PodCondition.type": + if e.complexity.PodCondition.Type == nil { + break + } + + return e.complexity.PodCondition.Type(childComplexity), true + + case "PodHTTPChaos.apiVersion": + if e.complexity.PodHTTPChaos.APIVersion == nil { + break + } + + return e.complexity.PodHTTPChaos.APIVersion(childComplexity), true + + case "PodHTTPChaos.annotations": + if e.complexity.PodHTTPChaos.Annotations == nil { + break + } + + return e.complexity.PodHTTPChaos.Annotations(childComplexity), true + + case "PodHTTPChaos.creationTimestamp": + if e.complexity.PodHTTPChaos.CreationTimestamp == nil { + break + } + + return e.complexity.PodHTTPChaos.CreationTimestamp(childComplexity), true + + case "PodHTTPChaos.deletionGracePeriodSeconds": + if e.complexity.PodHTTPChaos.DeletionGracePeriodSeconds == nil { + break + } + + return e.complexity.PodHTTPChaos.DeletionGracePeriodSeconds(childComplexity), true + + case "PodHTTPChaos.deletionTimestamp": + if e.complexity.PodHTTPChaos.DeletionTimestamp == nil { + break + } + + return e.complexity.PodHTTPChaos.DeletionTimestamp(childComplexity), true + + case "PodHTTPChaos.finalizers": + if e.complexity.PodHTTPChaos.Finalizers == nil { + break + } + + return e.complexity.PodHTTPChaos.Finalizers(childComplexity), true + + case "PodHTTPChaos.generateName": + if e.complexity.PodHTTPChaos.GenerateName == nil { + break + } + + return e.complexity.PodHTTPChaos.GenerateName(childComplexity), true + + case "PodHTTPChaos.generation": + if e.complexity.PodHTTPChaos.Generation == nil { + break + } + + return e.complexity.PodHTTPChaos.Generation(childComplexity), true + + case "PodHTTPChaos.kind": + if e.complexity.PodHTTPChaos.Kind == nil { + break + } + + return e.complexity.PodHTTPChaos.Kind(childComplexity), true + + case "PodHTTPChaos.labels": + if e.complexity.PodHTTPChaos.Labels == nil { + break + } + + return e.complexity.PodHTTPChaos.Labels(childComplexity), true + + case "PodHTTPChaos.name": + if e.complexity.PodHTTPChaos.Name == nil { + break + } + + return e.complexity.PodHTTPChaos.Name(childComplexity), true + + case "PodHTTPChaos.namespace": + if e.complexity.PodHTTPChaos.Namespace == nil { + break + } + + return e.complexity.PodHTTPChaos.Namespace(childComplexity), true + + case "PodHTTPChaos.ownerReferences": + if e.complexity.PodHTTPChaos.OwnerReferences == nil { + break + } + + return e.complexity.PodHTTPChaos.OwnerReferences(childComplexity), true + + case "PodHTTPChaos.pod": + if e.complexity.PodHTTPChaos.Pod == nil { + break + } + + return e.complexity.PodHTTPChaos.Pod(childComplexity), true + + case "PodHTTPChaos.resourceVersion": + if e.complexity.PodHTTPChaos.ResourceVersion == nil { + break + } + + return e.complexity.PodHTTPChaos.ResourceVersion(childComplexity), true + + case "PodHTTPChaos.selfLink": + if e.complexity.PodHTTPChaos.SelfLink == nil { + break + } + + return e.complexity.PodHTTPChaos.SelfLink(childComplexity), true + + case "PodHTTPChaos.spec": + if e.complexity.PodHTTPChaos.Spec == nil { + break + } + + return e.complexity.PodHTTPChaos.Spec(childComplexity), true + + case "PodHTTPChaos.status": + if e.complexity.PodHTTPChaos.Status == nil { + break + } + + return e.complexity.PodHTTPChaos.Status(childComplexity), true + + case "PodHTTPChaos.uid": + if e.complexity.PodHTTPChaos.UID == nil { + break + } + + return e.complexity.PodHTTPChaos.UID(childComplexity), true + + case "PodHttpChaosActions.abort": + if e.complexity.PodHttpChaosActions.Abort == nil { + break + } + + return e.complexity.PodHttpChaosActions.Abort(childComplexity), true + + case "PodHttpChaosActions.delay": + if e.complexity.PodHttpChaosActions.Delay == nil { + break + } + + return e.complexity.PodHttpChaosActions.Delay(childComplexity), true + + case "PodHttpChaosActions.patch": + if e.complexity.PodHttpChaosActions.Patch == nil { + break + } + + return e.complexity.PodHttpChaosActions.Patch(childComplexity), true + + case "PodHttpChaosActions.replace": + if e.complexity.PodHttpChaosActions.Replace == nil { + break + } + + return e.complexity.PodHttpChaosActions.Replace(childComplexity), true + + case "PodHttpChaosPatchActions.body": + if e.complexity.PodHttpChaosPatchActions.Body == nil { + break + } + + return e.complexity.PodHttpChaosPatchActions.Body(childComplexity), true + + case "PodHttpChaosPatchActions.headers": + if e.complexity.PodHttpChaosPatchActions.Headers == nil { + break + } + + return e.complexity.PodHttpChaosPatchActions.Headers(childComplexity), true + + case "PodHttpChaosPatchActions.queries": + if e.complexity.PodHttpChaosPatchActions.Queries == nil { + break + } + + return e.complexity.PodHttpChaosPatchActions.Queries(childComplexity), true + + case "PodHttpChaosPatchBodyAction.type": + if e.complexity.PodHttpChaosPatchBodyAction.Type == nil { + break + } + + return e.complexity.PodHttpChaosPatchBodyAction.Type(childComplexity), true + + case "PodHttpChaosPatchBodyAction.value": + if e.complexity.PodHttpChaosPatchBodyAction.Value == nil { + break + } + + return e.complexity.PodHttpChaosPatchBodyAction.Value(childComplexity), true + + case "PodHttpChaosReplaceActions.body": + if e.complexity.PodHttpChaosReplaceActions.Body == nil { + break + } + + return e.complexity.PodHttpChaosReplaceActions.Body(childComplexity), true + + case "PodHttpChaosReplaceActions.code": + if e.complexity.PodHttpChaosReplaceActions.Code == nil { + break + } + + return e.complexity.PodHttpChaosReplaceActions.Code(childComplexity), true + + case "PodHttpChaosReplaceActions.headers": + if e.complexity.PodHttpChaosReplaceActions.Headers == nil { + break + } + + return e.complexity.PodHttpChaosReplaceActions.Headers(childComplexity), true + + case "PodHttpChaosReplaceActions.method": + if e.complexity.PodHttpChaosReplaceActions.Method == nil { + break + } + + return e.complexity.PodHttpChaosReplaceActions.Method(childComplexity), true + + case "PodHttpChaosReplaceActions.path": + if e.complexity.PodHttpChaosReplaceActions.Path == nil { + break + } + + return e.complexity.PodHttpChaosReplaceActions.Path(childComplexity), true + + case "PodHttpChaosReplaceActions.queries": + if e.complexity.PodHttpChaosReplaceActions.Queries == nil { + break + } + + return e.complexity.PodHttpChaosReplaceActions.Queries(childComplexity), true + + case "PodHttpChaosRule.actions": + if e.complexity.PodHttpChaosRule.Actions == nil { + break + } + + return e.complexity.PodHttpChaosRule.Actions(childComplexity), true + + case "PodHttpChaosRule.port": + if e.complexity.PodHttpChaosRule.Port == nil { + break + } + + return e.complexity.PodHttpChaosRule.Port(childComplexity), true + + case "PodHttpChaosRule.selector": + if e.complexity.PodHttpChaosRule.Selector == nil { + break + } + + return e.complexity.PodHttpChaosRule.Selector(childComplexity), true + + case "PodHttpChaosRule.source": + if e.complexity.PodHttpChaosRule.Source == nil { + break + } + + return e.complexity.PodHttpChaosRule.Source(childComplexity), true + + case "PodHttpChaosRule.target": + if e.complexity.PodHttpChaosRule.Target == nil { + break + } + + return e.complexity.PodHttpChaosRule.Target(childComplexity), true + + case "PodHttpChaosSelector.code": + if e.complexity.PodHttpChaosSelector.Code == nil { + break + } + + return e.complexity.PodHttpChaosSelector.Code(childComplexity), true + + case "PodHttpChaosSelector.method": + if e.complexity.PodHttpChaosSelector.Method == nil { + break + } + + return e.complexity.PodHttpChaosSelector.Method(childComplexity), true + + case "PodHttpChaosSelector.path": + if e.complexity.PodHttpChaosSelector.Path == nil { + break + } + + return e.complexity.PodHttpChaosSelector.Path(childComplexity), true + + case "PodHttpChaosSelector.port": + if e.complexity.PodHttpChaosSelector.Port == nil { + break + } + + return e.complexity.PodHttpChaosSelector.Port(childComplexity), true + + case "PodHttpChaosSelector.requestHeaders": + if e.complexity.PodHttpChaosSelector.RequestHeaders == nil { + break + } + + return e.complexity.PodHttpChaosSelector.RequestHeaders(childComplexity), true + + case "PodHttpChaosSelector.responseHeaders": + if e.complexity.PodHttpChaosSelector.ResponseHeaders == nil { + break + } + + return e.complexity.PodHttpChaosSelector.ResponseHeaders(childComplexity), true + + case "PodHttpChaosSpec.rules": + if e.complexity.PodHttpChaosSpec.Rules == nil { + break + } + + return e.complexity.PodHttpChaosSpec.Rules(childComplexity), true + + case "PodHttpChaosSpec.tls": + if e.complexity.PodHttpChaosSpec.TLS == nil { + break + } + + return e.complexity.PodHttpChaosSpec.TLS(childComplexity), true + + case "PodHttpChaosStatus.failedMessage": + if e.complexity.PodHttpChaosStatus.FailedMessage == nil { + break + } + + return e.complexity.PodHttpChaosStatus.FailedMessage(childComplexity), true + + case "PodHttpChaosStatus.observedGeneration": + if e.complexity.PodHttpChaosStatus.ObservedGeneration == nil { + break + } + + return e.complexity.PodHttpChaosStatus.ObservedGeneration(childComplexity), true + + case "PodHttpChaosStatus.pid": + if e.complexity.PodHttpChaosStatus.Pid == nil { + break + } + + return e.complexity.PodHttpChaosStatus.Pid(childComplexity), true + + case "PodHttpChaosStatus.startTime": + if e.complexity.PodHttpChaosStatus.StartTime == nil { + break + } + + return e.complexity.PodHttpChaosStatus.StartTime(childComplexity), true + + case "PodHttpChaosTLS.caName": + if e.complexity.PodHttpChaosTLS.CAName == nil { + break + } + + return e.complexity.PodHttpChaosTLS.CAName(childComplexity), true + + case "PodHttpChaosTLS.certName": + if e.complexity.PodHttpChaosTLS.CertName == nil { + break + } + + return e.complexity.PodHttpChaosTLS.CertName(childComplexity), true + + case "PodHttpChaosTLS.keyName": + if e.complexity.PodHttpChaosTLS.KeyName == nil { + break + } + + return e.complexity.PodHttpChaosTLS.KeyName(childComplexity), true + + case "PodHttpChaosTLS.secretName": + if e.complexity.PodHttpChaosTLS.SecretName == nil { + break + } + + return e.complexity.PodHttpChaosTLS.SecretName(childComplexity), true + + case "PodHttpChaosTLS.secretNamespace": + if e.complexity.PodHttpChaosTLS.SecretNamespace == nil { + break + } + + return e.complexity.PodHttpChaosTLS.SecretNamespace(childComplexity), true + + case "PodIOChaos.apiVersion": + if e.complexity.PodIOChaos.APIVersion == nil { + break + } + + return e.complexity.PodIOChaos.APIVersion(childComplexity), true + + case "PodIOChaos.annotations": + if e.complexity.PodIOChaos.Annotations == nil { + break + } + + return e.complexity.PodIOChaos.Annotations(childComplexity), true + + case "PodIOChaos.creationTimestamp": + if e.complexity.PodIOChaos.CreationTimestamp == nil { + break + } + + return e.complexity.PodIOChaos.CreationTimestamp(childComplexity), true + + case "PodIOChaos.deletionGracePeriodSeconds": + if e.complexity.PodIOChaos.DeletionGracePeriodSeconds == nil { + break + } + + return e.complexity.PodIOChaos.DeletionGracePeriodSeconds(childComplexity), true + + case "PodIOChaos.deletionTimestamp": + if e.complexity.PodIOChaos.DeletionTimestamp == nil { + break + } + + return e.complexity.PodIOChaos.DeletionTimestamp(childComplexity), true + + case "PodIOChaos.finalizers": + if e.complexity.PodIOChaos.Finalizers == nil { + break + } + + return e.complexity.PodIOChaos.Finalizers(childComplexity), true + + case "PodIOChaos.generateName": + if e.complexity.PodIOChaos.GenerateName == nil { + break + } + + return e.complexity.PodIOChaos.GenerateName(childComplexity), true + + case "PodIOChaos.generation": + if e.complexity.PodIOChaos.Generation == nil { + break + } + + return e.complexity.PodIOChaos.Generation(childComplexity), true + + case "PodIOChaos.ios": + if e.complexity.PodIOChaos.Ios == nil { + break + } + + return e.complexity.PodIOChaos.Ios(childComplexity), true + + case "PodIOChaos.kind": + if e.complexity.PodIOChaos.Kind == nil { + break + } + + return e.complexity.PodIOChaos.Kind(childComplexity), true + + case "PodIOChaos.labels": + if e.complexity.PodIOChaos.Labels == nil { + break + } + + return e.complexity.PodIOChaos.Labels(childComplexity), true + + case "PodIOChaos.name": + if e.complexity.PodIOChaos.Name == nil { + break + } + + return e.complexity.PodIOChaos.Name(childComplexity), true + + case "PodIOChaos.namespace": + if e.complexity.PodIOChaos.Namespace == nil { + break + } + + return e.complexity.PodIOChaos.Namespace(childComplexity), true + + case "PodIOChaos.ownerReferences": + if e.complexity.PodIOChaos.OwnerReferences == nil { + break + } + + return e.complexity.PodIOChaos.OwnerReferences(childComplexity), true + + case "PodIOChaos.pod": + if e.complexity.PodIOChaos.Pod == nil { + break + } + + return e.complexity.PodIOChaos.Pod(childComplexity), true + + case "PodIOChaos.resourceVersion": + if e.complexity.PodIOChaos.ResourceVersion == nil { + break + } + + return e.complexity.PodIOChaos.ResourceVersion(childComplexity), true + + case "PodIOChaos.selfLink": + if e.complexity.PodIOChaos.SelfLink == nil { + break + } + + return e.complexity.PodIOChaos.SelfLink(childComplexity), true + + case "PodIOChaos.spec": + if e.complexity.PodIOChaos.Spec == nil { + break + } + + return e.complexity.PodIOChaos.Spec(childComplexity), true + + case "PodIOChaos.status": + if e.complexity.PodIOChaos.Status == nil { + break + } + + return e.complexity.PodIOChaos.Status(childComplexity), true + + case "PodIOChaos.uid": + if e.complexity.PodIOChaos.UID == nil { + break + } + + return e.complexity.PodIOChaos.UID(childComplexity), true + + case "PodIOChaosSpec.actions": + if e.complexity.PodIOChaosSpec.Actions == nil { + break + } + + return e.complexity.PodIOChaosSpec.Actions(childComplexity), true + + case "PodIOChaosSpec.container": + if e.complexity.PodIOChaosSpec.Container == nil { + break + } + + return e.complexity.PodIOChaosSpec.Container(childComplexity), true + + case "PodIOChaosSpec.volumeMountPath": + if e.complexity.PodIOChaosSpec.VolumeMountPath == nil { + break + } + + return e.complexity.PodIOChaosSpec.VolumeMountPath(childComplexity), true + + case "PodIOChaosStatus.failedMessage": + if e.complexity.PodIOChaosStatus.FailedMessage == nil { + break + } + + return e.complexity.PodIOChaosStatus.FailedMessage(childComplexity), true + + case "PodIOChaosStatus.observedGeneration": + if e.complexity.PodIOChaosStatus.ObservedGeneration == nil { + break + } + + return e.complexity.PodIOChaosStatus.ObservedGeneration(childComplexity), true + + case "PodIOChaosStatus.pid": + if e.complexity.PodIOChaosStatus.Pid == nil { + break + } + + return e.complexity.PodIOChaosStatus.Pid(childComplexity), true + + case "PodIOChaosStatus.startTime": + if e.complexity.PodIOChaosStatus.StartTime == nil { + break + } + + return e.complexity.PodIOChaosStatus.StartTime(childComplexity), true + + case "PodIP.ip": + if e.complexity.PodIP.IP == nil { + break + } + + return e.complexity.PodIP.IP(childComplexity), true + + case "PodNetworkChaos.apiVersion": + if e.complexity.PodNetworkChaos.APIVersion == nil { + break + } + + return e.complexity.PodNetworkChaos.APIVersion(childComplexity), true + + case "PodNetworkChaos.annotations": + if e.complexity.PodNetworkChaos.Annotations == nil { + break + } + + return e.complexity.PodNetworkChaos.Annotations(childComplexity), true + + case "PodNetworkChaos.creationTimestamp": + if e.complexity.PodNetworkChaos.CreationTimestamp == nil { + break + } + + return e.complexity.PodNetworkChaos.CreationTimestamp(childComplexity), true + + case "PodNetworkChaos.deletionGracePeriodSeconds": + if e.complexity.PodNetworkChaos.DeletionGracePeriodSeconds == nil { + break + } + + return e.complexity.PodNetworkChaos.DeletionGracePeriodSeconds(childComplexity), true + + case "PodNetworkChaos.deletionTimestamp": + if e.complexity.PodNetworkChaos.DeletionTimestamp == nil { + break + } + + return e.complexity.PodNetworkChaos.DeletionTimestamp(childComplexity), true + + case "PodNetworkChaos.finalizers": + if e.complexity.PodNetworkChaos.Finalizers == nil { + break + } + + return e.complexity.PodNetworkChaos.Finalizers(childComplexity), true + + case "PodNetworkChaos.generateName": + if e.complexity.PodNetworkChaos.GenerateName == nil { + break + } + + return e.complexity.PodNetworkChaos.GenerateName(childComplexity), true + + case "PodNetworkChaos.generation": + if e.complexity.PodNetworkChaos.Generation == nil { + break + } + + return e.complexity.PodNetworkChaos.Generation(childComplexity), true + + case "PodNetworkChaos.kind": + if e.complexity.PodNetworkChaos.Kind == nil { + break + } + + return e.complexity.PodNetworkChaos.Kind(childComplexity), true + + case "PodNetworkChaos.labels": + if e.complexity.PodNetworkChaos.Labels == nil { + break + } + + return e.complexity.PodNetworkChaos.Labels(childComplexity), true + + case "PodNetworkChaos.name": + if e.complexity.PodNetworkChaos.Name == nil { + break + } + + return e.complexity.PodNetworkChaos.Name(childComplexity), true + + case "PodNetworkChaos.namespace": + if e.complexity.PodNetworkChaos.Namespace == nil { + break + } + + return e.complexity.PodNetworkChaos.Namespace(childComplexity), true + + case "PodNetworkChaos.ownerReferences": + if e.complexity.PodNetworkChaos.OwnerReferences == nil { + break + } + + return e.complexity.PodNetworkChaos.OwnerReferences(childComplexity), true + + case "PodNetworkChaos.pod": + if e.complexity.PodNetworkChaos.Pod == nil { + break + } + + return e.complexity.PodNetworkChaos.Pod(childComplexity), true + + case "PodNetworkChaos.resourceVersion": + if e.complexity.PodNetworkChaos.ResourceVersion == nil { + break + } + + return e.complexity.PodNetworkChaos.ResourceVersion(childComplexity), true + + case "PodNetworkChaos.selfLink": + if e.complexity.PodNetworkChaos.SelfLink == nil { + break + } + + return e.complexity.PodNetworkChaos.SelfLink(childComplexity), true + + case "PodNetworkChaos.spec": + if e.complexity.PodNetworkChaos.Spec == nil { + break + } + + return e.complexity.PodNetworkChaos.Spec(childComplexity), true + + case "PodNetworkChaos.status": + if e.complexity.PodNetworkChaos.Status == nil { + break + } + + return e.complexity.PodNetworkChaos.Status(childComplexity), true + + case "PodNetworkChaos.uid": + if e.complexity.PodNetworkChaos.UID == nil { + break + } + + return e.complexity.PodNetworkChaos.UID(childComplexity), true + + case "PodNetworkChaosSpec.ipSets": + if e.complexity.PodNetworkChaosSpec.IPSets == nil { + break + } + + return e.complexity.PodNetworkChaosSpec.IPSets(childComplexity), true + + case "PodNetworkChaosSpec.iptables": + if e.complexity.PodNetworkChaosSpec.Iptables == nil { + break + } + + return e.complexity.PodNetworkChaosSpec.Iptables(childComplexity), true + + case "PodNetworkChaosSpec.trafficControls": + if e.complexity.PodNetworkChaosSpec.TrafficControls == nil { + break + } + + return e.complexity.PodNetworkChaosSpec.TrafficControls(childComplexity), true + + case "PodNetworkChaosStatus.failedMessage": + if e.complexity.PodNetworkChaosStatus.FailedMessage == nil { + break + } + + return e.complexity.PodNetworkChaosStatus.FailedMessage(childComplexity), true + + case "PodNetworkChaosStatus.observedGeneration": + if e.complexity.PodNetworkChaosStatus.ObservedGeneration == nil { + break + } + + return e.complexity.PodNetworkChaosStatus.ObservedGeneration(childComplexity), true + + case "PodSelectorSpec.annotationSelectors": + if e.complexity.PodSelectorSpec.AnnotationSelectors == nil { + break + } + + return e.complexity.PodSelectorSpec.AnnotationSelectors(childComplexity), true + + case "PodSelectorSpec.fieldSelectors": + if e.complexity.PodSelectorSpec.FieldSelectors == nil { + break + } + + return e.complexity.PodSelectorSpec.FieldSelectors(childComplexity), true + + case "PodSelectorSpec.labelSelectors": + if e.complexity.PodSelectorSpec.LabelSelectors == nil { + break + } + + return e.complexity.PodSelectorSpec.LabelSelectors(childComplexity), true + + case "PodSelectorSpec.namespaces": + if e.complexity.PodSelectorSpec.Namespaces == nil { + break + } + + return e.complexity.PodSelectorSpec.Namespaces(childComplexity), true + + case "PodSelectorSpec.nodeSelectors": + if e.complexity.PodSelectorSpec.NodeSelectors == nil { + break + } + + return e.complexity.PodSelectorSpec.NodeSelectors(childComplexity), true + + case "PodSelectorSpec.nodes": + if e.complexity.PodSelectorSpec.Nodes == nil { + break + } + + return e.complexity.PodSelectorSpec.Nodes(childComplexity), true + + case "PodSelectorSpec.podPhaseSelectors": + if e.complexity.PodSelectorSpec.PodPhaseSelectors == nil { + break + } + + return e.complexity.PodSelectorSpec.PodPhaseSelectors(childComplexity), true + + case "PodSelectorSpec.pods": + if e.complexity.PodSelectorSpec.Pods == nil { + break + } + + return e.complexity.PodSelectorSpec.Pods(childComplexity), true + + case "PodSpec.nodeName": + if e.complexity.PodSpec.NodeName == nil { + break + } + + return e.complexity.PodSpec.NodeName(childComplexity), true + + case "PodStatus.conditions": + if e.complexity.PodStatus.Conditions == nil { + break + } + + return e.complexity.PodStatus.Conditions(childComplexity), true + + case "PodStatus.containerStatuses": + if e.complexity.PodStatus.ContainerStatuses == nil { + break + } + + return e.complexity.PodStatus.ContainerStatuses(childComplexity), true + + case "PodStatus.ephemeralContainerStatuses": + if e.complexity.PodStatus.EphemeralContainerStatuses == nil { + break + } + + return e.complexity.PodStatus.EphemeralContainerStatuses(childComplexity), true + + case "PodStatus.hostIP": + if e.complexity.PodStatus.HostIP == nil { + break + } + + return e.complexity.PodStatus.HostIP(childComplexity), true + + case "PodStatus.initContainerStatuses": + if e.complexity.PodStatus.InitContainerStatuses == nil { + break + } + + return e.complexity.PodStatus.InitContainerStatuses(childComplexity), true + + case "PodStatus.message": + if e.complexity.PodStatus.Message == nil { + break + } + + return e.complexity.PodStatus.Message(childComplexity), true + + case "PodStatus.nominatedNodeName": + if e.complexity.PodStatus.NominatedNodeName == nil { + break + } + + return e.complexity.PodStatus.NominatedNodeName(childComplexity), true + + case "PodStatus.phase": + if e.complexity.PodStatus.Phase == nil { + break + } + + return e.complexity.PodStatus.Phase(childComplexity), true + + case "PodStatus.podIP": + if e.complexity.PodStatus.PodIP == nil { + break + } + + return e.complexity.PodStatus.PodIP(childComplexity), true + + case "PodStatus.podIPs": + if e.complexity.PodStatus.PodIPs == nil { + break + } + + return e.complexity.PodStatus.PodIPs(childComplexity), true + + case "PodStatus.qosClass": + if e.complexity.PodStatus.QosClass == nil { + break + } + + return e.complexity.PodStatus.QosClass(childComplexity), true + + case "PodStatus.reason": + if e.complexity.PodStatus.Reason == nil { + break + } + + return e.complexity.PodStatus.Reason(childComplexity), true + + case "PodStatus.startTime": + if e.complexity.PodStatus.StartTime == nil { + break + } + + return e.complexity.PodStatus.StartTime(childComplexity), true + + case "PodStressChaos.cgroups": + if e.complexity.PodStressChaos.Cgroups == nil { + break + } + + return e.complexity.PodStressChaos.Cgroups(childComplexity), true + + case "PodStressChaos.pod": + if e.complexity.PodStressChaos.Pod == nil { + break + } + + return e.complexity.PodStressChaos.Pod(childComplexity), true + + case "PodStressChaos.processStress": + if e.complexity.PodStressChaos.ProcessStress == nil { + break + } + + return e.complexity.PodStressChaos.ProcessStress(childComplexity), true + + case "PodStressChaos.stressChaos": + if e.complexity.PodStressChaos.StressChaos == nil { + break + } + + return e.complexity.PodStressChaos.StressChaos(childComplexity), true + + case "Process.command": + if e.complexity.Process.Command == nil { + break + } + + return e.complexity.Process.Command(childComplexity), true + + case "Process.fds": + if e.complexity.Process.Fds == nil { + break + } + + return e.complexity.Process.Fds(childComplexity), true + + case "Process.pid": + if e.complexity.Process.Pid == nil { + break + } + + return e.complexity.Process.Pid(childComplexity), true + + case "Process.pod": + if e.complexity.Process.Pod == nil { + break + } + + return e.complexity.Process.Pod(childComplexity), true + + case "ProcessStress.cgroup": + if e.complexity.ProcessStress.Cgroup == nil { + break + } + + return e.complexity.ProcessStress.Cgroup(childComplexity), true + + case "ProcessStress.process": + if e.complexity.ProcessStress.Process == nil { + break + } + + return e.complexity.ProcessStress.Process(childComplexity), true + + case "Query.namespace": + if e.complexity.Query.Namespace == nil { + break + } + + args, err := ec.field_Query_namespace_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.Namespace(childComplexity, args["ns"].(*string)), true + + case "Query.pods": + if e.complexity.Query.Pods == nil { + break + } + + args, err := ec.field_Query_pods_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.Pods(childComplexity, args["selector"].(model.PodSelectorInput)), true + + case "RateSpec.rate": + if e.complexity.RateSpec.Rate == nil { + break + } + + return e.complexity.RateSpec.Rate(childComplexity), true + + case "RawIPSet.cidrAndPorts": + if e.complexity.RawIPSet.CidrAndPorts == nil { + break + } + + return e.complexity.RawIPSet.CidrAndPorts(childComplexity), true + + case "RawIPSet.cidrs": + if e.complexity.RawIPSet.Cidrs == nil { + break + } + + return e.complexity.RawIPSet.Cidrs(childComplexity), true + + case "RawIPSet.ipSetType": + if e.complexity.RawIPSet.IPSetType == nil { + break + } + + return e.complexity.RawIPSet.IPSetType(childComplexity), true + + case "RawIPSet.name": + if e.complexity.RawIPSet.Name == nil { + break + } + + return e.complexity.RawIPSet.Name(childComplexity), true + + case "RawIPSet.setNames": + if e.complexity.RawIPSet.SetNames == nil { + break + } + + return e.complexity.RawIPSet.SetNames(childComplexity), true + + case "RawIPSet.source": + if e.complexity.RawIPSet.Source == nil { + break + } + + return e.complexity.RawIPSet.Source(childComplexity), true + + case "RawIptables.device": + if e.complexity.RawIptables.Device == nil { + break + } + + return e.complexity.RawIptables.Device(childComplexity), true + + case "RawIptables.direction": + if e.complexity.RawIptables.Direction == nil { + break + } + + return e.complexity.RawIptables.Direction(childComplexity), true + + case "RawIptables.ipSets": + if e.complexity.RawIptables.IPSets == nil { + break + } + + return e.complexity.RawIptables.IPSets(childComplexity), true + + case "RawIptables.name": + if e.complexity.RawIptables.Name == nil { + break + } + + return e.complexity.RawIptables.Name(childComplexity), true + + case "RawIptables.source": + if e.complexity.RawIptables.Source == nil { + break + } + + return e.complexity.RawIptables.Source(childComplexity), true + + case "RawTrafficControl.bandwidth": + if e.complexity.RawTrafficControl.Bandwidth == nil { + break + } + + return e.complexity.RawTrafficControl.Bandwidth(childComplexity), true + + case "RawTrafficControl.corrupt": + if e.complexity.RawTrafficControl.Corrupt == nil { + break + } + + return e.complexity.RawTrafficControl.Corrupt(childComplexity), true + + case "RawTrafficControl.delay": + if e.complexity.RawTrafficControl.Delay == nil { + break + } + + return e.complexity.RawTrafficControl.Delay(childComplexity), true + + case "RawTrafficControl.device": + if e.complexity.RawTrafficControl.Device == nil { + break + } + + return e.complexity.RawTrafficControl.Device(childComplexity), true + + case "RawTrafficControl.duplicate": + if e.complexity.RawTrafficControl.Duplicate == nil { + break + } + + return e.complexity.RawTrafficControl.Duplicate(childComplexity), true + + case "RawTrafficControl.ipSet": + if e.complexity.RawTrafficControl.IPSet == nil { + break + } + + return e.complexity.RawTrafficControl.IPSet(childComplexity), true + + case "RawTrafficControl.loss": + if e.complexity.RawTrafficControl.Loss == nil { + break + } + + return e.complexity.RawTrafficControl.Loss(childComplexity), true + + case "RawTrafficControl.rate": + if e.complexity.RawTrafficControl.Rate == nil { + break + } + + return e.complexity.RawTrafficControl.Rate(childComplexity), true + + case "RawTrafficControl.source": + if e.complexity.RawTrafficControl.Source == nil { + break + } + + return e.complexity.RawTrafficControl.Source(childComplexity), true + + case "RawTrafficControl.type": + if e.complexity.RawTrafficControl.Type == nil { + break + } + + return e.complexity.RawTrafficControl.Type(childComplexity), true + + case "Record.id": + if e.complexity.Record.Id == nil { + break + } + + return e.complexity.Record.Id(childComplexity), true + + case "Record.phase": + if e.complexity.Record.Phase == nil { + break + } + + return e.complexity.Record.Phase(childComplexity), true + + case "Record.selectorKey": + if e.complexity.Record.SelectorKey == nil { + break + } + + return e.complexity.Record.SelectorKey(childComplexity), true + + case "ReorderSpec.correlation": + if e.complexity.ReorderSpec.Correlation == nil { + break + } + + return e.complexity.ReorderSpec.Correlation(childComplexity), true + + case "ReorderSpec.gap": + if e.complexity.ReorderSpec.Gap == nil { + break + } + + return e.complexity.ReorderSpec.Gap(childComplexity), true + + case "ReorderSpec.reorder": + if e.complexity.ReorderSpec.Reorder == nil { + break + } + + return e.complexity.ReorderSpec.Reorder(childComplexity), true + + case "StressChaos.apiVersion": + if e.complexity.StressChaos.APIVersion == nil { + break + } + + return e.complexity.StressChaos.APIVersion(childComplexity), true + + case "StressChaos.annotations": + if e.complexity.StressChaos.Annotations == nil { + break + } + + return e.complexity.StressChaos.Annotations(childComplexity), true + + case "StressChaos.creationTimestamp": + if e.complexity.StressChaos.CreationTimestamp == nil { + break + } + + return e.complexity.StressChaos.CreationTimestamp(childComplexity), true + + case "StressChaos.deletionGracePeriodSeconds": + if e.complexity.StressChaos.DeletionGracePeriodSeconds == nil { + break + } + + return e.complexity.StressChaos.DeletionGracePeriodSeconds(childComplexity), true + + case "StressChaos.deletionTimestamp": + if e.complexity.StressChaos.DeletionTimestamp == nil { + break + } + + return e.complexity.StressChaos.DeletionTimestamp(childComplexity), true + + case "StressChaos.finalizers": + if e.complexity.StressChaos.Finalizers == nil { + break + } + + return e.complexity.StressChaos.Finalizers(childComplexity), true + + case "StressChaos.generateName": + if e.complexity.StressChaos.GenerateName == nil { + break + } + + return e.complexity.StressChaos.GenerateName(childComplexity), true + + case "StressChaos.generation": + if e.complexity.StressChaos.Generation == nil { + break + } + + return e.complexity.StressChaos.Generation(childComplexity), true + + case "StressChaos.kind": + if e.complexity.StressChaos.Kind == nil { + break + } + + return e.complexity.StressChaos.Kind(childComplexity), true + + case "StressChaos.labels": + if e.complexity.StressChaos.Labels == nil { + break + } + + return e.complexity.StressChaos.Labels(childComplexity), true + + case "StressChaos.name": + if e.complexity.StressChaos.Name == nil { + break + } + + return e.complexity.StressChaos.Name(childComplexity), true + + case "StressChaos.namespace": + if e.complexity.StressChaos.Namespace == nil { + break + } + + return e.complexity.StressChaos.Namespace(childComplexity), true + + case "StressChaos.ownerReferences": + if e.complexity.StressChaos.OwnerReferences == nil { + break + } + + return e.complexity.StressChaos.OwnerReferences(childComplexity), true + + case "StressChaos.podstress": + if e.complexity.StressChaos.Podstress == nil { + break + } + + return e.complexity.StressChaos.Podstress(childComplexity), true + + case "StressChaos.resourceVersion": + if e.complexity.StressChaos.ResourceVersion == nil { + break + } + + return e.complexity.StressChaos.ResourceVersion(childComplexity), true + + case "StressChaos.selfLink": + if e.complexity.StressChaos.SelfLink == nil { + break + } + + return e.complexity.StressChaos.SelfLink(childComplexity), true + + case "StressChaos.spec": + if e.complexity.StressChaos.Spec == nil { + break + } + + return e.complexity.StressChaos.Spec(childComplexity), true + + case "StressChaos.uid": + if e.complexity.StressChaos.UID == nil { + break + } + + return e.complexity.StressChaos.UID(childComplexity), true + + case "StressChaosSpec.containerNames": + if e.complexity.StressChaosSpec.ContainerNames == nil { + break + } + + return e.complexity.StressChaosSpec.ContainerNames(childComplexity), true + + case "StressChaosSpec.duration": + if e.complexity.StressChaosSpec.Duration == nil { + break + } + + return e.complexity.StressChaosSpec.Duration(childComplexity), true + + case "StressChaosSpec.mode": + if e.complexity.StressChaosSpec.Mode == nil { + break + } + + return e.complexity.StressChaosSpec.Mode(childComplexity), true + + case "StressChaosSpec.selector": + if e.complexity.StressChaosSpec.Selector == nil { + break + } + + return e.complexity.StressChaosSpec.Selector(childComplexity), true + + case "StressChaosSpec.stressngStressors": + if e.complexity.StressChaosSpec.StressngStressors == nil { + break + } + + return e.complexity.StressChaosSpec.StressngStressors(childComplexity), true + + case "StressChaosSpec.stressors": + if e.complexity.StressChaosSpec.Stressors == nil { + break + } + + return e.complexity.StressChaosSpec.Stressors(childComplexity), true + + case "StressChaosSpec.value": + if e.complexity.StressChaosSpec.Value == nil { + break + } + + return e.complexity.StressChaosSpec.Value(childComplexity), true + + case "StressChaosStatus.conditions": + if e.complexity.StressChaosStatus.Conditions == nil { + break + } + + return e.complexity.StressChaosStatus.Conditions(childComplexity), true + + case "StressChaosStatus.experiment": + if e.complexity.StressChaosStatus.Experiment == nil { + break + } + + return e.complexity.StressChaosStatus.Experiment(childComplexity), true + + case "StressChaosStatus.instances": + if e.complexity.StressChaosStatus.Instances == nil { + break + } + + return e.complexity.StressChaosStatus.Instances(childComplexity), true + + case "Stressors.cpuStressor": + if e.complexity.Stressors.CPUStressor == nil { + break + } + + return e.complexity.Stressors.CPUStressor(childComplexity), true + + case "Stressors.memoryStressor": + if e.complexity.Stressors.MemoryStressor == nil { + break + } + + return e.complexity.Stressors.MemoryStressor(childComplexity), true + + case "Timespec.nsec": + if e.complexity.Timespec.Nsec == nil { + break + } + + return e.complexity.Timespec.Nsec(childComplexity), true + + case "Timespec.sec": + if e.complexity.Timespec.Sec == nil { + break + } + + return e.complexity.Timespec.Sec(childComplexity), true + + } + return 0, false +} + +func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { + rc := graphql.GetOperationContext(ctx) + ec := executionContext{rc, e} + first := true + + switch rc.Operation.Operation { + case ast.Query: + return func(ctx context.Context) *graphql.Response { + if !first { + return nil + } + first = false + data := ec._Query(ctx, rc.Operation.SelectionSet) + var buf bytes.Buffer + data.MarshalGQL(&buf) + + return &graphql.Response{ + Data: buf.Bytes(), + } + } + case ast.Mutation: + return func(ctx context.Context) *graphql.Response { + if !first { + return nil + } + first = false + data := ec._Mutation(ctx, rc.Operation.SelectionSet) + var buf bytes.Buffer + data.MarshalGQL(&buf) + + return &graphql.Response{ + Data: buf.Bytes(), + } + } + case ast.Subscription: + next := ec._Logger(ctx, rc.Operation.SelectionSet) + + var buf bytes.Buffer + return func(ctx context.Context) *graphql.Response { + buf.Reset() + data := next() + + if data == nil { + return nil + } + data.MarshalGQL(&buf) + + return &graphql.Response{ + Data: buf.Bytes(), + } + } + + default: + return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation")) + } +} + +type executionContext struct { + *graphql.OperationContext + *executableSchema +} + +func (ec *executionContext) introspectSchema() (*introspection.Schema, error) { + if ec.DisableIntrospection { + return nil, errors.New("introspection disabled") + } + return introspection.WrapSchema(parsedSchema), nil +} + +func (ec *executionContext) introspectType(name string) (*introspection.Type, error) { + if ec.DisableIntrospection { + return nil, errors.New("introspection disabled") + } + return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil +} + +var sources = []*ast.Source{ + {Name: "server/schema.graphqls", Input: `# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +directive @goModel(model: String, models: [String!]) on OBJECT + | INPUT_OBJECT + | SCALAR + | ENUM + | INTERFACE + | UNION + +directive @goField(forceResolver: Boolean, name: String) on INPUT_FIELD_DEFINITION + | FIELD_DEFINITION + +scalar Time +scalar Map +scalar Int64 + +schema { + query: Query + mutation: Mutation + subscription: Logger +} + +type Query { + namespace(ns: String): [Namespace!] + pods(selector: PodSelectorInput!): [Pod!] +} + +type Mutation { + pod(ns: String! = "default", name: String!): MutablePod +} + +type Logger { + component(ns: String! = "chaos-mesh", component: Component!): String! @goField(forceResolver: true) + pod(ns: String! = "default", name: String!): String! @goField(forceResolver: true) +} + +type Namespace { + ns: String! + component(component: Component!): [Pod!] @goField(forceResolver: true) + pod(name: String): [Pod!] @goField(forceResolver: true) + stresschaos(name: String): [StressChaos!] @goField(forceResolver: true) + iochaos(name: String): [IOChaos!] @goField(forceResolver: true) + podiochaos(name: String): [PodIOChaos!] @goField(forceResolver: true) + httpchaos(name: String): [HTTPChaos!] @goField(forceResolver: true) + podhttpchaos(name: String): [PodHTTPChaos!] @goField(forceResolver: true) + networkchaos(name: String): [NetworkChaos!] @goField(forceResolver: true) + podnetworkchaos(name: String): [PodNetworkChaos!] @goField(forceResolver: true) +} + +type OwnerReference @goModel(model: "k8s.io/apimachinery/pkg/apis/meta/v1.OwnerReference") { + kind: String! + apiVersion: String! + name: String! + uid: String! + controller: Boolean + blockOwnerDeletion: Boolean +} + +enum Component { + MANAGER + DAEMON + DASHBOARD + DNSSERVER +} + +type Process { + pod: Pod! + pid: String! + command: String! + fds: [Fd!] @goField(forceResolver: true) +} + +type KillProcessResult { + pid: String! + command: String! +} + +type Fd { + fd: String! + target: String! +} + +# PodSelectorInput defines the some selectors to select objects. +# If the all selectors are empty, all objects will be used in chaos experiment. +input PodSelectorInput { + # namespaces is a set of namespace to which objects belong. + namespaces: [String!] + + # nodes is a set of node name and objects must belong to these nodes. + nodes: [String!] + + # pods is a map of string keys and a set values that used to select pods. + # The key defines the namespace which pods belong, + # and the each values is a set of pod names. + pods: Map + + # map of string keys and values that can be used to select nodes. + # Selector which must match a node's labels, + # and objects must belong to these selected nodes. + nodeSelectors: Map + + # map of string keys and values that can be used to select objects. + # A selector based on fields. + fieldSelectors: Map + + # map of string keys and values that can be used to select objects. + # A selector based on labels. + labelSelectors: Map + + # map of string keys and values that can be used to select objects. + # A selector based on annotations. + annotationSelectors: Map + + # podPhaseSelectors is a set of condition of a pod at the current time. + # supported value: Pending / Running / Succeeded / Failed / Unknown + podPhaseSelectors: [String!] +} + +type MutablePod { + pod: Pod! + killProcesses(pids: [String!]): [KillProcessResult!] @goField(forceResolver: true) + cleanTcs(devices: [String!]): [String!] @goField(forceResolver: true) + cleanIptables(chains: [String!]): [String!] @goField(forceResolver: true) +} + +type Pod @goModel(model: "k8s.io/api/core/v1.Pod") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + spec: PodSpec! + status: PodStatus! + + logs: String! @goField(forceResolver: true) + daemon: Pod @goField(forceResolver: true) + processes: [Process!] @goField(forceResolver: true) + mounts: [String!] @goField(forceResolver: true) + ipset: String! @goField(forceResolver: true) + tcQdisc: [String!] @goField(forceResolver: true) + iptables: [String!] @goField(forceResolver: true) +} + +# PodStatus represents information about the status of a pod. Status may trail the actual +# state of a system, especially if the node that hosts the pod cannot contact the control +# plane. +type PodStatus @goModel(model: "k8s.io/api/core/v1.PodStatus") { + # The phase of a Pod is a simple, high-level summary of where the Pod is in its lifecycle. + # The conditions array, the reason and message fields, and the individual container status + # arrays contain more detail about the pod's status. + # There are five possible phase values: + # + # Pending: The pod has been accepted by the Kubernetes system, but one or more of the + # container images has not been created. This includes time before being scheduled as + # well as time spent downloading images over the network, which could take a while. + # Running: The pod has been bound to a node, and all of the containers have been created. + # At least one container is still running, or is in the process of starting or restarting. + # Succeeded: All containers in the pod have terminated in success, and will not be restarted. + # Failed: All containers in the pod have terminated, and at least one container has + # terminated in failure. The container either exited with non-zero status or was terminated + # by the system. + # Unknown: For some reason the state of the pod could not be obtained, typically due to an + # error in communicating with the host of the pod. + # + # More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-phase + phase: String! + + # Current service state of pod. + # More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions + conditions: [PodCondition!] + + # A human readable message indicating details about why the pod is in this condition. + message: String! + + # A brief CamelCase message indicating details about why the pod is in this state. + # e.g. 'Evicted' + reason: String! + + # nominatedNodeName is set only when this pod preempts other pods on the node, but it cannot be + # scheduled right away as preemption victims receive their graceful termination periods. + # This field does not guarantee that the pod will be scheduled on this node. Scheduler may decide + # to place the pod elsewhere if other nodes become available sooner. Scheduler may also decide to + # give the resources on this node to a higher priority pod that is created after preemption. + # As a result, this field may be different than PodSpec.nodeName when the pod is + # scheduled. + nominatedNodeName: String! + + # IP address of the host to which the pod is assigned. Empty if not yet scheduled. + hostIP: String! + + # IP address allocated to the pod. Routable at least within the cluster. + # Empty if not yet allocated. + podIP: String! + + # podIPs holds the IP addresses allocated to the pod. If this field is specified, the 0th entry must + # match the podIP field. Pods may be allocated at most 1 value for each of IPv4 and IPv6. This list + # is empty if no IPs have been allocated yet. + podIPs: [PodIP!] + + # RFC 3339 date and time at which the object was acknowledged by the Kubelet. + # This is before the Kubelet pulled the container image(s) for the pod. + startTime: Time + + # The list has one entry per init container in the manifest. The most recent successful + # init container will have ready = true, the most recently started container will have + # startTime set. + # More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-and-container-status + initContainerStatuses: [ContainerStatus!] + + # The list has one entry per container in the manifest. Each entry is currently the output + # of ` + "`" + `docker inspect` + "`" + `. + # More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-and-container-status + containerStatuses: [ContainerStatus!] + + # The Quality of Service (QOS) classification assigned to the pod based on resource requirements + # See PodQOSClass type for available QOS classes + # More info: https://git.k8s.io/community/contributors/design-proposals/node/resource-qos.md + qosClass: String! + + # Status for any ephemeral containers that have run in this pod. + # This field is alpha-level and is only populated by servers that enable the EphemeralContainers feature. + ephemeralContainerStatuses: [ContainerStatus!] +} + +# IP address information for entries in the (plural) PodIPs field. +# Each entry includes: +# IP: An IP address allocated to the pod. Routable at least within the cluster. +type PodIP @goModel(model: "k8s.io/api/core/v1.PodIP") { + # ip is an IP address (IPv4 or IPv6) assigned to the pod + ip: String! +} + +# PodCondition contains details for the current condition of this pod. +type PodCondition @goModel(model: "k8s.io/api/core/v1.PodCondition") { + # Type is the type of the condition. + # More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions + type: String! + + # Status is the status of the condition. + # Can be True, False, Unknown. + # More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions + status: String! + + # Last time we probed the condition. + lastProbeTime: Time + + # Last time the condition transitioned from one status to another. + lastTransitionTime: Time + + # Unique, one-word, CamelCase reason for the condition's last transition. + reason: String + + # Human-readable message indicating details about last transition. + message: String +} + +# ContainerStatus contains details for the current status of this container. +type ContainerStatus @goModel(model: "k8s.io/api/core/v1.ContainerStatus") { + # This must be a DNS_LABEL. Each container in a pod must have a unique name. + # Cannot be updated. + name: String! + + # Details about the container's current condition. + State: ContainerState + + # Details about the container's last termination condition. + lastTerminationState: ContainerState + + # Specifies whether the container has passed its readiness probe. + ready: Boolean! + + # The number of times the container has been restarted, currently based on + # the number of dead containers that have not yet been removed. + # Note that this is calculated from dead containers. But those containers are subject to + # garbage collection. This value will get capped at 5 by GC. + restartCount: Int! + + # The image the container is running. + # More info: https://kubernetes.io/docs/concepts/containers/images + # TODO(dchen1107): Which image the container is running with? + image: String! + + # ImageID of the container's image. + imageID: String! + + # Container's ID in the format 'docker://'. + containerID: String! + + # Specifies whether the container has passed its startup probe. + # Initialized as false, becomes true after startupProbe is considered successful. + # Resets to false when the container is restarted, or if kubelet loses state temporarily. + # Is always true when no startupProbe is defined. + started: Boolean +} + +# ContainerState holds a possible state of container. +# Only one of its members may be specified. +# If none of them is specified, the default one is ContainerStateWaiting. +type ContainerState @goModel(model: "k8s.io/api/core/v1.ContainerState") { + # Details about a waiting container + waiting: ContainerStateWaiting + + # Details about a running container + running: ContainerStateRunning + + # Details about a terminated container + terminated: ContainerStateTerminated +} + +# ContainerStateWaiting is a waiting state of a container. +type ContainerStateWaiting @goModel(model: "k8s.io/api/core/v1.ContainerStateWaiting") { + # (brief) reason the container is not yet running. + reason: String + + # Message regarding why the container is not yet running. + message: String +} + +# ContainerStateRunning is a running state of a container. +type ContainerStateRunning @goModel(model: "k8s.io/api/core/v1.ContainerStateRunning") { + # Time at which the container was last (re-)started + startedAt: Time +} + +# ContainerStateTerminated is a terminated state of a container. +type ContainerStateTerminated @goModel(model: "k8s.io/api/core/v1.ContainerStateTerminated") { + # Exit status from the last termination of the container + exitCode: Int! + + # Signal from the last termination of the container + signal: Int + + # (brief) reason from the last termination of the container + reason: String + + # Message regarding the last termination of the container + message: String + + #Time at which previous execution of the container started + startedAt: Time + + # Time at which the container last terminated + finishedAt: Time + + # Container's ID in the format 'docker://' + containerID: String +} + + +# TODO: add more fields +type PodSpec @goModel(model: "k8s.io/api/core/v1.PodSpec") { + # ndeName is a request to schedule this pod onto a specific node. If it is non-empty, + # the scheduler simply schedules this pod onto that node, assuming that it fits resource + # requirements. + nodeName: String! + +} + +type PodIOChaos @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodIOChaos") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + spec: PodIOChaosSpec! + status: PodIOChaosStatus! + + pod: Pod! @goField(forceResolver: true) + ios: [IOChaos!] @goField(forceResolver: true) +} + +# PodIOChaosSpec defines the desired state of PodIOChaos +type PodIOChaosSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodIOChaosSpec") { + # volumeMountPath represents the target mount path + # It must be a root of mount path now. + volumeMountPath: String! + + container: String + + # actions are a list of IOChaos actions + actions: [IOChaosAction!] +} + +type PodIOChaosStatus @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodIOChaosStatus") { + + # pid represents a running toda process id + pid: Int + + # startTime represents the start time of a toda process + startTime: Int + failedMessage: String + observedGeneration: Int +} + +# IOChaosAction defines an possible action of IOChaos +type IOChaosAction @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.IOChaosAction") { + type: String! + + # path represents a glob of injecting path + path: String! + + # methods represents the method that the action will inject in + methods: [String!] + + # percent represents the percent probability of injecting this action + percent: Int + + # faults represents the fault to inject + faults: [IoFault!] + + # Latency represents the latency to inject + latency: String + + # attrOverrides represents the attribution to override + ino: Int64 + size: Int64 + blocks: Int64 + atime: Timespec @goField(forceResolver: true) + mtime: Timespec @goField(forceResolver: true) + ctime: Timespec @goField(forceResolver: true) + kind: String # the file kind + perm: Int + nlink: Int64 + uid: Int64 + gid: Int64 + rdev: Int64 + + # MistakeSpec represents the mistake to inject + + # filling determines what is filled in the miskate data. + filling: String + + # there will be [1, MaxOccurrences] segments of wrong data. + maxOccurrences: Int64 @goField(forceResolver: true) + + # max length of each wrong data segment in bytes + maxLength: Int64 @goField(forceResolver: true) + + # source represents the source of current rules + source: String! +} + +type IoFault @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.IoFault") { + errno: Int! + weight: Int! +} + +# Timespec represents a time +type Timespec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.Timespec") { + sec: Int! + nsec: Int! +} + + +type IOChaos @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.IOChaos") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + spec: IOChaosSpec! + status: IOChaosStatus! + + podios: [PodIOChaos!] @goField(forceResolver: true) +} + +# IOChaosSpec defines the desired state of IOChaos +type IOChaosSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.IOChaosSpec") { + # containerNames indicates list of the name of affected container. + # If not set, the first container will be injected + containerNames: [String!] + + # selector is used to select pods that are used to inject chaos action. + selector: PodSelectorSpec! + + # mode defines the mode to run chaos action. + # supported mode: one / all / fixed / fixed-percent / random-max-percent + mode: String! + + # value is required when the mode is set to ` + "`" + `FixedPodMode` + "`" + ` / ` + "`" + `FixedPercentPodMod` + "`" + ` / ` + "`" + `RandomMaxPercentPodMod` + "`" + `. + # If ` + "`" + `FixedPodMode` + "`" + `, provide an integer of pods to do chaos action. + # If ` + "`" + `FixedPercentPodMod` + "`" + `, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + # IF ` + "`" + `RandomMaxPercentPodMod` + "`" + `, provide a number from 0-100 to specify the max percent of pods to do chaos action + value: String + + + # action defines the specific pod chaos action. + # Supported action: latency / fault / attrOverride / mistake + action: String! + + # delay defines the value of I/O chaos action delay. + # A delay string is a possibly signed sequence of + # decimal numbers, each with optional fraction and a unit suffix, + # such as "300ms". + # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + delay: String + + # errno defines the error code that returned by I/O action. + # refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html + errno: Int + + # attr defines the overrided attribution + attr: AttrOverrideSpec + + # mistake defines what types of incorrectness are injected to IO operations + mistake: MistakeSpec + + # path defines the path of files for injecting I/O chaos action. + path: String + + # methods defines the I/O methods for injecting I/O chaos action. + # default: all I/O methods. + methods: [String!] + + # percent defines the percentage of injection errors and provides a number from 0-100. + # default: 100. + percent: Int + + # volumePath represents the mount path of injected volume + volumePath: String! + + # duration represents the duration of the chaos action. + # It is required when the action is ` + "`" + `PodFailureAction` + "`" + `. + # 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". + duration: String +} + +# AttrOverrideSpec represents an override of attribution +type AttrOverrideSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.AttrOverrideSpec") { + ino: Int + size: Int + blocks: Int + atime: Timespec + mtime: Timespec + ctime: Timespec + kind: String # the file kind + perm: Int + nlink: Int + uid: Int + gid: Int + rdev: Int +} + +# MistakeSpec represents one type of mistake +type MistakeSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.MistakeSpec") { + # filling determines what is filled in the miskate data. + filling: String + + # there will be [1, MaxOccurrences] segments of wrong data. + maxOccurrences: Int + + # max length of each wrong data segment in bytes + maxLength: Int +} + +type IOChaosStatus @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.IOChaosStatus") { + # conditions represents the current global condition of the chaos + conditions: [ChaosCondition!] + + # experiment records the last experiment state. + experiment: ExperimentStatus + + # instances always specifies podhttpchaos generation or empty + instances: Map +} + +type PodHTTPChaos @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaos") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + spec: PodHttpChaosSpec! + status: PodHttpChaosStatus! + + pod: Pod! @goField(forceResolver: true) +} + +# PodHttpChaosSpec defines the desired state of PodHttpChaos. +type PodHttpChaosSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosSpec") { + # rules are a list of injection rule for http request. + rules: [PodHttpChaosRule!]! + + # tls is the tls config, + # will be override if there are multiple HTTPChaos experiments are applied + tls: PodHttpChaosTLS +} + +# PodHttpChaosStatus defines the actual state of PodHttpChaos. +type PodHttpChaosStatus @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosStatus") { + # pid represents a running tproxy process id. + pid: Int + + # startTime represents the start time of a tproxy process. + startTime: Int + + failedMessage: String + observedGeneration: Int +} + +# PodHttpChaosTLS contains the tls config for HTTPChaos +type PodHttpChaosTLS @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosTLS") { + # secretName represents the name of required secret resource + secretName: String! + + # secretNamespace represents the namespace of required secret resource, + # should be the same with deployment/chaos-controller-manager in most cases + secretNamespace: String! + + # certName represents the data name of cert file in secret, ` + "`" + `tls.crt` + "`" + ` for example + certName: String! + + # keyName represents the data name of key file in secret, ` + "`" + `tls.key` + "`" + ` for example + keyName: String! + + # caName represents the data name of ca file in secret, ` + "`" + `ca.crt` + "`" + ` for example + caName: String +} + +# PodHttpChaosRule defines the injection rule for http. +type PodHttpChaosRule @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosRule") { + # target is the object to be selected and injected, . + target: String! + + selector: PodHttpChaosSelector! + + actions: PodHttpChaosActions! + + # source represents the source of current rules + source: String! + + # port represents the target port to be proxy of. + port: Int! +} + +type PodHttpChaosSelector @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosSelector") { + # port represents the target port to be proxy of. + port: Int + + # path is a rule to select target by uri path in http request. + path: String + + # method is a rule to select target by http method in request. + method: String + + # code is a rule to select target by http status code in response. + code: Int + + # requestHeaders is a rule to select target by http headers in request. + # The key-value pairs represent header name and header value pairs. + requestHeaders: Map + + # responseHeaders is a rule to select target by http headers in response. + # The key-value pairs represent header name and header value pairs. + responseHeaders: Map +} + +# PodHttpChaosAction defines possible actions of HttpChaos. +type PodHttpChaosActions @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosActions") { + # abort is a rule to abort a http session. + abort: Boolean + + # delay represents the delay of the target request/response. + # A duration string is a possibly unsigned sequence of + # decimal numbers, each with optional fraction and a unit suffix, + # such as "300ms", "2h45m". + # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + delay: String + + # replace is a rule to replace some contents in target. + replace: PodHttpChaosReplaceActions + + # patch is a rule to patch some contents in target. + patch: PodHttpChaosPatchActions +} + +type HTTPChaos @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.HTTPChaos") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + spec: HTTPChaosSpec! + status: HTTPChaosStatus! + + podhttp: [PodHTTPChaos!] @goField(forceResolver: true) +} + +type HTTPChaosSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.HTTPChaosSpec") { + # selector is used to select pods that are used to inject chaos action. + selector: PodSelectorSpec! + + # mode defines the mode to run chaos action. + # supported mode: one / all / fixed / fixed-percent / random-max-percent + mode: String! + + # value is required when the mode is set to ` + "`" + `FixedPodMode` + "`" + ` / ` + "`" + `FixedPercentPodMod` + "`" + ` / ` + "`" + `RandomMaxPercentPodMod` + "`" + `. + # If ` + "`" + `FixedPodMode` + "`" + `, provide an integer of pods to do chaos action. + # If ` + "`" + `FixedPercentPodMod` + "`" + `, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + # IF ` + "`" + `RandomMaxPercentPodMod` + "`" + `, provide a number from 0-100 to specify the max percent of pods to do chaos action + value: String + + # target is the object to be selected and injected. + target: String! + + # abort is a rule to abort a http session. + abort: Boolean + + # delay represents the delay of the target request/response. + # A duration string is a possibly unsigned sequence of + # decimal numbers, each with optional fraction and a unit suffix, + # such as "300ms", "2h45m". + # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + delay: String + + # replace is a rule to replace some contents in target. + replace: PodHttpChaosReplaceActions + + # patch is a rule to patch some contents in target. + patch: PodHttpChaosPatchActions + + # port represents the target port to be proxy of. + port: Int + + # path is a rule to select target by uri path in http request. + path: String + + # method is a rule to select target by http method in request. + method: String + + # code is a rule to select target by http status code in response. + code: Int + + # requestHeaders is a rule to select target by http headers in request. + # The key-value pairs represent header name and header value pairs. + requestHeaders: Map + + # responseHeaders is a rule to select target by http headers in response. + # The key-value pairs represent header name and header value pairs. + responseHeaders: Map + + # duration represents the duration of the chaos action. + duration: String +} + +# PodSelectorSpec defines the some selectors to select objects. +# If the all selectors are empty, all objects will be used in chaos experiment. +type PodSelectorSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodSelectorSpec") { + # namespaces is a set of namespace to which objects belong. + namespaces: [String!] + + # nodes is a set of node name and objects must belong to these nodes. + nodes: [String!] + + # pods is a map of string keys and a set values that used to select pods. + # The key defines the namespace which pods belong, + # and the each values is a set of pod names. + pods: Map + + # map of string keys and values that can be used to select nodes. + # Selector which must match a node's labels, + # and objects must belong to these selected nodes. + nodeSelectors: Map + + # map of string keys and values that can be used to select objects. + # A selector based on fields. + fieldSelectors: Map + + # map of string keys and values that can be used to select objects. + # A selector based on labels. + labelSelectors: Map + + # map of string keys and values that can be used to select objects. + # A selector based on annotations. + annotationSelectors: Map + + # podPhaseSelectors is a set of condition of a pod at the current time. + # supported value: Pending / Running / Succeeded / Failed / Unknown + podPhaseSelectors: [String!] +} + +type PodHttpChaosReplaceActions @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosReplaceActions") { + # path is rule to to replace uri path in http request. + path: String + + # method is a rule to replace http method in request. + method: String + + # code is a rule to replace http status code in response. + code: Int + + # body is a rule to replace http message body in target. + body: String + + # queries is a rule to replace uri queries in http request. + # For example, with value ` + "`" + `{ "foo": "unknown" }` + "`" + `, the ` + "`" + `/?foo=bar` + "`" + ` will be altered to ` + "`" + `/?foo=unknown` + "`" + `, + queries: Map + + # headers is a rule to replace http headers of target. + # The key-value pairs represent header name and header value pairs. + headers: Map +} + +# PodHttpChaosPatchActions defines possible patch-actions of HttpChaos. +type PodHttpChaosPatchActions @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosPatchActions") { + # body is a rule to patch message body of target. + body: PodHttpChaosPatchBodyAction + + # queries is a rule to append uri queries of target(Request only). + # For example: ` + "`" + `[["foo", "bar"], ["foo", "unknown"]]` + "`" + `. + queries: [[String!]!] + + # headers is a rule to append http headers of target. + # For example: ` + "`" + `[["Set-Cookie", ""], ["Set-Cookie", ""]]` + "`" + `. + headers: [[String!]!] +} + +# PodHttpChaosPatchBodyAction defines patch body action of HttpChaos. +type PodHttpChaosPatchBodyAction @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosPatchBodyAction") { + # type represents the patch type, only support ` + "`" + `JSON` + "`" + ` as [merge patch json](https://tools.ietf.org/html/rfc7396) currently. + type: String! + + # value is the patch contents. + value: String! +} + +type HTTPChaosStatus @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.HTTPChaosStatus") { + # conditions represents the current global condition of the chaos + conditions: [ChaosCondition!] + + # experiment records the last experiment state. + experiment: ExperimentStatus + + # instances always specifies podhttpchaos generation or empty + instances: Map +} + +type ChaosCondition @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.ChaosCondition") { + type: String! + status: String! + reason: String +} + +type ExperimentStatus @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.ExperimentStatus") { + desiredPhase: String! + + # Records are used to track the running status + Records: [Record!] +} + +type Record @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.Record") { + id: String! + selectorKey: String! + phase: String! +} + +type PodNetworkChaos @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodNetworkChaos") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + spec: PodNetworkChaosSpec! + status: PodNetworkChaosStatus! + + pod: Pod! @goField(forceResolver: true) +} + +# PodNetworkChaosSpec defines the desired state of PodNetworkChaos +type PodNetworkChaosSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodNetworkChaosSpec") { + # The ipset on the pod + ipSets: [RawIPSet!] + + # The iptables rules on the pod + iptables: [RawIptables!] + + # The tc rules on the pod + trafficControls: [RawTrafficControl!] +} + +# PodNetworkChaosStatus defines the observed state of PodNetworkChaos +type PodNetworkChaosStatus @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodNetworkChaosStatus") { + failedMessage: String! + observedGeneration: Int! +} + +# RawIPSet represents an ipset on specific pod +type RawIPSet @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.RawIPSet") { + # The name of ipset + name: String! + + ipSetType: String! + + # The contents of ipset + cidrs: [String!]! + + # The contents of ipset. + # Only available when IPSetType is NetPortIPSet. + cidrAndPorts: [CidrAndPort!] + + # The contents of ipset. + # Only available when IPSetType is SetIPSet. + setNames: [String!]! + + # The name and namespace of the source network chaos + source: String! +} + +type CidrAndPort @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.CidrAndPort") { + cidr: String! + port: Int! +} + +# RawIptables represents the iptables rules on specific pod +type RawIptables @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.RawIptables") { + # The name of iptables chain + name: String! + + # The name of related ipset + ipSets: [String!]! + + # The block direction of this iptables rule + direction: String! + + # The name and namespace of the source network chaos + source: String! + + # Device represents the network device to be affected. + device: String +} + +# RawTrafficControl represents the traffic control chaos on specific pod +type RawTrafficControl @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.RawTrafficControl") { + # The type of traffic control + type: String! + + # delay represents the detail about delay action + delay: DelaySpec + + # loss represents the detail about loss action + loss: LossSpec + + # duplicateSpec represents the detail about loss action + duplicate: DuplicateSpec + + # corrupt represents the detail about corrupt action + corrupt: CorruptSpec + + # bandwidth represents the detail about bandwidth control action + bandwidth: BandwidthSpec + + # Rate represents the detail about rate control action + rate: RateSpec + + # The name of target ipset + ipSet: String + + # The name and namespace of the source network chaos + source: String + + # Device represents the network device to be affected. + device: String +} + +# DelaySpec defines detail of a delay action +type DelaySpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.DelaySpec") { + latency: String! + correlation: String + jitter: String + reorder: ReorderSpec +} + +# LossSpec defines detail of a loss action +type LossSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.LossSpec") { + loss: String! + correlation: String +} + +# DuplicateSpec defines detail of a duplicate action +type DuplicateSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.DuplicateSpec") { + duplicate: String! + correlation: String +} + +# CorruptSpec defines detail of a corrupt action +type CorruptSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.CorruptSpec") { + corrupt: String! + correlation: String +} + +# BandwidthSpec defines detail of bandwidth limit. +type BandwidthSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.BandwidthSpec") { + # rate is the speed knob. Allows bps, kbps, mbps, gbps, tbps unit. bps means bytes per second. + rate: String! + + # limit is the number of bytes that can be queued waiting for tokens to become available. + limit: Int! + + # buffer is the maximum amount of bytes that tokens can be available for instantaneously. + buffer: Int! + + # peakrate is the maximum depletion rate of the bucket. + # The peakrate does not need to be set, it is only necessary + # if perfect millisecond timescale shaping is required. + peakrate: Int + + # minburst specifies the size of the peakrate bucket. For perfect + # accuracy, should be set to the MTU of the interface. If a + # peakrate is needed, but some burstiness is acceptable, this + # size can be raised. A 3000 byte minburst allows around 3mbit/s + # of peakrate, given 1000 byte packets. + minburst: Int +} + +type RateSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.RateSpec"){ + # Rate is the speed knob. Allows bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means bytes per second. + rate: String! +} + +# ReorderSpec defines details of packet reorder. +type ReorderSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.ReorderSpec") { + reorder: String! + correlation: String + gap: Int +} + +type NetworkChaos @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.NetworkChaos") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + podnetwork: [PodNetworkChaos!] @goField(forceResolver: true) +} + +type MemoryStressor @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.MemoryStressor") { + # Workers specifies N workers to apply the stressor. + # Maximum 8192 workers can run by stress-ng + workers: Int! + + # Size specifies N bytes consumed per vm worker, default is the total available memory. + # One can specify the size as % of total available memory or in units of B, KB/KiB, + # MB/MiB, GB/GiB, TB/TiB. + size: String + + # extend stress-ng options + options: [String!] +} + +type CPUStressor @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.CPUStressor") { + # Workers specifies N workers to apply the stressor. + # Maximum 8192 workers can run by stress-ng + workers: Int! + + # Load specifies P percent loading per CPU worker. 0 is effectively a sleep (no load) and 100 + # is full loading. + load: Int + + # extend stress-ng options + options: [String!] +} + +type Stressors @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.Stressors") { + memoryStressor: MemoryStressor + cpuStressor: CPUStressor +} + +# StressChaosSpec defines the desired state of StressChaos +type StressChaosSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.StressChaosSpec") { + # containerNames indicates list of the name of affected container. + # If not set, all containers will be injected + containerNames: [String!] + + # selector is used to select pods that are used to inject chaos action. + selector: PodSelectorSpec! + + # mode defines the mode to run chaos action. + # supported mode: one / all / fixed / fixed-percent / random-max-percent + mode: String! + + # value is required when the mode is set to ` + "`" + `FixedPodMode` + "`" + ` / ` + "`" + `FixedPercentPodMod` + "`" + ` / ` + "`" + `RandomMaxPercentPodMod` + "`" + `. + # If ` + "`" + `FixedPodMode` + "`" + `, provide an integer of pods to do chaos action. + # If ` + "`" + `FixedPercentPodMod` + "`" + `, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + # IF ` + "`" + `RandomMaxPercentPodMod` + "`" + `, provide a number from 0-100 to specify the max percent of pods to do chaos action + value: String + + stressors: Stressors + + + # StressngStressors defines plenty of stressors just like ` + "`" + `Stressors` + "`" + ` except that it's an experimental + # feature and more powerful. You can define stressors in ` + "`" + `stress-ng` + "`" + ` (see also ` + "`" + `man stress-ng` + "`" + `) dialect, + # however not all of the supported stressors are well tested. It maybe retired in later releases. You + # should always use ` + "`" + `Stressors` + "`" + ` to define the stressors and use this only when you want more stressors + # unsupported by ` + "`" + `Stressors` + "`" + `. When both ` + "`" + `StressngStressors` + "`" + ` and ` + "`" + `Stressors` + "`" + ` are defined, ` + "`" + `StressngStressors` + "`" + ` + # wins. + stressngStressors: String + + # duration represents the duration of the chaos action. + # It is required when the action is ` + "`" + `PodFailureAction` + "`" + `. + # 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". + duration: String +} + +type StressChaosStatus @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.StressChaosStatus") { + # conditions represents the current global condition of the chaos + conditions: [ChaosCondition!] + + # experiment records the last experiment state. + experiment: ExperimentStatus + + # instances always specifies stressing instances + instances: Map +} + +type StressChaos @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.StressChaos") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + spec: StressChaosSpec! + + podstress: [PodStressChaos!] @goField(forceResolver: true) +} + +# PodStressChaos is a virtual type to describe relationship between pod and stress chaos +type PodStressChaos { + stressChaos: StressChaos! + + pod: Pod! + cgroups: Cgroups! @goField(forceResolver: true) + processStress: [ProcessStress!] @goField(forceResolver: true) +} + +type Cgroups { + raw: String! + cpu: CgroupsCpu + memory: CgroupsMemory +} + +type CgroupsCpu { + quota: Int! + period: Int! +} + +type CgroupsMemory { + limit: Int64! +} + +type ProcessStress { + process: Process! + cgroup: String! +} +`, BuiltIn: false}, +} +var parsedSchema = gqlparser.MustLoadSchema(sources...) + +// endregion ************************** generated!.gotpl ************************** + +// region ***************************** args.gotpl ***************************** + +func (ec *executionContext) field_Logger_component_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["ns"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ns")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["ns"] = arg0 + var arg1 model.Component + if tmp, ok := rawArgs["component"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("component")) + arg1, err = ec.unmarshalNComponent2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐComponent(ctx, tmp) + if err != nil { + return nil, err + } + } + args["component"] = arg1 + return args, nil +} + +func (ec *executionContext) field_Logger_pod_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["ns"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ns")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["ns"] = arg0 + var arg1 string + if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + arg1, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["name"] = arg1 + return args, nil +} + +func (ec *executionContext) field_MutablePod_cleanIptables_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 []string + if tmp, ok := rawArgs["chains"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("chains")) + arg0, err = ec.unmarshalOString2ᚕstringᚄ(ctx, tmp) + if err != nil { + return nil, err + } + } + args["chains"] = arg0 + return args, nil +} + +func (ec *executionContext) field_MutablePod_cleanTcs_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 []string + if tmp, ok := rawArgs["devices"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("devices")) + arg0, err = ec.unmarshalOString2ᚕstringᚄ(ctx, tmp) + if err != nil { + return nil, err + } + } + args["devices"] = arg0 + return args, nil +} + +func (ec *executionContext) field_MutablePod_killProcesses_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 []string + if tmp, ok := rawArgs["pids"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("pids")) + arg0, err = ec.unmarshalOString2ᚕstringᚄ(ctx, tmp) + if err != nil { + return nil, err + } + } + args["pids"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Mutation_pod_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["ns"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ns")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["ns"] = arg0 + var arg1 string + if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + arg1, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["name"] = arg1 + return args, nil +} + +func (ec *executionContext) field_Namespace_component_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.Component + if tmp, ok := rawArgs["component"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("component")) + arg0, err = ec.unmarshalNComponent2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐComponent(ctx, tmp) + if err != nil { + return nil, err + } + } + args["component"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Namespace_httpchaos_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *string + if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + arg0, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["name"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Namespace_iochaos_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *string + if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + arg0, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["name"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Namespace_networkchaos_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *string + if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + arg0, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["name"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Namespace_pod_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *string + if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + arg0, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["name"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Namespace_podhttpchaos_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *string + if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + arg0, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["name"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Namespace_podiochaos_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *string + if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + arg0, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["name"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Namespace_podnetworkchaos_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *string + if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + arg0, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["name"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Namespace_stresschaos_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *string + if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + arg0, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["name"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["name"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query_namespace_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *string + if tmp, ok := rawArgs["ns"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ns")) + arg0, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["ns"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query_pods_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.PodSelectorInput + if tmp, ok := rawArgs["selector"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("selector")) + arg0, err = ec.unmarshalNPodSelectorInput2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐPodSelectorInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["selector"] = arg0 + return args, nil +} + +func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 bool + if tmp, ok := rawArgs["includeDeprecated"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) + if err != nil { + return nil, err + } + } + args["includeDeprecated"] = arg0 + return args, nil +} + +func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 bool + if tmp, ok := rawArgs["includeDeprecated"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) + if err != nil { + return nil, err + } + } + args["includeDeprecated"] = arg0 + return args, nil +} + +// endregion ***************************** args.gotpl ***************************** + +// region ************************** directives.gotpl ************************** + +// endregion ************************** directives.gotpl ************************** + +// region **************************** field.gotpl ***************************** + +func (ec *executionContext) _AttrOverrideSpec_ino(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.AttrOverrideSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "AttrOverrideSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.AttrOverrideSpec().Ino(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int) + fc.Result = res + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) +} + +func (ec *executionContext) _AttrOverrideSpec_size(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.AttrOverrideSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "AttrOverrideSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.AttrOverrideSpec().Size(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int) + fc.Result = res + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) +} + +func (ec *executionContext) _AttrOverrideSpec_blocks(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.AttrOverrideSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "AttrOverrideSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.AttrOverrideSpec().Blocks(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int) + fc.Result = res + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) +} + +func (ec *executionContext) _AttrOverrideSpec_atime(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.AttrOverrideSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "AttrOverrideSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Atime, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.Timespec) + fc.Result = res + return ec.marshalOTimespec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐTimespec(ctx, field.Selections, res) +} + +func (ec *executionContext) _AttrOverrideSpec_mtime(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.AttrOverrideSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "AttrOverrideSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Mtime, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.Timespec) + fc.Result = res + return ec.marshalOTimespec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐTimespec(ctx, field.Selections, res) +} + +func (ec *executionContext) _AttrOverrideSpec_ctime(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.AttrOverrideSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "AttrOverrideSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Ctime, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.Timespec) + fc.Result = res + return ec.marshalOTimespec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐTimespec(ctx, field.Selections, res) +} + +func (ec *executionContext) _AttrOverrideSpec_kind(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.AttrOverrideSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "AttrOverrideSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.AttrOverrideSpec().Kind(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _AttrOverrideSpec_perm(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.AttrOverrideSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "AttrOverrideSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.AttrOverrideSpec().Perm(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int) + fc.Result = res + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) +} + +func (ec *executionContext) _AttrOverrideSpec_nlink(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.AttrOverrideSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "AttrOverrideSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.AttrOverrideSpec().Nlink(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int) + fc.Result = res + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) +} + +func (ec *executionContext) _AttrOverrideSpec_uid(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.AttrOverrideSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "AttrOverrideSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.AttrOverrideSpec().UID(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int) + fc.Result = res + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) +} + +func (ec *executionContext) _AttrOverrideSpec_gid(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.AttrOverrideSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "AttrOverrideSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.AttrOverrideSpec().Gid(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int) + fc.Result = res + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) +} + +func (ec *executionContext) _AttrOverrideSpec_rdev(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.AttrOverrideSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "AttrOverrideSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.AttrOverrideSpec().Rdev(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int) + fc.Result = res + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) +} + +func (ec *executionContext) _BandwidthSpec_rate(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.BandwidthSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "BandwidthSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Rate, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _BandwidthSpec_limit(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.BandwidthSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "BandwidthSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.BandwidthSpec().Limit(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) _BandwidthSpec_buffer(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.BandwidthSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "BandwidthSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.BandwidthSpec().Buffer(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) _BandwidthSpec_peakrate(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.BandwidthSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "BandwidthSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.BandwidthSpec().Peakrate(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int) + fc.Result = res + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) +} + +func (ec *executionContext) _BandwidthSpec_minburst(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.BandwidthSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "BandwidthSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.BandwidthSpec().Minburst(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int) + fc.Result = res + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) +} + +func (ec *executionContext) _CPUStressor_workers(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.CPUStressor) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "CPUStressor", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Workers, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) _CPUStressor_load(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.CPUStressor) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "CPUStressor", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Load, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int) + fc.Result = res + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) +} + +func (ec *executionContext) _CPUStressor_options(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.CPUStressor) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "CPUStressor", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Options, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Cgroups_raw(ctx context.Context, field graphql.CollectedField, obj *model.Cgroups) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Cgroups", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Raw, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Cgroups_cpu(ctx context.Context, field graphql.CollectedField, obj *model.Cgroups) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Cgroups", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.CPU, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*model.CgroupsCPU) + fc.Result = res + return ec.marshalOCgroupsCpu2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐCgroupsCPU(ctx, field.Selections, res) +} + +func (ec *executionContext) _Cgroups_memory(ctx context.Context, field graphql.CollectedField, obj *model.Cgroups) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Cgroups", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Memory, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*model.CgroupsMemory) + fc.Result = res + return ec.marshalOCgroupsMemory2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐCgroupsMemory(ctx, field.Selections, res) +} + +func (ec *executionContext) _CgroupsCpu_quota(ctx context.Context, field graphql.CollectedField, obj *model.CgroupsCPU) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "CgroupsCpu", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Quota, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) _CgroupsCpu_period(ctx context.Context, field graphql.CollectedField, obj *model.CgroupsCPU) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "CgroupsCpu", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Period, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) _CgroupsMemory_limit(ctx context.Context, field graphql.CollectedField, obj *model.CgroupsMemory) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "CgroupsMemory", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Limit, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalNInt642int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _ChaosCondition_type(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.ChaosCondition) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ChaosCondition", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.ChaosCondition().Type(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ChaosCondition_status(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.ChaosCondition) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ChaosCondition", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.ChaosCondition().Status(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ChaosCondition_reason(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.ChaosCondition) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ChaosCondition", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Reason, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _CidrAndPort_cidr(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.CidrAndPort) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "CidrAndPort", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Cidr, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _CidrAndPort_port(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.CidrAndPort) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "CidrAndPort", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.CidrAndPort().Port(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerState_waiting(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerState) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerState", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Waiting, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1.ContainerStateWaiting) + fc.Result = res + return ec.marshalOContainerStateWaiting2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐContainerStateWaiting(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerState_running(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerState) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerState", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Running, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1.ContainerStateRunning) + fc.Result = res + return ec.marshalOContainerStateRunning2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐContainerStateRunning(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerState_terminated(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerState) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerState", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Terminated, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1.ContainerStateTerminated) + fc.Result = res + return ec.marshalOContainerStateTerminated2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐContainerStateTerminated(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStateRunning_startedAt(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStateRunning) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStateRunning", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.ContainerStateRunning().StartedAt(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStateTerminated_exitCode(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStateTerminated) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStateTerminated", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ExitCode, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int32) + fc.Result = res + return ec.marshalNInt2int32(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStateTerminated_signal(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStateTerminated) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStateTerminated", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Signal, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int32) + fc.Result = res + return ec.marshalOInt2int32(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStateTerminated_reason(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStateTerminated) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStateTerminated", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Reason, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStateTerminated_message(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStateTerminated) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStateTerminated", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Message, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStateTerminated_startedAt(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStateTerminated) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStateTerminated", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.ContainerStateTerminated().StartedAt(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStateTerminated_finishedAt(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStateTerminated) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStateTerminated", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.ContainerStateTerminated().FinishedAt(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStateTerminated_containerID(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStateTerminated) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStateTerminated", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ContainerID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStateWaiting_reason(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStateWaiting) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStateWaiting", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Reason, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStateWaiting_message(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStateWaiting) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStateWaiting", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Message, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStatus_name(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStatus_State(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.State, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(v1.ContainerState) + fc.Result = res + return ec.marshalOContainerState2k8sᚗioᚋapiᚋcoreᚋv1ᚐContainerState(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStatus_lastTerminationState(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.LastTerminationState, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(v1.ContainerState) + fc.Result = res + return ec.marshalOContainerState2k8sᚗioᚋapiᚋcoreᚋv1ᚐContainerState(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStatus_ready(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Ready, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStatus_restartCount(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.RestartCount, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int32) + fc.Result = res + return ec.marshalNInt2int32(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStatus_image(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Image, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStatus_imageID(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ImageID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStatus_containerID(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ContainerID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ContainerStatus_started(ctx context.Context, field graphql.CollectedField, obj *v1.ContainerStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ContainerStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Started, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*bool) + fc.Result = res + return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) +} + +func (ec *executionContext) _CorruptSpec_corrupt(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.CorruptSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "CorruptSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Corrupt, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _CorruptSpec_correlation(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.CorruptSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "CorruptSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Correlation, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _DelaySpec_latency(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.DelaySpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "DelaySpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Latency, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _DelaySpec_correlation(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.DelaySpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "DelaySpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Correlation, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _DelaySpec_jitter(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.DelaySpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "DelaySpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Jitter, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _DelaySpec_reorder(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.DelaySpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "DelaySpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Reorder, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.ReorderSpec) + fc.Result = res + return ec.marshalOReorderSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐReorderSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _DuplicateSpec_duplicate(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.DuplicateSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "DuplicateSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Duplicate, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _DuplicateSpec_correlation(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.DuplicateSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "DuplicateSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Correlation, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ExperimentStatus_desiredPhase(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.ExperimentStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ExperimentStatus", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.ExperimentStatus().DesiredPhase(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ExperimentStatus_Records(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.ExperimentStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ExperimentStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Records, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1alpha1.Record) + fc.Result = res + return ec.marshalORecord2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRecordᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Fd_fd(ctx context.Context, field graphql.CollectedField, obj *model.Fd) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Fd", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Fd, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Fd_target(ctx context.Context, field graphql.CollectedField, obj *model.Fd) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Fd", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Target, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_kind(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Kind, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_apiVersion(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.APIVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_name(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_generateName(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GenerateName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_namespace(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Namespace, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_selfLink(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SelfLink, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_uid(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.HTTPChaos().UID(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_resourceVersion(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ResourceVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_generation(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Generation, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalNInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_creationTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.HTTPChaos().CreationTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalNTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_deletionTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.HTTPChaos().DeletionTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_deletionGracePeriodSeconds(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeletionGracePeriodSeconds, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt2ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_labels(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.HTTPChaos().Labels(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_annotations(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.HTTPChaos().Annotations(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_ownerReferences(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.OwnerReferences, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v11.OwnerReference) + fc.Result = res + return ec.marshalOOwnerReference2ᚕk8sᚗioᚋapimachineryᚋpkgᚋapisᚋmetaᚋv1ᚐOwnerReferenceᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_finalizers(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Finalizers, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_spec(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Spec, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.HTTPChaosSpec) + fc.Result = res + return ec.marshalNHTTPChaosSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐHTTPChaosSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_status(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Status, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.HTTPChaosStatus) + fc.Result = res + return ec.marshalNHTTPChaosStatus2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐHTTPChaosStatus(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaos_podhttp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.HTTPChaos().Podhttp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1alpha1.PodHttpChaos) + fc.Result = res + return ec.marshalOPodHTTPChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_selector(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Selector, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.PodSelectorSpec) + fc.Result = res + return ec.marshalNPodSelectorSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodSelectorSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_mode(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.HTTPChaosSpec().Mode(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_value(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Value, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_target(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.HTTPChaosSpec().Target(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_abort(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Abort, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*bool) + fc.Result = res + return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_delay(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Delay, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_replace(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Replace, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.PodHttpChaosReplaceActions) + fc.Result = res + return ec.marshalOPodHttpChaosReplaceActions2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosReplaceActions(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_patch(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Patch, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.PodHttpChaosPatchActions) + fc.Result = res + return ec.marshalOPodHttpChaosPatchActions2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosPatchActions(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_port(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Port, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int32) + fc.Result = res + return ec.marshalOInt2int32(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_path(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Path, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_method(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Method, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_code(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Code, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int32) + fc.Result = res + return ec.marshalOInt2ᚖint32(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_requestHeaders(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.HTTPChaosSpec().RequestHeaders(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_responseHeaders(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.HTTPChaosSpec().ResponseHeaders(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosSpec_duration(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Duration, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosStatus_conditions(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Conditions, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v1alpha1.ChaosCondition) + fc.Result = res + return ec.marshalOChaosCondition2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐChaosConditionᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosStatus_experiment(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Experiment, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(v1alpha1.ExperimentStatus) + fc.Result = res + return ec.marshalOExperimentStatus2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐExperimentStatus(ctx, field.Selections, res) +} + +func (ec *executionContext) _HTTPChaosStatus_instances(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.HTTPChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HTTPChaosStatus", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.HTTPChaosStatus().Instances(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_kind(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Kind, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_apiVersion(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.APIVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_name(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_generateName(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GenerateName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_namespace(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Namespace, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_selfLink(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SelfLink, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_uid(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaos().UID(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_resourceVersion(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ResourceVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_generation(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Generation, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalNInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_creationTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaos().CreationTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalNTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_deletionTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaos().DeletionTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_deletionGracePeriodSeconds(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeletionGracePeriodSeconds, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt2ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_labels(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaos().Labels(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_annotations(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaos().Annotations(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_ownerReferences(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.OwnerReferences, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v11.OwnerReference) + fc.Result = res + return ec.marshalOOwnerReference2ᚕk8sᚗioᚋapimachineryᚋpkgᚋapisᚋmetaᚋv1ᚐOwnerReferenceᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_finalizers(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Finalizers, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_spec(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Spec, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.IOChaosSpec) + fc.Result = res + return ec.marshalNIOChaosSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIOChaosSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_status(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Status, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.IOChaosStatus) + fc.Result = res + return ec.marshalNIOChaosStatus2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIOChaosStatus(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaos_podios(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaos().Podios(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1alpha1.PodIOChaos) + fc.Result = res + return ec.marshalOPodIOChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodIOChaosᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_type(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().Type(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_path(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Path, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_methods(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().Methods(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_percent(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Percent, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalOInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_faults(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Faults, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v1alpha1.IoFault) + fc.Result = res + return ec.marshalOIoFault2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIoFaultᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_latency(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Latency, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_ino(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().Ino(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_size(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().Size(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_blocks(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().Blocks(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_atime(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().Atime(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.Timespec) + fc.Result = res + return ec.marshalOTimespec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐTimespec(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_mtime(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().Mtime(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.Timespec) + fc.Result = res + return ec.marshalOTimespec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐTimespec(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_ctime(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().Ctime(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.Timespec) + fc.Result = res + return ec.marshalOTimespec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐTimespec(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_kind(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().Kind(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_perm(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().Perm(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int) + fc.Result = res + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_nlink(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().Nlink(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_uid(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().UID(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_gid(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().Gid(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_rdev(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().Rdev(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_filling(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().Filling(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_maxOccurrences(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().MaxOccurrences(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_maxLength(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosAction().MaxLength(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosAction_source(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosAction", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Source, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosSpec_containerNames(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ContainerNames, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosSpec_selector(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Selector, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.PodSelectorSpec) + fc.Result = res + return ec.marshalNPodSelectorSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodSelectorSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosSpec_mode(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosSpec().Mode(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosSpec_value(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Value, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosSpec_action(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosSpec().Action(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosSpec_delay(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Delay, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosSpec_errno(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosSpec().Errno(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int) + fc.Result = res + return ec.marshalOInt2ᚖint(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosSpec_attr(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Attr, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.AttrOverrideSpec) + fc.Result = res + return ec.marshalOAttrOverrideSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐAttrOverrideSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosSpec_mistake(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Mistake, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.MistakeSpec) + fc.Result = res + return ec.marshalOMistakeSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐMistakeSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosSpec_path(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Path, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosSpec_methods(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosSpec().Methods(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosSpec_percent(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Percent, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalOInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosSpec_volumePath(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.VolumePath, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosSpec_duration(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Duration, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosStatus_conditions(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Conditions, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v1alpha1.ChaosCondition) + fc.Result = res + return ec.marshalOChaosCondition2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐChaosConditionᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosStatus_experiment(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Experiment, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(v1alpha1.ExperimentStatus) + fc.Result = res + return ec.marshalOExperimentStatus2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐExperimentStatus(ctx, field.Selections, res) +} + +func (ec *executionContext) _IOChaosStatus_instances(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IOChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IOChaosStatus", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IOChaosStatus().Instances(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _IoFault_errno(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IoFault) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IoFault", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.IoFault().Errno(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) _IoFault_weight(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.IoFault) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "IoFault", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Weight, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int32) + fc.Result = res + return ec.marshalNInt2int32(ctx, field.Selections, res) +} + +func (ec *executionContext) _KillProcessResult_pid(ctx context.Context, field graphql.CollectedField, obj *model.KillProcessResult) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "KillProcessResult", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Pid, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _KillProcessResult_command(ctx context.Context, field graphql.CollectedField, obj *model.KillProcessResult) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "KillProcessResult", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Command, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Logger_component(ctx context.Context, field graphql.CollectedField) (ret func() graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + fc := &graphql.FieldContext{ + Object: "Logger", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Logger_component_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return nil + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Logger().Component(rctx, args["ns"].(string), args["component"].(model.Component)) + }) + if err != nil { + ec.Error(ctx, err) + return nil + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return nil + } + return func() graphql.Marshaler { + res, ok := <-resTmp.(<-chan string) + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.marshalNString2string(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + } +} + +func (ec *executionContext) _Logger_pod(ctx context.Context, field graphql.CollectedField) (ret func() graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + fc := &graphql.FieldContext{ + Object: "Logger", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Logger_pod_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return nil + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Logger().Pod(rctx, args["ns"].(string), args["name"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return nil + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return nil + } + return func() graphql.Marshaler { + res, ok := <-resTmp.(<-chan string) + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.marshalNString2string(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + } +} + +func (ec *executionContext) _LossSpec_loss(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.LossSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "LossSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Loss, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _LossSpec_correlation(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.LossSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "LossSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Correlation, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _MemoryStressor_workers(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.MemoryStressor) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "MemoryStressor", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Workers, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) _MemoryStressor_size(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.MemoryStressor) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "MemoryStressor", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Size, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _MemoryStressor_options(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.MemoryStressor) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "MemoryStressor", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Options, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _MistakeSpec_filling(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.MistakeSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "MistakeSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.MistakeSpec().Filling(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _MistakeSpec_maxOccurrences(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.MistakeSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "MistakeSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.MaxOccurrences, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalOInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _MistakeSpec_maxLength(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.MistakeSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "MistakeSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.MaxLength, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalOInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _MutablePod_pod(ctx context.Context, field graphql.CollectedField, obj *model.MutablePod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "MutablePod", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Pod, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*v1.Pod) + fc.Result = res + return ec.marshalNPod2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐPod(ctx, field.Selections, res) +} + +func (ec *executionContext) _MutablePod_killProcesses(ctx context.Context, field graphql.CollectedField, obj *model.MutablePod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "MutablePod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_MutablePod_killProcesses_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.MutablePod().KillProcesses(rctx, obj, args["pids"].([]string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*model.KillProcessResult) + fc.Result = res + return ec.marshalOKillProcessResult2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐKillProcessResultᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _MutablePod_cleanTcs(ctx context.Context, field graphql.CollectedField, obj *model.MutablePod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "MutablePod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_MutablePod_cleanTcs_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.MutablePod().CleanTcs(rctx, obj, args["devices"].([]string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _MutablePod_cleanIptables(ctx context.Context, field graphql.CollectedField, obj *model.MutablePod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "MutablePod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_MutablePod_cleanIptables_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.MutablePod().CleanIptables(rctx, obj, args["chains"].([]string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Mutation_pod(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Mutation", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Mutation_pod_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().Pod(rctx, args["ns"].(string), args["name"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*model.MutablePod) + fc.Result = res + return ec.marshalOMutablePod2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐMutablePod(ctx, field.Selections, res) +} + +func (ec *executionContext) _Namespace_ns(ctx context.Context, field graphql.CollectedField, obj *model.Namespace) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Namespace", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Ns, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Namespace_component(ctx context.Context, field graphql.CollectedField, obj *model.Namespace) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Namespace", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Namespace_component_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Namespace().Component(rctx, obj, args["component"].(model.Component)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1.Pod) + fc.Result = res + return ec.marshalOPod2ᚕᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐPodᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Namespace_pod(ctx context.Context, field graphql.CollectedField, obj *model.Namespace) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Namespace", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Namespace_pod_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Namespace().Pod(rctx, obj, args["name"].(*string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1.Pod) + fc.Result = res + return ec.marshalOPod2ᚕᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐPodᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Namespace_stresschaos(ctx context.Context, field graphql.CollectedField, obj *model.Namespace) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Namespace", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Namespace_stresschaos_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Namespace().Stresschaos(rctx, obj, args["name"].(*string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1alpha1.StressChaos) + fc.Result = res + return ec.marshalOStressChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐStressChaosᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Namespace_iochaos(ctx context.Context, field graphql.CollectedField, obj *model.Namespace) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Namespace", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Namespace_iochaos_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Namespace().Iochaos(rctx, obj, args["name"].(*string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1alpha1.IOChaos) + fc.Result = res + return ec.marshalOIOChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIOChaosᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Namespace_podiochaos(ctx context.Context, field graphql.CollectedField, obj *model.Namespace) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Namespace", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Namespace_podiochaos_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Namespace().Podiochaos(rctx, obj, args["name"].(*string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1alpha1.PodIOChaos) + fc.Result = res + return ec.marshalOPodIOChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodIOChaosᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Namespace_httpchaos(ctx context.Context, field graphql.CollectedField, obj *model.Namespace) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Namespace", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Namespace_httpchaos_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Namespace().Httpchaos(rctx, obj, args["name"].(*string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1alpha1.HTTPChaos) + fc.Result = res + return ec.marshalOHTTPChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐHTTPChaosᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Namespace_podhttpchaos(ctx context.Context, field graphql.CollectedField, obj *model.Namespace) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Namespace", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Namespace_podhttpchaos_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Namespace().Podhttpchaos(rctx, obj, args["name"].(*string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1alpha1.PodHttpChaos) + fc.Result = res + return ec.marshalOPodHTTPChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Namespace_networkchaos(ctx context.Context, field graphql.CollectedField, obj *model.Namespace) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Namespace", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Namespace_networkchaos_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Namespace().Networkchaos(rctx, obj, args["name"].(*string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1alpha1.NetworkChaos) + fc.Result = res + return ec.marshalONetworkChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐNetworkChaosᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Namespace_podnetworkchaos(ctx context.Context, field graphql.CollectedField, obj *model.Namespace) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Namespace", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Namespace_podnetworkchaos_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Namespace().Podnetworkchaos(rctx, obj, args["name"].(*string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1alpha1.PodNetworkChaos) + fc.Result = res + return ec.marshalOPodNetworkChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodNetworkChaosᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_kind(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Kind, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_apiVersion(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.APIVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_name(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_generateName(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GenerateName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_namespace(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Namespace, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_selfLink(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SelfLink, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_uid(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.NetworkChaos().UID(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_resourceVersion(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ResourceVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_generation(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Generation, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalNInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_creationTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.NetworkChaos().CreationTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalNTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_deletionTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.NetworkChaos().DeletionTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_deletionGracePeriodSeconds(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeletionGracePeriodSeconds, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt2ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_labels(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.NetworkChaos().Labels(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_annotations(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.NetworkChaos().Annotations(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_ownerReferences(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.OwnerReferences, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v11.OwnerReference) + fc.Result = res + return ec.marshalOOwnerReference2ᚕk8sᚗioᚋapimachineryᚋpkgᚋapisᚋmetaᚋv1ᚐOwnerReferenceᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_finalizers(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Finalizers, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _NetworkChaos_podnetwork(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.NetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "NetworkChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.NetworkChaos().Podnetwork(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1alpha1.PodNetworkChaos) + fc.Result = res + return ec.marshalOPodNetworkChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodNetworkChaosᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _OwnerReference_kind(ctx context.Context, field graphql.CollectedField, obj *v11.OwnerReference) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "OwnerReference", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Kind, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _OwnerReference_apiVersion(ctx context.Context, field graphql.CollectedField, obj *v11.OwnerReference) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "OwnerReference", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.APIVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _OwnerReference_name(ctx context.Context, field graphql.CollectedField, obj *v11.OwnerReference) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "OwnerReference", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _OwnerReference_uid(ctx context.Context, field graphql.CollectedField, obj *v11.OwnerReference) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "OwnerReference", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.OwnerReference().UID(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _OwnerReference_controller(ctx context.Context, field graphql.CollectedField, obj *v11.OwnerReference) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "OwnerReference", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Controller, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*bool) + fc.Result = res + return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) +} + +func (ec *executionContext) _OwnerReference_blockOwnerDeletion(ctx context.Context, field graphql.CollectedField, obj *v11.OwnerReference) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "OwnerReference", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.BlockOwnerDeletion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*bool) + fc.Result = res + return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_kind(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Kind, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_apiVersion(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.APIVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_name(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_generateName(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GenerateName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_namespace(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Namespace, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_selfLink(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SelfLink, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_uid(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Pod().UID(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_resourceVersion(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ResourceVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_generation(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Generation, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalNInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_creationTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Pod().CreationTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalNTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_deletionTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Pod().DeletionTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_deletionGracePeriodSeconds(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeletionGracePeriodSeconds, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt2ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_labels(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Pod().Labels(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_annotations(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Pod().Annotations(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_ownerReferences(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.OwnerReferences, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v11.OwnerReference) + fc.Result = res + return ec.marshalOOwnerReference2ᚕk8sᚗioᚋapimachineryᚋpkgᚋapisᚋmetaᚋv1ᚐOwnerReferenceᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_finalizers(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Finalizers, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_spec(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Spec, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1.PodSpec) + fc.Result = res + return ec.marshalNPodSpec2k8sᚗioᚋapiᚋcoreᚋv1ᚐPodSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_status(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Status, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1.PodStatus) + fc.Result = res + return ec.marshalNPodStatus2k8sᚗioᚋapiᚋcoreᚋv1ᚐPodStatus(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_logs(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Pod().Logs(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_daemon(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Pod().Daemon(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1.Pod) + fc.Result = res + return ec.marshalOPod2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐPod(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_processes(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Pod().Processes(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*model.Process) + fc.Result = res + return ec.marshalOProcess2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐProcessᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_mounts(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Pod().Mounts(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_ipset(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Pod().Ipset(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_tcQdisc(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Pod().TcQdisc(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Pod_iptables(ctx context.Context, field graphql.CollectedField, obj *v1.Pod) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Pod", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Pod().Iptables(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodCondition_type(ctx context.Context, field graphql.CollectedField, obj *v1.PodCondition) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodCondition", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodCondition().Type(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodCondition_status(ctx context.Context, field graphql.CollectedField, obj *v1.PodCondition) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodCondition", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodCondition().Status(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodCondition_lastProbeTime(ctx context.Context, field graphql.CollectedField, obj *v1.PodCondition) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodCondition", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodCondition().LastProbeTime(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodCondition_lastTransitionTime(ctx context.Context, field graphql.CollectedField, obj *v1.PodCondition) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodCondition", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodCondition().LastTransitionTime(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodCondition_reason(ctx context.Context, field graphql.CollectedField, obj *v1.PodCondition) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodCondition", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Reason, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodCondition_message(ctx context.Context, field graphql.CollectedField, obj *v1.PodCondition) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodCondition", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Message, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_kind(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Kind, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_apiVersion(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.APIVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_name(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_generateName(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GenerateName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_namespace(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Namespace, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_selfLink(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SelfLink, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_uid(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodHTTPChaos().UID(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_resourceVersion(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ResourceVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_generation(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Generation, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalNInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_creationTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodHTTPChaos().CreationTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalNTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_deletionTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodHTTPChaos().DeletionTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_deletionGracePeriodSeconds(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeletionGracePeriodSeconds, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt2ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_labels(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodHTTPChaos().Labels(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_annotations(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodHTTPChaos().Annotations(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_ownerReferences(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.OwnerReferences, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v11.OwnerReference) + fc.Result = res + return ec.marshalOOwnerReference2ᚕk8sᚗioᚋapimachineryᚋpkgᚋapisᚋmetaᚋv1ᚐOwnerReferenceᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_finalizers(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Finalizers, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_spec(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Spec, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.PodHttpChaosSpec) + fc.Result = res + return ec.marshalNPodHttpChaosSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_status(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Status, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.PodHttpChaosStatus) + fc.Result = res + return ec.marshalNPodHttpChaosStatus2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosStatus(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHTTPChaos_pod(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHTTPChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodHTTPChaos().Pod(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*v1.Pod) + fc.Result = res + return ec.marshalNPod2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐPod(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosActions_abort(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosActions) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosActions", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Abort, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*bool) + fc.Result = res + return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosActions_delay(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosActions) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosActions", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Delay, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosActions_replace(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosActions) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosActions", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Replace, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.PodHttpChaosReplaceActions) + fc.Result = res + return ec.marshalOPodHttpChaosReplaceActions2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosReplaceActions(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosActions_patch(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosActions) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosActions", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Patch, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.PodHttpChaosPatchActions) + fc.Result = res + return ec.marshalOPodHttpChaosPatchActions2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosPatchActions(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosPatchActions_body(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosPatchActions) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosPatchActions", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Body, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.PodHttpChaosPatchBodyAction) + fc.Result = res + return ec.marshalOPodHttpChaosPatchBodyAction2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosPatchBodyAction(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosPatchActions_queries(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosPatchActions) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosPatchActions", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Queries, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([][]string) + fc.Result = res + return ec.marshalOString2ᚕᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosPatchActions_headers(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosPatchActions) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosPatchActions", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Headers, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([][]string) + fc.Result = res + return ec.marshalOString2ᚕᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosPatchBodyAction_type(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosPatchBodyAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosPatchBodyAction", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Type, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosPatchBodyAction_value(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosPatchBodyAction) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosPatchBodyAction", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Value, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosReplaceActions_path(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosReplaceActions) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosReplaceActions", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Path, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosReplaceActions_method(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosReplaceActions) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosReplaceActions", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Method, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosReplaceActions_code(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosReplaceActions) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosReplaceActions", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Code, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int32) + fc.Result = res + return ec.marshalOInt2ᚖint32(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosReplaceActions_body(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosReplaceActions) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosReplaceActions", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodHttpChaosReplaceActions().Body(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosReplaceActions_queries(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosReplaceActions) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosReplaceActions", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodHttpChaosReplaceActions().Queries(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosReplaceActions_headers(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosReplaceActions) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosReplaceActions", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodHttpChaosReplaceActions().Headers(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosRule_target(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosRule) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosRule", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodHttpChaosRule().Target(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosRule_selector(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosRule) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosRule", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Selector, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.PodHttpChaosSelector) + fc.Result = res + return ec.marshalNPodHttpChaosSelector2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosSelector(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosRule_actions(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosRule) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosRule", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Actions, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.PodHttpChaosActions) + fc.Result = res + return ec.marshalNPodHttpChaosActions2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosActions(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosRule_source(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosRule) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosRule", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Source, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosRule_port(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosRule) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosRule", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Port, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int32) + fc.Result = res + return ec.marshalNInt2int32(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosSelector_port(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosSelector) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosSelector", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Port, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int32) + fc.Result = res + return ec.marshalOInt2ᚖint32(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosSelector_path(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosSelector) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosSelector", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Path, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosSelector_method(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosSelector) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosSelector", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Method, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosSelector_code(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosSelector) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosSelector", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Code, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int32) + fc.Result = res + return ec.marshalOInt2ᚖint32(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosSelector_requestHeaders(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosSelector) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosSelector", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodHttpChaosSelector().RequestHeaders(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosSelector_responseHeaders(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosSelector) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosSelector", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodHttpChaosSelector().ResponseHeaders(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosSpec_rules(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Rules, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]v1alpha1.PodHttpChaosRule) + fc.Result = res + return ec.marshalNPodHttpChaosRule2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosRuleᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosSpec_tls(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.TLS, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.PodHttpChaosTLS) + fc.Result = res + return ec.marshalOPodHttpChaosTLS2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosTLS(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosStatus_pid(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Pid, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalOInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosStatus_startTime(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.StartTime, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalOInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosStatus_failedMessage(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.FailedMessage, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosStatus_observedGeneration(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ObservedGeneration, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalOInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosTLS_secretName(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosTLS) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosTLS", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SecretName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosTLS_secretNamespace(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosTLS) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosTLS", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SecretNamespace, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosTLS_certName(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosTLS) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosTLS", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.CertName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosTLS_keyName(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosTLS) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosTLS", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.KeyName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodHttpChaosTLS_caName(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodHttpChaosTLS) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodHttpChaosTLS", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.CAName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_kind(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Kind, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_apiVersion(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.APIVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_name(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_generateName(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GenerateName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_namespace(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Namespace, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_selfLink(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SelfLink, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_uid(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodIOChaos().UID(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_resourceVersion(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ResourceVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_generation(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Generation, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalNInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_creationTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodIOChaos().CreationTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalNTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_deletionTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodIOChaos().DeletionTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_deletionGracePeriodSeconds(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeletionGracePeriodSeconds, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt2ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_labels(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodIOChaos().Labels(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_annotations(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodIOChaos().Annotations(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_ownerReferences(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.OwnerReferences, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v11.OwnerReference) + fc.Result = res + return ec.marshalOOwnerReference2ᚕk8sᚗioᚋapimachineryᚋpkgᚋapisᚋmetaᚋv1ᚐOwnerReferenceᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_finalizers(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Finalizers, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_spec(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Spec, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.PodIOChaosSpec) + fc.Result = res + return ec.marshalNPodIOChaosSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodIOChaosSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_status(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Status, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.PodIOChaosStatus) + fc.Result = res + return ec.marshalNPodIOChaosStatus2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodIOChaosStatus(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_pod(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodIOChaos().Pod(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*v1.Pod) + fc.Result = res + return ec.marshalNPod2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐPod(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaos_ios(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodIOChaos().Ios(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1alpha1.IOChaos) + fc.Result = res + return ec.marshalOIOChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIOChaosᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaosSpec_volumeMountPath(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.VolumeMountPath, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaosSpec_container(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Container, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaosSpec_actions(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Actions, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v1alpha1.IOChaosAction) + fc.Result = res + return ec.marshalOIOChaosAction2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIOChaosActionᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaosStatus_pid(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Pid, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalOInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaosStatus_startTime(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.StartTime, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalOInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaosStatus_failedMessage(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.FailedMessage, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIOChaosStatus_observedGeneration(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodIOChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIOChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ObservedGeneration, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalOInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodIP_ip(ctx context.Context, field graphql.CollectedField, obj *v1.PodIP) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodIP", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IP, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_kind(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Kind, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_apiVersion(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.APIVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_name(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_generateName(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GenerateName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_namespace(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Namespace, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_selfLink(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SelfLink, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_uid(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodNetworkChaos().UID(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_resourceVersion(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ResourceVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_generation(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Generation, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalNInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_creationTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodNetworkChaos().CreationTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalNTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_deletionTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodNetworkChaos().DeletionTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_deletionGracePeriodSeconds(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeletionGracePeriodSeconds, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt2ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_labels(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodNetworkChaos().Labels(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_annotations(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodNetworkChaos().Annotations(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_ownerReferences(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.OwnerReferences, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v11.OwnerReference) + fc.Result = res + return ec.marshalOOwnerReference2ᚕk8sᚗioᚋapimachineryᚋpkgᚋapisᚋmetaᚋv1ᚐOwnerReferenceᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_finalizers(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Finalizers, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_spec(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Spec, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.PodNetworkChaosSpec) + fc.Result = res + return ec.marshalNPodNetworkChaosSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodNetworkChaosSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_status(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Status, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.PodNetworkChaosStatus) + fc.Result = res + return ec.marshalNPodNetworkChaosStatus2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodNetworkChaosStatus(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaos_pod(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodNetworkChaos().Pod(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*v1.Pod) + fc.Result = res + return ec.marshalNPod2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐPod(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaosSpec_ipSets(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IPSets, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v1alpha1.RawIPSet) + fc.Result = res + return ec.marshalORawIPSet2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRawIPSetᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaosSpec_iptables(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Iptables, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v1alpha1.RawIptables) + fc.Result = res + return ec.marshalORawIptables2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRawIptablesᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaosSpec_trafficControls(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.TrafficControls, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v1alpha1.RawTrafficControl) + fc.Result = res + return ec.marshalORawTrafficControl2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRawTrafficControlᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaosStatus_failedMessage(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.FailedMessage, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodNetworkChaosStatus_observedGeneration(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodNetworkChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodNetworkChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ObservedGeneration, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalNInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodSelectorSpec_namespaces(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodSelectorSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodSelectorSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Namespaces, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodSelectorSpec_nodes(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodSelectorSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodSelectorSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Nodes, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodSelectorSpec_pods(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodSelectorSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodSelectorSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodSelectorSpec().Pods(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodSelectorSpec_nodeSelectors(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodSelectorSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodSelectorSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodSelectorSpec().NodeSelectors(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodSelectorSpec_fieldSelectors(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodSelectorSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodSelectorSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodSelectorSpec().FieldSelectors(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodSelectorSpec_labelSelectors(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodSelectorSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodSelectorSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodSelectorSpec().LabelSelectors(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodSelectorSpec_annotationSelectors(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodSelectorSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodSelectorSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodSelectorSpec().AnnotationSelectors(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodSelectorSpec_podPhaseSelectors(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.PodSelectorSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodSelectorSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PodPhaseSelectors, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodSpec_nodeName(ctx context.Context, field graphql.CollectedField, obj *v1.PodSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.NodeName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStatus_phase(ctx context.Context, field graphql.CollectedField, obj *v1.PodStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStatus", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodStatus().Phase(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStatus_conditions(ctx context.Context, field graphql.CollectedField, obj *v1.PodStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Conditions, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v1.PodCondition) + fc.Result = res + return ec.marshalOPodCondition2ᚕk8sᚗioᚋapiᚋcoreᚋv1ᚐPodConditionᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStatus_message(ctx context.Context, field graphql.CollectedField, obj *v1.PodStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Message, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStatus_reason(ctx context.Context, field graphql.CollectedField, obj *v1.PodStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Reason, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStatus_nominatedNodeName(ctx context.Context, field graphql.CollectedField, obj *v1.PodStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.NominatedNodeName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStatus_hostIP(ctx context.Context, field graphql.CollectedField, obj *v1.PodStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.HostIP, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStatus_podIP(ctx context.Context, field graphql.CollectedField, obj *v1.PodStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PodIP, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStatus_podIPs(ctx context.Context, field graphql.CollectedField, obj *v1.PodStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PodIPs, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v1.PodIP) + fc.Result = res + return ec.marshalOPodIP2ᚕk8sᚗioᚋapiᚋcoreᚋv1ᚐPodIPᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStatus_startTime(ctx context.Context, field graphql.CollectedField, obj *v1.PodStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStatus", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodStatus().StartTime(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStatus_initContainerStatuses(ctx context.Context, field graphql.CollectedField, obj *v1.PodStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.InitContainerStatuses, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v1.ContainerStatus) + fc.Result = res + return ec.marshalOContainerStatus2ᚕk8sᚗioᚋapiᚋcoreᚋv1ᚐContainerStatusᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStatus_containerStatuses(ctx context.Context, field graphql.CollectedField, obj *v1.PodStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ContainerStatuses, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v1.ContainerStatus) + fc.Result = res + return ec.marshalOContainerStatus2ᚕk8sᚗioᚋapiᚋcoreᚋv1ᚐContainerStatusᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStatus_qosClass(ctx context.Context, field graphql.CollectedField, obj *v1.PodStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStatus", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodStatus().QosClass(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStatus_ephemeralContainerStatuses(ctx context.Context, field graphql.CollectedField, obj *v1.PodStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.EphemeralContainerStatuses, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v1.ContainerStatus) + fc.Result = res + return ec.marshalOContainerStatus2ᚕk8sᚗioᚋapiᚋcoreᚋv1ᚐContainerStatusᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStressChaos_stressChaos(ctx context.Context, field graphql.CollectedField, obj *model.PodStressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStressChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.StressChaos, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*v1alpha1.StressChaos) + fc.Result = res + return ec.marshalNStressChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐStressChaos(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStressChaos_pod(ctx context.Context, field graphql.CollectedField, obj *model.PodStressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStressChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Pod, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*v1.Pod) + fc.Result = res + return ec.marshalNPod2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐPod(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStressChaos_cgroups(ctx context.Context, field graphql.CollectedField, obj *model.PodStressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStressChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodStressChaos().Cgroups(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Cgroups) + fc.Result = res + return ec.marshalNCgroups2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐCgroups(ctx, field.Selections, res) +} + +func (ec *executionContext) _PodStressChaos_processStress(ctx context.Context, field graphql.CollectedField, obj *model.PodStressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "PodStressChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.PodStressChaos().ProcessStress(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*model.ProcessStress) + fc.Result = res + return ec.marshalOProcessStress2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐProcessStressᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Process_pod(ctx context.Context, field graphql.CollectedField, obj *model.Process) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Process", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Pod, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*v1.Pod) + fc.Result = res + return ec.marshalNPod2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐPod(ctx, field.Selections, res) +} + +func (ec *executionContext) _Process_pid(ctx context.Context, field graphql.CollectedField, obj *model.Process) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Process", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Pid, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Process_command(ctx context.Context, field graphql.CollectedField, obj *model.Process) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Process", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Command, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Process_fds(ctx context.Context, field graphql.CollectedField, obj *model.Process) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Process", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Process().Fds(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*model.Fd) + fc.Result = res + return ec.marshalOFd2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐFdᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _ProcessStress_process(ctx context.Context, field graphql.CollectedField, obj *model.ProcessStress) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ProcessStress", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Process, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Process) + fc.Result = res + return ec.marshalNProcess2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐProcess(ctx, field.Selections, res) +} + +func (ec *executionContext) _ProcessStress_cgroup(ctx context.Context, field graphql.CollectedField, obj *model.ProcessStress) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ProcessStress", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Cgroup, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Query_namespace(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Query_namespace_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Namespace(rctx, args["ns"].(*string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*model.Namespace) + fc.Result = res + return ec.marshalONamespace2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐNamespaceᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Query_pods(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Query_pods_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Pods(rctx, args["selector"].(model.PodSelectorInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*v1.Pod) + fc.Result = res + return ec.marshalOPod2ᚕᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐPodᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Query___type_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.introspectType(args["name"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.introspectSchema() + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Schema) + fc.Result = res + return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res) +} + +func (ec *executionContext) _RateSpec_rate(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RateSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RateSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Rate, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawIPSet_name(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawIPSet) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawIPSet", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawIPSet_ipSetType(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawIPSet) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawIPSet", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.RawIPSet().IPSetType(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawIPSet_cidrs(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawIPSet) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawIPSet", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Cidrs, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalNString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawIPSet_cidrAndPorts(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawIPSet) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawIPSet", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.CidrAndPorts, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v1alpha1.CidrAndPort) + fc.Result = res + return ec.marshalOCidrAndPort2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐCidrAndPortᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawIPSet_setNames(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawIPSet) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawIPSet", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SetNames, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalNString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawIPSet_source(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawIPSet) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawIPSet", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Source, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawIptables_name(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawIptables) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawIptables", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawIptables_ipSets(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawIptables) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawIptables", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IPSets, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalNString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawIptables_direction(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawIptables) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawIptables", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.RawIptables().Direction(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawIptables_source(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawIptables) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawIptables", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Source, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawIptables_device(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawIptables) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawIptables", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Device, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawTrafficControl_type(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawTrafficControl) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawTrafficControl", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.RawTrafficControl().Type(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawTrafficControl_delay(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawTrafficControl) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawTrafficControl", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Delay, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.DelaySpec) + fc.Result = res + return ec.marshalODelaySpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐDelaySpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawTrafficControl_loss(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawTrafficControl) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawTrafficControl", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Loss, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.LossSpec) + fc.Result = res + return ec.marshalOLossSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐLossSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawTrafficControl_duplicate(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawTrafficControl) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawTrafficControl", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Duplicate, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.DuplicateSpec) + fc.Result = res + return ec.marshalODuplicateSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐDuplicateSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawTrafficControl_corrupt(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawTrafficControl) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawTrafficControl", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Corrupt, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.CorruptSpec) + fc.Result = res + return ec.marshalOCorruptSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐCorruptSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawTrafficControl_bandwidth(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawTrafficControl) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawTrafficControl", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Bandwidth, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.BandwidthSpec) + fc.Result = res + return ec.marshalOBandwidthSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐBandwidthSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawTrafficControl_rate(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawTrafficControl) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawTrafficControl", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Rate, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.RateSpec) + fc.Result = res + return ec.marshalORateSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRateSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawTrafficControl_ipSet(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawTrafficControl) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawTrafficControl", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IPSet, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawTrafficControl_source(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawTrafficControl) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawTrafficControl", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Source, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _RawTrafficControl_device(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.RawTrafficControl) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RawTrafficControl", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Device, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Record_id(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.Record) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Record", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Id, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Record_selectorKey(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.Record) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Record", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SelectorKey, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Record_phase(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.Record) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Record", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Record().Phase(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ReorderSpec_reorder(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.ReorderSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ReorderSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Reorder, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ReorderSpec_correlation(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.ReorderSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ReorderSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Correlation, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ReorderSpec_gap(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.ReorderSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ReorderSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Gap, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalOInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_kind(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Kind, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_apiVersion(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.APIVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_name(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_generateName(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GenerateName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_namespace(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Namespace, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_selfLink(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SelfLink, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_uid(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.StressChaos().UID(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_resourceVersion(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ResourceVersion, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_generation(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Generation, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalNInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_creationTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.StressChaos().CreationTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalNTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_deletionTimestamp(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.StressChaos().DeletionTimestamp(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_deletionGracePeriodSeconds(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeletionGracePeriodSeconds, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*int64) + fc.Result = res + return ec.marshalOInt2ᚖint64(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_labels(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.StressChaos().Labels(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_annotations(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.StressChaos().Annotations(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_ownerReferences(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.OwnerReferences, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v11.OwnerReference) + fc.Result = res + return ec.marshalOOwnerReference2ᚕk8sᚗioᚋapimachineryᚋpkgᚋapisᚋmetaᚋv1ᚐOwnerReferenceᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_finalizers(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Finalizers, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_spec(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Spec, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.StressChaosSpec) + fc.Result = res + return ec.marshalNStressChaosSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐStressChaosSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaos_podstress(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaos) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaos", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.StressChaos().Podstress(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*model.PodStressChaos) + fc.Result = res + return ec.marshalOPodStressChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐPodStressChaosᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaosSpec_containerNames(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ContainerNames, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaosSpec_selector(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Selector, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(v1alpha1.PodSelectorSpec) + fc.Result = res + return ec.marshalNPodSelectorSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodSelectorSpec(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaosSpec_mode(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaosSpec", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.StressChaosSpec().Mode(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaosSpec_value(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Value, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaosSpec_stressors(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Stressors, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.Stressors) + fc.Result = res + return ec.marshalOStressors2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐStressors(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaosSpec_stressngStressors(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.StressngStressors, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaosSpec_duration(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaosSpec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaosSpec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Duration, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaosStatus_conditions(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Conditions, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]v1alpha1.ChaosCondition) + fc.Result = res + return ec.marshalOChaosCondition2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐChaosConditionᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaosStatus_experiment(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaosStatus", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Experiment, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(v1alpha1.ExperimentStatus) + fc.Result = res + return ec.marshalOExperimentStatus2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐExperimentStatus(ctx, field.Selections, res) +} + +func (ec *executionContext) _StressChaosStatus_instances(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.StressChaosStatus) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "StressChaosStatus", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.StressChaosStatus().Instances(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(map[string]interface{}) + fc.Result = res + return ec.marshalOMap2map(ctx, field.Selections, res) +} + +func (ec *executionContext) _Stressors_memoryStressor(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.Stressors) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Stressors", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.MemoryStressor, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.MemoryStressor) + fc.Result = res + return ec.marshalOMemoryStressor2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐMemoryStressor(ctx, field.Selections, res) +} + +func (ec *executionContext) _Stressors_cpuStressor(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.Stressors) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Stressors", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.CPUStressor, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*v1alpha1.CPUStressor) + fc.Result = res + return ec.marshalOCPUStressor2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐCPUStressor(ctx, field.Selections, res) +} + +func (ec *executionContext) _Timespec_sec(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.Timespec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Timespec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Sec, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalNInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _Timespec_nsec(ctx context.Context, field graphql.CollectedField, obj *v1alpha1.Timespec) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Timespec", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Nsec, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalNInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Directive", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Directive_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Directive", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Directive_locations(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Directive", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Locations, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalN__DirectiveLocation2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Directive", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Args, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]introspection.InputValue) + fc.Result = res + return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Directive", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IsRepeatable, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__EnumValue", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) ___EnumValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__EnumValue", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__EnumValue", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IsDeprecated(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__EnumValue", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeprecationReason(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Field", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Field_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Field", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Field", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Args, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]introspection.InputValue) + fc.Result = res + return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Field", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Type, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Field", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IsDeprecated(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Field", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeprecationReason(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__InputValue", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) ___InputValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__InputValue", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__InputValue", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Type, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__InputValue", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DefaultValue, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Schema_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Schema", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Schema", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Types(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]introspection.Type) + fc.Result = res + return ec.marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Schema", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.QueryType(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Schema", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.MutationType(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Schema", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SubscriptionType(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Schema_directives(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Schema", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Directives(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]introspection.Directive) + fc.Result = res + return ec.marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Kind(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalN__TypeKind2string(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Type_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Type_fields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field___Type_fields_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Fields(args["includeDeprecated"].(bool)), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.Field) + fc.Result = res + return ec.marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Interfaces(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PossibleTypes(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Type_enumValues(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field___Type_enumValues_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.EnumValues(args["includeDeprecated"].(bool)), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.EnumValue) + fc.Result = res + return ec.marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.InputFields(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.InputValue) + fc.Result = res + return ec.marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.OfType(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "__Type", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SpecifiedByURL(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +// endregion **************************** field.gotpl ***************************** + +// region **************************** input.gotpl ***************************** + +func (ec *executionContext) unmarshalInputPodSelectorInput(ctx context.Context, obj interface{}) (model.PodSelectorInput, error) { + var it model.PodSelectorInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + for k, v := range asMap { + switch k { + case "namespaces": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("namespaces")) + it.Namespaces, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err + } + case "nodes": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("nodes")) + it.Nodes, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err + } + case "pods": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("pods")) + it.Pods, err = ec.unmarshalOMap2map(ctx, v) + if err != nil { + return it, err + } + case "nodeSelectors": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("nodeSelectors")) + it.NodeSelectors, err = ec.unmarshalOMap2map(ctx, v) + if err != nil { + return it, err + } + case "fieldSelectors": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fieldSelectors")) + it.FieldSelectors, err = ec.unmarshalOMap2map(ctx, v) + if err != nil { + return it, err + } + case "labelSelectors": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("labelSelectors")) + it.LabelSelectors, err = ec.unmarshalOMap2map(ctx, v) + if err != nil { + return it, err + } + case "annotationSelectors": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("annotationSelectors")) + it.AnnotationSelectors, err = ec.unmarshalOMap2map(ctx, v) + if err != nil { + return it, err + } + case "podPhaseSelectors": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("podPhaseSelectors")) + it.PodPhaseSelectors, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + +// endregion **************************** input.gotpl ***************************** + +// region ************************** interface.gotpl *************************** + +// endregion ************************** interface.gotpl *************************** + +// region **************************** object.gotpl **************************** + +var attrOverrideSpecImplementors = []string{"AttrOverrideSpec"} + +func (ec *executionContext) _AttrOverrideSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.AttrOverrideSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, attrOverrideSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("AttrOverrideSpec") + case "ino": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._AttrOverrideSpec_ino(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "size": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._AttrOverrideSpec_size(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "blocks": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._AttrOverrideSpec_blocks(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "atime": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._AttrOverrideSpec_atime(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "mtime": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._AttrOverrideSpec_mtime(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "ctime": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._AttrOverrideSpec_ctime(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "kind": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._AttrOverrideSpec_kind(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "perm": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._AttrOverrideSpec_perm(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "nlink": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._AttrOverrideSpec_nlink(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "uid": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._AttrOverrideSpec_uid(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "gid": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._AttrOverrideSpec_gid(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "rdev": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._AttrOverrideSpec_rdev(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var bandwidthSpecImplementors = []string{"BandwidthSpec"} + +func (ec *executionContext) _BandwidthSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.BandwidthSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, bandwidthSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("BandwidthSpec") + case "rate": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._BandwidthSpec_rate(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "limit": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._BandwidthSpec_limit(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "buffer": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._BandwidthSpec_buffer(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "peakrate": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._BandwidthSpec_peakrate(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "minburst": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._BandwidthSpec_minburst(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var cPUStressorImplementors = []string{"CPUStressor"} + +func (ec *executionContext) _CPUStressor(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.CPUStressor) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, cPUStressorImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("CPUStressor") + case "workers": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._CPUStressor_workers(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "load": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._CPUStressor_load(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "options": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._CPUStressor_options(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var cgroupsImplementors = []string{"Cgroups"} + +func (ec *executionContext) _Cgroups(ctx context.Context, sel ast.SelectionSet, obj *model.Cgroups) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, cgroupsImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Cgroups") + case "raw": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Cgroups_raw(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "cpu": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Cgroups_cpu(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "memory": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Cgroups_memory(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var cgroupsCpuImplementors = []string{"CgroupsCpu"} + +func (ec *executionContext) _CgroupsCpu(ctx context.Context, sel ast.SelectionSet, obj *model.CgroupsCPU) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, cgroupsCpuImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("CgroupsCpu") + case "quota": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._CgroupsCpu_quota(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "period": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._CgroupsCpu_period(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var cgroupsMemoryImplementors = []string{"CgroupsMemory"} + +func (ec *executionContext) _CgroupsMemory(ctx context.Context, sel ast.SelectionSet, obj *model.CgroupsMemory) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, cgroupsMemoryImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("CgroupsMemory") + case "limit": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._CgroupsMemory_limit(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var chaosConditionImplementors = []string{"ChaosCondition"} + +func (ec *executionContext) _ChaosCondition(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.ChaosCondition) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, chaosConditionImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ChaosCondition") + case "type": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._ChaosCondition_type(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "status": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._ChaosCondition_status(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "reason": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ChaosCondition_reason(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var cidrAndPortImplementors = []string{"CidrAndPort"} + +func (ec *executionContext) _CidrAndPort(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.CidrAndPort) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, cidrAndPortImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("CidrAndPort") + case "cidr": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._CidrAndPort_cidr(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "port": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._CidrAndPort_port(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var containerStateImplementors = []string{"ContainerState"} + +func (ec *executionContext) _ContainerState(ctx context.Context, sel ast.SelectionSet, obj *v1.ContainerState) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, containerStateImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ContainerState") + case "waiting": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerState_waiting(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "running": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerState_running(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "terminated": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerState_terminated(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var containerStateRunningImplementors = []string{"ContainerStateRunning"} + +func (ec *executionContext) _ContainerStateRunning(ctx context.Context, sel ast.SelectionSet, obj *v1.ContainerStateRunning) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, containerStateRunningImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ContainerStateRunning") + case "startedAt": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._ContainerStateRunning_startedAt(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var containerStateTerminatedImplementors = []string{"ContainerStateTerminated"} + +func (ec *executionContext) _ContainerStateTerminated(ctx context.Context, sel ast.SelectionSet, obj *v1.ContainerStateTerminated) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, containerStateTerminatedImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ContainerStateTerminated") + case "exitCode": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStateTerminated_exitCode(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "signal": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStateTerminated_signal(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "reason": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStateTerminated_reason(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "message": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStateTerminated_message(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "startedAt": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._ContainerStateTerminated_startedAt(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "finishedAt": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._ContainerStateTerminated_finishedAt(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "containerID": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStateTerminated_containerID(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var containerStateWaitingImplementors = []string{"ContainerStateWaiting"} + +func (ec *executionContext) _ContainerStateWaiting(ctx context.Context, sel ast.SelectionSet, obj *v1.ContainerStateWaiting) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, containerStateWaitingImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ContainerStateWaiting") + case "reason": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStateWaiting_reason(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "message": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStateWaiting_message(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var containerStatusImplementors = []string{"ContainerStatus"} + +func (ec *executionContext) _ContainerStatus(ctx context.Context, sel ast.SelectionSet, obj *v1.ContainerStatus) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, containerStatusImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ContainerStatus") + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStatus_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "State": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStatus_State(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "lastTerminationState": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStatus_lastTerminationState(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "ready": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStatus_ready(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "restartCount": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStatus_restartCount(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "image": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStatus_image(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "imageID": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStatus_imageID(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "containerID": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStatus_containerID(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "started": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ContainerStatus_started(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var corruptSpecImplementors = []string{"CorruptSpec"} + +func (ec *executionContext) _CorruptSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.CorruptSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, corruptSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("CorruptSpec") + case "corrupt": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._CorruptSpec_corrupt(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "correlation": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._CorruptSpec_correlation(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var delaySpecImplementors = []string{"DelaySpec"} + +func (ec *executionContext) _DelaySpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.DelaySpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, delaySpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("DelaySpec") + case "latency": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._DelaySpec_latency(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "correlation": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._DelaySpec_correlation(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "jitter": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._DelaySpec_jitter(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "reorder": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._DelaySpec_reorder(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var duplicateSpecImplementors = []string{"DuplicateSpec"} + +func (ec *executionContext) _DuplicateSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.DuplicateSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, duplicateSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("DuplicateSpec") + case "duplicate": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._DuplicateSpec_duplicate(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "correlation": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._DuplicateSpec_correlation(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var experimentStatusImplementors = []string{"ExperimentStatus"} + +func (ec *executionContext) _ExperimentStatus(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.ExperimentStatus) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, experimentStatusImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ExperimentStatus") + case "desiredPhase": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._ExperimentStatus_desiredPhase(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "Records": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ExperimentStatus_Records(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var fdImplementors = []string{"Fd"} + +func (ec *executionContext) _Fd(ctx context.Context, sel ast.SelectionSet, obj *model.Fd) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, fdImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Fd") + case "fd": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Fd_fd(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "target": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Fd_target(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var hTTPChaosImplementors = []string{"HTTPChaos"} + +func (ec *executionContext) _HTTPChaos(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.HTTPChaos) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, hTTPChaosImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("HTTPChaos") + case "kind": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaos_kind(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "apiVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaos_apiVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaos_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generateName": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaos_generateName(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "namespace": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaos_namespace(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "selfLink": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaos_selfLink(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "uid": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._HTTPChaos_uid(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "resourceVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaos_resourceVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generation": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaos_generation(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "creationTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._HTTPChaos_creationTimestamp(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._HTTPChaos_deletionTimestamp(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionGracePeriodSeconds": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaos_deletionGracePeriodSeconds(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "labels": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._HTTPChaos_labels(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "annotations": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._HTTPChaos_annotations(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "ownerReferences": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaos_ownerReferences(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "finalizers": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaos_finalizers(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "spec": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaos_spec(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "status": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaos_status(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "podhttp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._HTTPChaos_podhttp(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var hTTPChaosSpecImplementors = []string{"HTTPChaosSpec"} + +func (ec *executionContext) _HTTPChaosSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.HTTPChaosSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, hTTPChaosSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("HTTPChaosSpec") + case "selector": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaosSpec_selector(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "mode": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._HTTPChaosSpec_mode(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "value": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaosSpec_value(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "target": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._HTTPChaosSpec_target(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "abort": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaosSpec_abort(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "delay": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaosSpec_delay(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "replace": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaosSpec_replace(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "patch": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaosSpec_patch(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "port": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaosSpec_port(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "path": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaosSpec_path(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "method": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaosSpec_method(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "code": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaosSpec_code(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "requestHeaders": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._HTTPChaosSpec_requestHeaders(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "responseHeaders": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._HTTPChaosSpec_responseHeaders(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "duration": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaosSpec_duration(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var hTTPChaosStatusImplementors = []string{"HTTPChaosStatus"} + +func (ec *executionContext) _HTTPChaosStatus(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.HTTPChaosStatus) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, hTTPChaosStatusImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("HTTPChaosStatus") + case "conditions": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaosStatus_conditions(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "experiment": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HTTPChaosStatus_experiment(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "instances": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._HTTPChaosStatus_instances(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var iOChaosImplementors = []string{"IOChaos"} + +func (ec *executionContext) _IOChaos(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.IOChaos) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, iOChaosImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("IOChaos") + case "kind": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaos_kind(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "apiVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaos_apiVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaos_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generateName": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaos_generateName(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "namespace": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaos_namespace(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "selfLink": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaos_selfLink(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "uid": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaos_uid(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "resourceVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaos_resourceVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generation": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaos_generation(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "creationTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaos_creationTimestamp(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaos_deletionTimestamp(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionGracePeriodSeconds": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaos_deletionGracePeriodSeconds(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "labels": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaos_labels(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "annotations": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaos_annotations(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "ownerReferences": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaos_ownerReferences(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "finalizers": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaos_finalizers(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "spec": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaos_spec(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "status": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaos_status(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "podios": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaos_podios(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var iOChaosActionImplementors = []string{"IOChaosAction"} + +func (ec *executionContext) _IOChaosAction(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.IOChaosAction) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, iOChaosActionImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("IOChaosAction") + case "type": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_type(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "path": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosAction_path(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "methods": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_methods(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "percent": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosAction_percent(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "faults": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosAction_faults(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "latency": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosAction_latency(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "ino": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_ino(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "size": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_size(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "blocks": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_blocks(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "atime": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_atime(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "mtime": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_mtime(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "ctime": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_ctime(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "kind": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_kind(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "perm": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_perm(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "nlink": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_nlink(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "uid": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_uid(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "gid": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_gid(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "rdev": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_rdev(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "filling": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_filling(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "maxOccurrences": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_maxOccurrences(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "maxLength": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosAction_maxLength(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "source": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosAction_source(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var iOChaosSpecImplementors = []string{"IOChaosSpec"} + +func (ec *executionContext) _IOChaosSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.IOChaosSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, iOChaosSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("IOChaosSpec") + case "containerNames": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosSpec_containerNames(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "selector": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosSpec_selector(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "mode": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosSpec_mode(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "value": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosSpec_value(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "action": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosSpec_action(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "delay": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosSpec_delay(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "errno": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosSpec_errno(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "attr": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosSpec_attr(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "mistake": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosSpec_mistake(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "path": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosSpec_path(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "methods": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosSpec_methods(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "percent": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosSpec_percent(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "volumePath": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosSpec_volumePath(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "duration": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosSpec_duration(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var iOChaosStatusImplementors = []string{"IOChaosStatus"} + +func (ec *executionContext) _IOChaosStatus(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.IOChaosStatus) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, iOChaosStatusImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("IOChaosStatus") + case "conditions": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosStatus_conditions(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "experiment": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IOChaosStatus_experiment(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "instances": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IOChaosStatus_instances(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var ioFaultImplementors = []string{"IoFault"} + +func (ec *executionContext) _IoFault(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.IoFault) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, ioFaultImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("IoFault") + case "errno": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._IoFault_errno(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "weight": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._IoFault_weight(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var killProcessResultImplementors = []string{"KillProcessResult"} + +func (ec *executionContext) _KillProcessResult(ctx context.Context, sel ast.SelectionSet, obj *model.KillProcessResult) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, killProcessResultImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("KillProcessResult") + case "pid": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._KillProcessResult_pid(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "command": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._KillProcessResult_command(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var loggerImplementors = []string{"Logger"} + +func (ec *executionContext) _Logger(ctx context.Context, sel ast.SelectionSet) func() graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, loggerImplementors) + ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ + Object: "Logger", + }) + if len(fields) != 1 { + ec.Errorf(ctx, "must subscribe to exactly one stream") + return nil + } + + switch fields[0].Name { + case "component": + return ec._Logger_component(ctx, fields[0]) + case "pod": + return ec._Logger_pod(ctx, fields[0]) + default: + panic("unknown field " + strconv.Quote(fields[0].Name)) + } +} + +var lossSpecImplementors = []string{"LossSpec"} + +func (ec *executionContext) _LossSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.LossSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, lossSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("LossSpec") + case "loss": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._LossSpec_loss(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "correlation": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._LossSpec_correlation(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var memoryStressorImplementors = []string{"MemoryStressor"} + +func (ec *executionContext) _MemoryStressor(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.MemoryStressor) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, memoryStressorImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("MemoryStressor") + case "workers": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MemoryStressor_workers(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "size": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MemoryStressor_size(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "options": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MemoryStressor_options(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var mistakeSpecImplementors = []string{"MistakeSpec"} + +func (ec *executionContext) _MistakeSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.MistakeSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, mistakeSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("MistakeSpec") + case "filling": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._MistakeSpec_filling(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "maxOccurrences": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MistakeSpec_maxOccurrences(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "maxLength": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MistakeSpec_maxLength(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var mutablePodImplementors = []string{"MutablePod"} + +func (ec *executionContext) _MutablePod(ctx context.Context, sel ast.SelectionSet, obj *model.MutablePod) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, mutablePodImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("MutablePod") + case "pod": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MutablePod_pod(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "killProcesses": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._MutablePod_killProcesses(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "cleanTcs": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._MutablePod_cleanTcs(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "cleanIptables": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._MutablePod_cleanIptables(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var mutationImplementors = []string{"Mutation"} + +func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, mutationImplementors) + ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ + Object: "Mutation", + }) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ + Object: field.Name, + Field: field, + }) + + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Mutation") + case "pod": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_pod(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var namespaceImplementors = []string{"Namespace"} + +func (ec *executionContext) _Namespace(ctx context.Context, sel ast.SelectionSet, obj *model.Namespace) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, namespaceImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Namespace") + case "ns": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Namespace_ns(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "component": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Namespace_component(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "pod": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Namespace_pod(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "stresschaos": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Namespace_stresschaos(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "iochaos": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Namespace_iochaos(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "podiochaos": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Namespace_podiochaos(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "httpchaos": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Namespace_httpchaos(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "podhttpchaos": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Namespace_podhttpchaos(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "networkchaos": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Namespace_networkchaos(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "podnetworkchaos": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Namespace_podnetworkchaos(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var networkChaosImplementors = []string{"NetworkChaos"} + +func (ec *executionContext) _NetworkChaos(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.NetworkChaos) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, networkChaosImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("NetworkChaos") + case "kind": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._NetworkChaos_kind(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "apiVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._NetworkChaos_apiVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._NetworkChaos_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generateName": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._NetworkChaos_generateName(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "namespace": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._NetworkChaos_namespace(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "selfLink": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._NetworkChaos_selfLink(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "uid": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._NetworkChaos_uid(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "resourceVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._NetworkChaos_resourceVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generation": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._NetworkChaos_generation(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "creationTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._NetworkChaos_creationTimestamp(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._NetworkChaos_deletionTimestamp(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionGracePeriodSeconds": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._NetworkChaos_deletionGracePeriodSeconds(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "labels": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._NetworkChaos_labels(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "annotations": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._NetworkChaos_annotations(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "ownerReferences": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._NetworkChaos_ownerReferences(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "finalizers": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._NetworkChaos_finalizers(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "podnetwork": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._NetworkChaos_podnetwork(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var ownerReferenceImplementors = []string{"OwnerReference"} + +func (ec *executionContext) _OwnerReference(ctx context.Context, sel ast.SelectionSet, obj *v11.OwnerReference) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, ownerReferenceImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("OwnerReference") + case "kind": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._OwnerReference_kind(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "apiVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._OwnerReference_apiVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._OwnerReference_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "uid": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._OwnerReference_uid(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "controller": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._OwnerReference_controller(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "blockOwnerDeletion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._OwnerReference_blockOwnerDeletion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podImplementors = []string{"Pod"} + +func (ec *executionContext) _Pod(ctx context.Context, sel ast.SelectionSet, obj *v1.Pod) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Pod") + case "kind": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Pod_kind(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "apiVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Pod_apiVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Pod_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generateName": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Pod_generateName(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "namespace": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Pod_namespace(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "selfLink": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Pod_selfLink(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "uid": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Pod_uid(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "resourceVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Pod_resourceVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generation": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Pod_generation(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "creationTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Pod_creationTimestamp(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Pod_deletionTimestamp(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionGracePeriodSeconds": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Pod_deletionGracePeriodSeconds(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "labels": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Pod_labels(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "annotations": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Pod_annotations(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "ownerReferences": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Pod_ownerReferences(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "finalizers": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Pod_finalizers(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "spec": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Pod_spec(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "status": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Pod_status(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "logs": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Pod_logs(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "daemon": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Pod_daemon(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "processes": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Pod_processes(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "mounts": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Pod_mounts(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "ipset": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Pod_ipset(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "tcQdisc": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Pod_tcQdisc(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "iptables": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Pod_iptables(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podConditionImplementors = []string{"PodCondition"} + +func (ec *executionContext) _PodCondition(ctx context.Context, sel ast.SelectionSet, obj *v1.PodCondition) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podConditionImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodCondition") + case "type": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodCondition_type(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "status": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodCondition_status(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "lastProbeTime": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodCondition_lastProbeTime(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "lastTransitionTime": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodCondition_lastTransitionTime(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "reason": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodCondition_reason(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "message": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodCondition_message(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podHTTPChaosImplementors = []string{"PodHTTPChaos"} + +func (ec *executionContext) _PodHTTPChaos(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodHttpChaos) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podHTTPChaosImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodHTTPChaos") + case "kind": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHTTPChaos_kind(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "apiVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHTTPChaos_apiVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHTTPChaos_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generateName": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHTTPChaos_generateName(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "namespace": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHTTPChaos_namespace(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "selfLink": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHTTPChaos_selfLink(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "uid": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodHTTPChaos_uid(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "resourceVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHTTPChaos_resourceVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generation": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHTTPChaos_generation(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "creationTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodHTTPChaos_creationTimestamp(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodHTTPChaos_deletionTimestamp(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionGracePeriodSeconds": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHTTPChaos_deletionGracePeriodSeconds(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "labels": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodHTTPChaos_labels(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "annotations": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodHTTPChaos_annotations(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "ownerReferences": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHTTPChaos_ownerReferences(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "finalizers": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHTTPChaos_finalizers(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "spec": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHTTPChaos_spec(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "status": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHTTPChaos_status(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "pod": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodHTTPChaos_pod(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podHttpChaosActionsImplementors = []string{"PodHttpChaosActions"} + +func (ec *executionContext) _PodHttpChaosActions(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodHttpChaosActions) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podHttpChaosActionsImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodHttpChaosActions") + case "abort": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosActions_abort(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "delay": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosActions_delay(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "replace": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosActions_replace(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "patch": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosActions_patch(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podHttpChaosPatchActionsImplementors = []string{"PodHttpChaosPatchActions"} + +func (ec *executionContext) _PodHttpChaosPatchActions(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodHttpChaosPatchActions) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podHttpChaosPatchActionsImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodHttpChaosPatchActions") + case "body": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosPatchActions_body(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "queries": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosPatchActions_queries(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "headers": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosPatchActions_headers(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podHttpChaosPatchBodyActionImplementors = []string{"PodHttpChaosPatchBodyAction"} + +func (ec *executionContext) _PodHttpChaosPatchBodyAction(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodHttpChaosPatchBodyAction) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podHttpChaosPatchBodyActionImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodHttpChaosPatchBodyAction") + case "type": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosPatchBodyAction_type(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "value": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosPatchBodyAction_value(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podHttpChaosReplaceActionsImplementors = []string{"PodHttpChaosReplaceActions"} + +func (ec *executionContext) _PodHttpChaosReplaceActions(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodHttpChaosReplaceActions) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podHttpChaosReplaceActionsImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodHttpChaosReplaceActions") + case "path": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosReplaceActions_path(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "method": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosReplaceActions_method(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "code": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosReplaceActions_code(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "body": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodHttpChaosReplaceActions_body(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "queries": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodHttpChaosReplaceActions_queries(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "headers": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodHttpChaosReplaceActions_headers(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podHttpChaosRuleImplementors = []string{"PodHttpChaosRule"} + +func (ec *executionContext) _PodHttpChaosRule(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodHttpChaosRule) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podHttpChaosRuleImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodHttpChaosRule") + case "target": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodHttpChaosRule_target(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "selector": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosRule_selector(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "actions": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosRule_actions(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "source": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosRule_source(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "port": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosRule_port(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podHttpChaosSelectorImplementors = []string{"PodHttpChaosSelector"} + +func (ec *executionContext) _PodHttpChaosSelector(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodHttpChaosSelector) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podHttpChaosSelectorImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodHttpChaosSelector") + case "port": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosSelector_port(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "path": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosSelector_path(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "method": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosSelector_method(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "code": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosSelector_code(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "requestHeaders": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodHttpChaosSelector_requestHeaders(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "responseHeaders": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodHttpChaosSelector_responseHeaders(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podHttpChaosSpecImplementors = []string{"PodHttpChaosSpec"} + +func (ec *executionContext) _PodHttpChaosSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodHttpChaosSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podHttpChaosSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodHttpChaosSpec") + case "rules": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosSpec_rules(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "tls": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosSpec_tls(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podHttpChaosStatusImplementors = []string{"PodHttpChaosStatus"} + +func (ec *executionContext) _PodHttpChaosStatus(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodHttpChaosStatus) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podHttpChaosStatusImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodHttpChaosStatus") + case "pid": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosStatus_pid(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "startTime": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosStatus_startTime(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "failedMessage": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosStatus_failedMessage(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "observedGeneration": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosStatus_observedGeneration(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podHttpChaosTLSImplementors = []string{"PodHttpChaosTLS"} + +func (ec *executionContext) _PodHttpChaosTLS(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodHttpChaosTLS) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podHttpChaosTLSImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodHttpChaosTLS") + case "secretName": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosTLS_secretName(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "secretNamespace": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosTLS_secretNamespace(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "certName": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosTLS_certName(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "keyName": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosTLS_keyName(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "caName": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodHttpChaosTLS_caName(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podIOChaosImplementors = []string{"PodIOChaos"} + +func (ec *executionContext) _PodIOChaos(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodIOChaos) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podIOChaosImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodIOChaos") + case "kind": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaos_kind(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "apiVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaos_apiVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaos_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generateName": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaos_generateName(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "namespace": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaos_namespace(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "selfLink": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaos_selfLink(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "uid": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodIOChaos_uid(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "resourceVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaos_resourceVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generation": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaos_generation(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "creationTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodIOChaos_creationTimestamp(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodIOChaos_deletionTimestamp(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionGracePeriodSeconds": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaos_deletionGracePeriodSeconds(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "labels": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodIOChaos_labels(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "annotations": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodIOChaos_annotations(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "ownerReferences": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaos_ownerReferences(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "finalizers": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaos_finalizers(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "spec": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaos_spec(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "status": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaos_status(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "pod": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodIOChaos_pod(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "ios": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodIOChaos_ios(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podIOChaosSpecImplementors = []string{"PodIOChaosSpec"} + +func (ec *executionContext) _PodIOChaosSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodIOChaosSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podIOChaosSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodIOChaosSpec") + case "volumeMountPath": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaosSpec_volumeMountPath(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "container": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaosSpec_container(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "actions": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaosSpec_actions(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podIOChaosStatusImplementors = []string{"PodIOChaosStatus"} + +func (ec *executionContext) _PodIOChaosStatus(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodIOChaosStatus) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podIOChaosStatusImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodIOChaosStatus") + case "pid": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaosStatus_pid(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "startTime": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaosStatus_startTime(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "failedMessage": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaosStatus_failedMessage(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "observedGeneration": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIOChaosStatus_observedGeneration(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podIPImplementors = []string{"PodIP"} + +func (ec *executionContext) _PodIP(ctx context.Context, sel ast.SelectionSet, obj *v1.PodIP) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podIPImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodIP") + case "ip": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodIP_ip(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podNetworkChaosImplementors = []string{"PodNetworkChaos"} + +func (ec *executionContext) _PodNetworkChaos(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodNetworkChaos) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podNetworkChaosImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodNetworkChaos") + case "kind": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaos_kind(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "apiVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaos_apiVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaos_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generateName": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaos_generateName(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "namespace": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaos_namespace(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "selfLink": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaos_selfLink(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "uid": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodNetworkChaos_uid(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "resourceVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaos_resourceVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generation": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaos_generation(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "creationTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodNetworkChaos_creationTimestamp(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodNetworkChaos_deletionTimestamp(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionGracePeriodSeconds": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaos_deletionGracePeriodSeconds(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "labels": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodNetworkChaos_labels(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "annotations": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodNetworkChaos_annotations(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "ownerReferences": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaos_ownerReferences(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "finalizers": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaos_finalizers(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "spec": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaos_spec(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "status": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaos_status(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "pod": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodNetworkChaos_pod(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podNetworkChaosSpecImplementors = []string{"PodNetworkChaosSpec"} + +func (ec *executionContext) _PodNetworkChaosSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodNetworkChaosSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podNetworkChaosSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodNetworkChaosSpec") + case "ipSets": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaosSpec_ipSets(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "iptables": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaosSpec_iptables(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "trafficControls": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaosSpec_trafficControls(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podNetworkChaosStatusImplementors = []string{"PodNetworkChaosStatus"} + +func (ec *executionContext) _PodNetworkChaosStatus(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodNetworkChaosStatus) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podNetworkChaosStatusImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodNetworkChaosStatus") + case "failedMessage": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaosStatus_failedMessage(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "observedGeneration": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodNetworkChaosStatus_observedGeneration(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podSelectorSpecImplementors = []string{"PodSelectorSpec"} + +func (ec *executionContext) _PodSelectorSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.PodSelectorSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podSelectorSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodSelectorSpec") + case "namespaces": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodSelectorSpec_namespaces(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "nodes": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodSelectorSpec_nodes(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "pods": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodSelectorSpec_pods(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "nodeSelectors": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodSelectorSpec_nodeSelectors(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "fieldSelectors": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodSelectorSpec_fieldSelectors(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "labelSelectors": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodSelectorSpec_labelSelectors(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "annotationSelectors": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodSelectorSpec_annotationSelectors(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "podPhaseSelectors": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodSelectorSpec_podPhaseSelectors(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podSpecImplementors = []string{"PodSpec"} + +func (ec *executionContext) _PodSpec(ctx context.Context, sel ast.SelectionSet, obj *v1.PodSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodSpec") + case "nodeName": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodSpec_nodeName(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podStatusImplementors = []string{"PodStatus"} + +func (ec *executionContext) _PodStatus(ctx context.Context, sel ast.SelectionSet, obj *v1.PodStatus) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podStatusImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodStatus") + case "phase": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodStatus_phase(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "conditions": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodStatus_conditions(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "message": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodStatus_message(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "reason": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodStatus_reason(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "nominatedNodeName": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodStatus_nominatedNodeName(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "hostIP": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodStatus_hostIP(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "podIP": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodStatus_podIP(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "podIPs": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodStatus_podIPs(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "startTime": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodStatus_startTime(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "initContainerStatuses": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodStatus_initContainerStatuses(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "containerStatuses": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodStatus_containerStatuses(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "qosClass": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodStatus_qosClass(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "ephemeralContainerStatuses": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodStatus_ephemeralContainerStatuses(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var podStressChaosImplementors = []string{"PodStressChaos"} + +func (ec *executionContext) _PodStressChaos(ctx context.Context, sel ast.SelectionSet, obj *model.PodStressChaos) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, podStressChaosImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PodStressChaos") + case "stressChaos": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodStressChaos_stressChaos(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "pod": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._PodStressChaos_pod(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "cgroups": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodStressChaos_cgroups(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "processStress": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._PodStressChaos_processStress(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var processImplementors = []string{"Process"} + +func (ec *executionContext) _Process(ctx context.Context, sel ast.SelectionSet, obj *model.Process) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, processImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Process") + case "pod": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Process_pod(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "pid": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Process_pid(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "command": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Process_command(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "fds": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Process_fds(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var processStressImplementors = []string{"ProcessStress"} + +func (ec *executionContext) _ProcessStress(ctx context.Context, sel ast.SelectionSet, obj *model.ProcessStress) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, processStressImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ProcessStress") + case "process": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ProcessStress_process(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "cgroup": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ProcessStress_cgroup(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var queryImplementors = []string{"Query"} + +func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, queryImplementors) + ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ + Object: "Query", + }) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ + Object: field.Name, + Field: field, + }) + + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Query") + case "namespace": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_namespace(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) + }) + case "pods": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_pods(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) + }) + case "__type": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Query___type(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + + case "__schema": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Query___schema(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var rateSpecImplementors = []string{"RateSpec"} + +func (ec *executionContext) _RateSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.RateSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, rateSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("RateSpec") + case "rate": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RateSpec_rate(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var rawIPSetImplementors = []string{"RawIPSet"} + +func (ec *executionContext) _RawIPSet(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.RawIPSet) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, rawIPSetImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("RawIPSet") + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawIPSet_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "ipSetType": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._RawIPSet_ipSetType(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "cidrs": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawIPSet_cidrs(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "cidrAndPorts": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawIPSet_cidrAndPorts(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "setNames": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawIPSet_setNames(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "source": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawIPSet_source(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var rawIptablesImplementors = []string{"RawIptables"} + +func (ec *executionContext) _RawIptables(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.RawIptables) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, rawIptablesImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("RawIptables") + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawIptables_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "ipSets": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawIptables_ipSets(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "direction": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._RawIptables_direction(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "source": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawIptables_source(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "device": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawIptables_device(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var rawTrafficControlImplementors = []string{"RawTrafficControl"} + +func (ec *executionContext) _RawTrafficControl(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.RawTrafficControl) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, rawTrafficControlImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("RawTrafficControl") + case "type": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._RawTrafficControl_type(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "delay": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawTrafficControl_delay(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "loss": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawTrafficControl_loss(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "duplicate": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawTrafficControl_duplicate(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "corrupt": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawTrafficControl_corrupt(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "bandwidth": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawTrafficControl_bandwidth(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "rate": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawTrafficControl_rate(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "ipSet": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawTrafficControl_ipSet(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "source": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawTrafficControl_source(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "device": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._RawTrafficControl_device(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var recordImplementors = []string{"Record"} + +func (ec *executionContext) _Record(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.Record) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, recordImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Record") + case "id": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Record_id(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "selectorKey": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Record_selectorKey(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "phase": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Record_phase(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var reorderSpecImplementors = []string{"ReorderSpec"} + +func (ec *executionContext) _ReorderSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.ReorderSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, reorderSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ReorderSpec") + case "reorder": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ReorderSpec_reorder(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "correlation": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ReorderSpec_correlation(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "gap": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._ReorderSpec_gap(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var stressChaosImplementors = []string{"StressChaos"} + +func (ec *executionContext) _StressChaos(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.StressChaos) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, stressChaosImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("StressChaos") + case "kind": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaos_kind(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "apiVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaos_apiVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaos_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generateName": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaos_generateName(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "namespace": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaos_namespace(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "selfLink": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaos_selfLink(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "uid": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._StressChaos_uid(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "resourceVersion": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaos_resourceVersion(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "generation": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaos_generation(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "creationTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._StressChaos_creationTimestamp(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionTimestamp": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._StressChaos_deletionTimestamp(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "deletionGracePeriodSeconds": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaos_deletionGracePeriodSeconds(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "labels": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._StressChaos_labels(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "annotations": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._StressChaos_annotations(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "ownerReferences": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaos_ownerReferences(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "finalizers": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaos_finalizers(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "spec": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaos_spec(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "podstress": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._StressChaos_podstress(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var stressChaosSpecImplementors = []string{"StressChaosSpec"} + +func (ec *executionContext) _StressChaosSpec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.StressChaosSpec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, stressChaosSpecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("StressChaosSpec") + case "containerNames": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaosSpec_containerNames(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "selector": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaosSpec_selector(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "mode": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._StressChaosSpec_mode(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "value": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaosSpec_value(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "stressors": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaosSpec_stressors(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "stressngStressors": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaosSpec_stressngStressors(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "duration": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaosSpec_duration(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var stressChaosStatusImplementors = []string{"StressChaosStatus"} + +func (ec *executionContext) _StressChaosStatus(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.StressChaosStatus) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, stressChaosStatusImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("StressChaosStatus") + case "conditions": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaosStatus_conditions(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "experiment": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._StressChaosStatus_experiment(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "instances": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._StressChaosStatus_instances(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var stressorsImplementors = []string{"Stressors"} + +func (ec *executionContext) _Stressors(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.Stressors) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, stressorsImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Stressors") + case "memoryStressor": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Stressors_memoryStressor(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "cpuStressor": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Stressors_cpuStressor(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var timespecImplementors = []string{"Timespec"} + +func (ec *executionContext) _Timespec(ctx context.Context, sel ast.SelectionSet, obj *v1alpha1.Timespec) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, timespecImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Timespec") + case "sec": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Timespec_sec(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "nsec": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Timespec_nsec(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var __DirectiveImplementors = []string{"__Directive"} + +func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __DirectiveImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__Directive") + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Directive_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "description": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Directive_description(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "locations": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Directive_locations(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "args": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Directive_args(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "isRepeatable": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Directive_isRepeatable(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var __EnumValueImplementors = []string{"__EnumValue"} + +func (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.EnumValue) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __EnumValueImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__EnumValue") + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___EnumValue_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "description": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___EnumValue_description(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "isDeprecated": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___EnumValue_isDeprecated(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "deprecationReason": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___EnumValue_deprecationReason(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var __FieldImplementors = []string{"__Field"} + +func (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet, obj *introspection.Field) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __FieldImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__Field") + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Field_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "description": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Field_description(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "args": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Field_args(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "type": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Field_type(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "isDeprecated": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Field_isDeprecated(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "deprecationReason": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Field_deprecationReason(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var __InputValueImplementors = []string{"__InputValue"} + +func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.InputValue) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __InputValueImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__InputValue") + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___InputValue_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "description": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___InputValue_description(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "type": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___InputValue_type(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "defaultValue": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___InputValue_defaultValue(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var __SchemaImplementors = []string{"__Schema"} + +func (ec *executionContext) ___Schema(ctx context.Context, sel ast.SelectionSet, obj *introspection.Schema) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __SchemaImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__Schema") + case "description": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Schema_description(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "types": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Schema_types(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "queryType": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Schema_queryType(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "mutationType": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Schema_mutationType(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "subscriptionType": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Schema_subscriptionType(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "directives": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Schema_directives(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var __TypeImplementors = []string{"__Type"} + +func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, obj *introspection.Type) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __TypeImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__Type") + case "kind": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_kind(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "name": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_name(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "description": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_description(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "fields": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_fields(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "interfaces": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_interfaces(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "possibleTypes": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_possibleTypes(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "enumValues": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_enumValues(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "inputFields": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_inputFields(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "ofType": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_ofType(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + case "specifiedByURL": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec.___Type_specifiedByURL(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +// endregion **************************** object.gotpl **************************** + +// region ***************************** type.gotpl ***************************** + +func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v interface{}) (bool, error) { + res, err := graphql.UnmarshalBoolean(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { + res := graphql.MarshalBoolean(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + } + return res +} + +func (ec *executionContext) marshalNCgroups2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐCgroups(ctx context.Context, sel ast.SelectionSet, v model.Cgroups) graphql.Marshaler { + return ec._Cgroups(ctx, sel, &v) +} + +func (ec *executionContext) marshalNCgroups2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐCgroups(ctx context.Context, sel ast.SelectionSet, v *model.Cgroups) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._Cgroups(ctx, sel, v) +} + +func (ec *executionContext) marshalNChaosCondition2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐChaosCondition(ctx context.Context, sel ast.SelectionSet, v v1alpha1.ChaosCondition) graphql.Marshaler { + return ec._ChaosCondition(ctx, sel, &v) +} + +func (ec *executionContext) marshalNCidrAndPort2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐCidrAndPort(ctx context.Context, sel ast.SelectionSet, v v1alpha1.CidrAndPort) graphql.Marshaler { + return ec._CidrAndPort(ctx, sel, &v) +} + +func (ec *executionContext) unmarshalNComponent2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐComponent(ctx context.Context, v interface{}) (model.Component, error) { + var res model.Component + err := res.UnmarshalGQL(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNComponent2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐComponent(ctx context.Context, sel ast.SelectionSet, v model.Component) graphql.Marshaler { + return v +} + +func (ec *executionContext) marshalNContainerStatus2k8sᚗioᚋapiᚋcoreᚋv1ᚐContainerStatus(ctx context.Context, sel ast.SelectionSet, v v1.ContainerStatus) graphql.Marshaler { + return ec._ContainerStatus(ctx, sel, &v) +} + +func (ec *executionContext) marshalNFd2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐFd(ctx context.Context, sel ast.SelectionSet, v *model.Fd) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._Fd(ctx, sel, v) +} + +func (ec *executionContext) marshalNHTTPChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐHTTPChaos(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.HTTPChaos) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._HTTPChaos(ctx, sel, v) +} + +func (ec *executionContext) marshalNHTTPChaosSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐHTTPChaosSpec(ctx context.Context, sel ast.SelectionSet, v v1alpha1.HTTPChaosSpec) graphql.Marshaler { + return ec._HTTPChaosSpec(ctx, sel, &v) +} + +func (ec *executionContext) marshalNHTTPChaosStatus2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐHTTPChaosStatus(ctx context.Context, sel ast.SelectionSet, v v1alpha1.HTTPChaosStatus) graphql.Marshaler { + return ec._HTTPChaosStatus(ctx, sel, &v) +} + +func (ec *executionContext) marshalNIOChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIOChaos(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.IOChaos) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._IOChaos(ctx, sel, v) +} + +func (ec *executionContext) marshalNIOChaosAction2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIOChaosAction(ctx context.Context, sel ast.SelectionSet, v v1alpha1.IOChaosAction) graphql.Marshaler { + return ec._IOChaosAction(ctx, sel, &v) +} + +func (ec *executionContext) marshalNIOChaosSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIOChaosSpec(ctx context.Context, sel ast.SelectionSet, v v1alpha1.IOChaosSpec) graphql.Marshaler { + return ec._IOChaosSpec(ctx, sel, &v) +} + +func (ec *executionContext) marshalNIOChaosStatus2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIOChaosStatus(ctx context.Context, sel ast.SelectionSet, v v1alpha1.IOChaosStatus) graphql.Marshaler { + return ec._IOChaosStatus(ctx, sel, &v) +} + +func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v interface{}) (int, error) { + res, err := graphql.UnmarshalInt(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.SelectionSet, v int) graphql.Marshaler { + res := graphql.MarshalInt(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + } + return res +} + +func (ec *executionContext) unmarshalNInt2int32(ctx context.Context, v interface{}) (int32, error) { + res, err := graphql.UnmarshalInt32(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNInt2int32(ctx context.Context, sel ast.SelectionSet, v int32) graphql.Marshaler { + res := graphql.MarshalInt32(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + } + return res +} + +func (ec *executionContext) unmarshalNInt2int64(ctx context.Context, v interface{}) (int64, error) { + res, err := graphql.UnmarshalInt64(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNInt2int64(ctx context.Context, sel ast.SelectionSet, v int64) graphql.Marshaler { + res := graphql.MarshalInt64(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + } + return res +} + +func (ec *executionContext) unmarshalNInt642int64(ctx context.Context, v interface{}) (int64, error) { + res, err := graphql.UnmarshalInt64(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNInt642int64(ctx context.Context, sel ast.SelectionSet, v int64) graphql.Marshaler { + res := graphql.MarshalInt64(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + } + return res +} + +func (ec *executionContext) marshalNIoFault2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIoFault(ctx context.Context, sel ast.SelectionSet, v v1alpha1.IoFault) graphql.Marshaler { + return ec._IoFault(ctx, sel, &v) +} + +func (ec *executionContext) marshalNKillProcessResult2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐKillProcessResult(ctx context.Context, sel ast.SelectionSet, v *model.KillProcessResult) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._KillProcessResult(ctx, sel, v) +} + +func (ec *executionContext) marshalNNamespace2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐNamespace(ctx context.Context, sel ast.SelectionSet, v *model.Namespace) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._Namespace(ctx, sel, v) +} + +func (ec *executionContext) marshalNNetworkChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐNetworkChaos(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.NetworkChaos) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._NetworkChaos(ctx, sel, v) +} + +func (ec *executionContext) marshalNOwnerReference2k8sᚗioᚋapimachineryᚋpkgᚋapisᚋmetaᚋv1ᚐOwnerReference(ctx context.Context, sel ast.SelectionSet, v v11.OwnerReference) graphql.Marshaler { + return ec._OwnerReference(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPod2k8sᚗioᚋapiᚋcoreᚋv1ᚐPod(ctx context.Context, sel ast.SelectionSet, v v1.Pod) graphql.Marshaler { + return ec._Pod(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPod2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐPod(ctx context.Context, sel ast.SelectionSet, v *v1.Pod) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._Pod(ctx, sel, v) +} + +func (ec *executionContext) marshalNPodCondition2k8sᚗioᚋapiᚋcoreᚋv1ᚐPodCondition(ctx context.Context, sel ast.SelectionSet, v v1.PodCondition) graphql.Marshaler { + return ec._PodCondition(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPodHTTPChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaos(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.PodHttpChaos) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._PodHTTPChaos(ctx, sel, v) +} + +func (ec *executionContext) marshalNPodHttpChaosActions2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosActions(ctx context.Context, sel ast.SelectionSet, v v1alpha1.PodHttpChaosActions) graphql.Marshaler { + return ec._PodHttpChaosActions(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPodHttpChaosRule2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosRule(ctx context.Context, sel ast.SelectionSet, v v1alpha1.PodHttpChaosRule) graphql.Marshaler { + return ec._PodHttpChaosRule(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPodHttpChaosRule2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosRuleᚄ(ctx context.Context, sel ast.SelectionSet, v []v1alpha1.PodHttpChaosRule) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNPodHttpChaosRule2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosRule(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNPodHttpChaosSelector2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosSelector(ctx context.Context, sel ast.SelectionSet, v v1alpha1.PodHttpChaosSelector) graphql.Marshaler { + return ec._PodHttpChaosSelector(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPodHttpChaosSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosSpec(ctx context.Context, sel ast.SelectionSet, v v1alpha1.PodHttpChaosSpec) graphql.Marshaler { + return ec._PodHttpChaosSpec(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPodHttpChaosStatus2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosStatus(ctx context.Context, sel ast.SelectionSet, v v1alpha1.PodHttpChaosStatus) graphql.Marshaler { + return ec._PodHttpChaosStatus(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPodIOChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodIOChaos(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.PodIOChaos) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._PodIOChaos(ctx, sel, v) +} + +func (ec *executionContext) marshalNPodIOChaosSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodIOChaosSpec(ctx context.Context, sel ast.SelectionSet, v v1alpha1.PodIOChaosSpec) graphql.Marshaler { + return ec._PodIOChaosSpec(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPodIOChaosStatus2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodIOChaosStatus(ctx context.Context, sel ast.SelectionSet, v v1alpha1.PodIOChaosStatus) graphql.Marshaler { + return ec._PodIOChaosStatus(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPodIP2k8sᚗioᚋapiᚋcoreᚋv1ᚐPodIP(ctx context.Context, sel ast.SelectionSet, v v1.PodIP) graphql.Marshaler { + return ec._PodIP(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPodNetworkChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodNetworkChaos(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.PodNetworkChaos) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._PodNetworkChaos(ctx, sel, v) +} + +func (ec *executionContext) marshalNPodNetworkChaosSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodNetworkChaosSpec(ctx context.Context, sel ast.SelectionSet, v v1alpha1.PodNetworkChaosSpec) graphql.Marshaler { + return ec._PodNetworkChaosSpec(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPodNetworkChaosStatus2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodNetworkChaosStatus(ctx context.Context, sel ast.SelectionSet, v v1alpha1.PodNetworkChaosStatus) graphql.Marshaler { + return ec._PodNetworkChaosStatus(ctx, sel, &v) +} + +func (ec *executionContext) unmarshalNPodSelectorInput2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐPodSelectorInput(ctx context.Context, v interface{}) (model.PodSelectorInput, error) { + res, err := ec.unmarshalInputPodSelectorInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNPodSelectorSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodSelectorSpec(ctx context.Context, sel ast.SelectionSet, v v1alpha1.PodSelectorSpec) graphql.Marshaler { + return ec._PodSelectorSpec(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPodSpec2k8sᚗioᚋapiᚋcoreᚋv1ᚐPodSpec(ctx context.Context, sel ast.SelectionSet, v v1.PodSpec) graphql.Marshaler { + return ec._PodSpec(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPodStatus2k8sᚗioᚋapiᚋcoreᚋv1ᚐPodStatus(ctx context.Context, sel ast.SelectionSet, v v1.PodStatus) graphql.Marshaler { + return ec._PodStatus(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPodStressChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐPodStressChaos(ctx context.Context, sel ast.SelectionSet, v *model.PodStressChaos) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._PodStressChaos(ctx, sel, v) +} + +func (ec *executionContext) marshalNProcess2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐProcess(ctx context.Context, sel ast.SelectionSet, v *model.Process) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._Process(ctx, sel, v) +} + +func (ec *executionContext) marshalNProcessStress2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐProcessStress(ctx context.Context, sel ast.SelectionSet, v *model.ProcessStress) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._ProcessStress(ctx, sel, v) +} + +func (ec *executionContext) marshalNRawIPSet2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRawIPSet(ctx context.Context, sel ast.SelectionSet, v v1alpha1.RawIPSet) graphql.Marshaler { + return ec._RawIPSet(ctx, sel, &v) +} + +func (ec *executionContext) marshalNRawIptables2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRawIptables(ctx context.Context, sel ast.SelectionSet, v v1alpha1.RawIptables) graphql.Marshaler { + return ec._RawIptables(ctx, sel, &v) +} + +func (ec *executionContext) marshalNRawTrafficControl2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRawTrafficControl(ctx context.Context, sel ast.SelectionSet, v v1alpha1.RawTrafficControl) graphql.Marshaler { + return ec._RawTrafficControl(ctx, sel, &v) +} + +func (ec *executionContext) marshalNRecord2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRecord(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.Record) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._Record(ctx, sel, v) +} + +func (ec *executionContext) marshalNStressChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐStressChaos(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.StressChaos) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._StressChaos(ctx, sel, v) +} + +func (ec *executionContext) marshalNStressChaosSpec2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐStressChaosSpec(ctx context.Context, sel ast.SelectionSet, v v1alpha1.StressChaosSpec) graphql.Marshaler { + return ec._StressChaosSpec(ctx, sel, &v) +} + +func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) { + res, err := graphql.UnmarshalString(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + res := graphql.MarshalString(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + } + return res +} + +func (ec *executionContext) unmarshalNString2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { + var vSlice []interface{} + if v != nil { + vSlice = graphql.CoerceList(v) + } + var err error + res := make([]string, len(vSlice)) + for i := range vSlice { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) + res[i], err = ec.unmarshalNString2string(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + +func (ec *executionContext) marshalNString2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + for i := range v { + ret[i] = ec.marshalNString2string(ctx, sel, v[i]) + } + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) unmarshalNTime2timeᚐTime(ctx context.Context, v interface{}) (time.Time, error) { + res, err := graphql.UnmarshalTime(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNTime2timeᚐTime(ctx context.Context, sel ast.SelectionSet, v time.Time) graphql.Marshaler { + res := graphql.MarshalTime(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + } + return res +} + +func (ec *executionContext) unmarshalNTime2ᚖtimeᚐTime(ctx context.Context, v interface{}) (*time.Time, error) { + res, err := graphql.UnmarshalTime(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNTime2ᚖtimeᚐTime(ctx context.Context, sel ast.SelectionSet, v *time.Time) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := graphql.MarshalTime(*v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + } + return res +} + +func (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx context.Context, sel ast.SelectionSet, v introspection.Directive) graphql.Marshaler { + return ec.___Directive(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Directive) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v interface{}) (string, error) { + res, err := graphql.UnmarshalString(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + res := graphql.MarshalString(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + } + return res +} + +func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { + var vSlice []interface{} + if v != nil { + vSlice = graphql.CoerceList(v) + } + var err error + res := make([]string, len(vSlice)) + for i := range vSlice { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) + res[i], err = ec.unmarshalN__DirectiveLocation2string(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + +func (ec *executionContext) marshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__DirectiveLocation2string(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx context.Context, sel ast.SelectionSet, v introspection.EnumValue) graphql.Marshaler { + return ec.___EnumValue(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx context.Context, sel ast.SelectionSet, v introspection.Field) graphql.Marshaler { + return ec.___Field(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx context.Context, sel ast.SelectionSet, v introspection.InputValue) graphql.Marshaler { + return ec.___InputValue(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v introspection.Type) graphql.Marshaler { + return ec.___Type(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec.___Type(ctx, sel, v) +} + +func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v interface{}) (string, error) { + res, err := graphql.UnmarshalString(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + res := graphql.MarshalString(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + } + return res +} + +func (ec *executionContext) marshalOAttrOverrideSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐAttrOverrideSpec(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.AttrOverrideSpec) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._AttrOverrideSpec(ctx, sel, v) +} + +func (ec *executionContext) marshalOBandwidthSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐBandwidthSpec(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.BandwidthSpec) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._BandwidthSpec(ctx, sel, v) +} + +func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) { + res, err := graphql.UnmarshalBoolean(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { + res := graphql.MarshalBoolean(v) + return res +} + +func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v interface{}) (*bool, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalBoolean(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast.SelectionSet, v *bool) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalBoolean(*v) + return res +} + +func (ec *executionContext) marshalOCPUStressor2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐCPUStressor(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.CPUStressor) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._CPUStressor(ctx, sel, v) +} + +func (ec *executionContext) marshalOCgroupsCpu2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐCgroupsCPU(ctx context.Context, sel ast.SelectionSet, v *model.CgroupsCPU) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._CgroupsCpu(ctx, sel, v) +} + +func (ec *executionContext) marshalOCgroupsMemory2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐCgroupsMemory(ctx context.Context, sel ast.SelectionSet, v *model.CgroupsMemory) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._CgroupsMemory(ctx, sel, v) +} + +func (ec *executionContext) marshalOChaosCondition2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐChaosConditionᚄ(ctx context.Context, sel ast.SelectionSet, v []v1alpha1.ChaosCondition) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNChaosCondition2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐChaosCondition(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOCidrAndPort2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐCidrAndPortᚄ(ctx context.Context, sel ast.SelectionSet, v []v1alpha1.CidrAndPort) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNCidrAndPort2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐCidrAndPort(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOContainerState2k8sᚗioᚋapiᚋcoreᚋv1ᚐContainerState(ctx context.Context, sel ast.SelectionSet, v v1.ContainerState) graphql.Marshaler { + return ec._ContainerState(ctx, sel, &v) +} + +func (ec *executionContext) marshalOContainerStateRunning2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐContainerStateRunning(ctx context.Context, sel ast.SelectionSet, v *v1.ContainerStateRunning) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._ContainerStateRunning(ctx, sel, v) +} + +func (ec *executionContext) marshalOContainerStateTerminated2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐContainerStateTerminated(ctx context.Context, sel ast.SelectionSet, v *v1.ContainerStateTerminated) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._ContainerStateTerminated(ctx, sel, v) +} + +func (ec *executionContext) marshalOContainerStateWaiting2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐContainerStateWaiting(ctx context.Context, sel ast.SelectionSet, v *v1.ContainerStateWaiting) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._ContainerStateWaiting(ctx, sel, v) +} + +func (ec *executionContext) marshalOContainerStatus2ᚕk8sᚗioᚋapiᚋcoreᚋv1ᚐContainerStatusᚄ(ctx context.Context, sel ast.SelectionSet, v []v1.ContainerStatus) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNContainerStatus2k8sᚗioᚋapiᚋcoreᚋv1ᚐContainerStatus(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOCorruptSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐCorruptSpec(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.CorruptSpec) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._CorruptSpec(ctx, sel, v) +} + +func (ec *executionContext) marshalODelaySpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐDelaySpec(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.DelaySpec) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._DelaySpec(ctx, sel, v) +} + +func (ec *executionContext) marshalODuplicateSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐDuplicateSpec(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.DuplicateSpec) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._DuplicateSpec(ctx, sel, v) +} + +func (ec *executionContext) marshalOExperimentStatus2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐExperimentStatus(ctx context.Context, sel ast.SelectionSet, v v1alpha1.ExperimentStatus) graphql.Marshaler { + return ec._ExperimentStatus(ctx, sel, &v) +} + +func (ec *executionContext) marshalOFd2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐFdᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Fd) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNFd2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐFd(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOHTTPChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐHTTPChaosᚄ(ctx context.Context, sel ast.SelectionSet, v []*v1alpha1.HTTPChaos) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNHTTPChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐHTTPChaos(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOIOChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIOChaosᚄ(ctx context.Context, sel ast.SelectionSet, v []*v1alpha1.IOChaos) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNIOChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIOChaos(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOIOChaosAction2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIOChaosActionᚄ(ctx context.Context, sel ast.SelectionSet, v []v1alpha1.IOChaosAction) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNIOChaosAction2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIOChaosAction(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) unmarshalOInt2int(ctx context.Context, v interface{}) (int, error) { + res, err := graphql.UnmarshalInt(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOInt2int(ctx context.Context, sel ast.SelectionSet, v int) graphql.Marshaler { + res := graphql.MarshalInt(v) + return res +} + +func (ec *executionContext) unmarshalOInt2int32(ctx context.Context, v interface{}) (int32, error) { + res, err := graphql.UnmarshalInt32(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOInt2int32(ctx context.Context, sel ast.SelectionSet, v int32) graphql.Marshaler { + res := graphql.MarshalInt32(v) + return res +} + +func (ec *executionContext) unmarshalOInt2int64(ctx context.Context, v interface{}) (int64, error) { + res, err := graphql.UnmarshalInt64(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOInt2int64(ctx context.Context, sel ast.SelectionSet, v int64) graphql.Marshaler { + res := graphql.MarshalInt64(v) + return res +} + +func (ec *executionContext) unmarshalOInt2ᚖint(ctx context.Context, v interface{}) (*int, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalInt(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOInt2ᚖint(ctx context.Context, sel ast.SelectionSet, v *int) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalInt(*v) + return res +} + +func (ec *executionContext) unmarshalOInt2ᚖint32(ctx context.Context, v interface{}) (*int32, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalInt32(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOInt2ᚖint32(ctx context.Context, sel ast.SelectionSet, v *int32) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalInt32(*v) + return res +} + +func (ec *executionContext) unmarshalOInt2ᚖint64(ctx context.Context, v interface{}) (*int64, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalInt64(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOInt2ᚖint64(ctx context.Context, sel ast.SelectionSet, v *int64) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalInt64(*v) + return res +} + +func (ec *executionContext) unmarshalOInt642ᚖint64(ctx context.Context, v interface{}) (*int64, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalInt64(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOInt642ᚖint64(ctx context.Context, sel ast.SelectionSet, v *int64) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalInt64(*v) + return res +} + +func (ec *executionContext) marshalOIoFault2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIoFaultᚄ(ctx context.Context, sel ast.SelectionSet, v []v1alpha1.IoFault) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNIoFault2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐIoFault(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOKillProcessResult2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐKillProcessResultᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.KillProcessResult) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNKillProcessResult2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐKillProcessResult(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOLossSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐLossSpec(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.LossSpec) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._LossSpec(ctx, sel, v) +} + +func (ec *executionContext) unmarshalOMap2map(ctx context.Context, v interface{}) (map[string]interface{}, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalMap(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOMap2map(ctx context.Context, sel ast.SelectionSet, v map[string]interface{}) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalMap(v) + return res +} + +func (ec *executionContext) marshalOMemoryStressor2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐMemoryStressor(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.MemoryStressor) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._MemoryStressor(ctx, sel, v) +} + +func (ec *executionContext) marshalOMistakeSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐMistakeSpec(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.MistakeSpec) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._MistakeSpec(ctx, sel, v) +} + +func (ec *executionContext) marshalOMutablePod2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐMutablePod(ctx context.Context, sel ast.SelectionSet, v *model.MutablePod) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._MutablePod(ctx, sel, v) +} + +func (ec *executionContext) marshalONamespace2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐNamespaceᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Namespace) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNNamespace2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐNamespace(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalONetworkChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐNetworkChaosᚄ(ctx context.Context, sel ast.SelectionSet, v []*v1alpha1.NetworkChaos) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNNetworkChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐNetworkChaos(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOOwnerReference2ᚕk8sᚗioᚋapimachineryᚋpkgᚋapisᚋmetaᚋv1ᚐOwnerReferenceᚄ(ctx context.Context, sel ast.SelectionSet, v []v11.OwnerReference) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNOwnerReference2k8sᚗioᚋapimachineryᚋpkgᚋapisᚋmetaᚋv1ᚐOwnerReference(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOPod2ᚕᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐPodᚄ(ctx context.Context, sel ast.SelectionSet, v []*v1.Pod) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNPod2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐPod(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOPod2ᚖk8sᚗioᚋapiᚋcoreᚋv1ᚐPod(ctx context.Context, sel ast.SelectionSet, v *v1.Pod) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._Pod(ctx, sel, v) +} + +func (ec *executionContext) marshalOPodCondition2ᚕk8sᚗioᚋapiᚋcoreᚋv1ᚐPodConditionᚄ(ctx context.Context, sel ast.SelectionSet, v []v1.PodCondition) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNPodCondition2k8sᚗioᚋapiᚋcoreᚋv1ᚐPodCondition(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOPodHTTPChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosᚄ(ctx context.Context, sel ast.SelectionSet, v []*v1alpha1.PodHttpChaos) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNPodHTTPChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaos(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOPodHttpChaosPatchActions2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosPatchActions(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.PodHttpChaosPatchActions) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._PodHttpChaosPatchActions(ctx, sel, v) +} + +func (ec *executionContext) marshalOPodHttpChaosPatchBodyAction2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosPatchBodyAction(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.PodHttpChaosPatchBodyAction) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._PodHttpChaosPatchBodyAction(ctx, sel, v) +} + +func (ec *executionContext) marshalOPodHttpChaosReplaceActions2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosReplaceActions(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.PodHttpChaosReplaceActions) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._PodHttpChaosReplaceActions(ctx, sel, v) +} + +func (ec *executionContext) marshalOPodHttpChaosTLS2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodHttpChaosTLS(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.PodHttpChaosTLS) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._PodHttpChaosTLS(ctx, sel, v) +} + +func (ec *executionContext) marshalOPodIOChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodIOChaosᚄ(ctx context.Context, sel ast.SelectionSet, v []*v1alpha1.PodIOChaos) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNPodIOChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodIOChaos(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOPodIP2ᚕk8sᚗioᚋapiᚋcoreᚋv1ᚐPodIPᚄ(ctx context.Context, sel ast.SelectionSet, v []v1.PodIP) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNPodIP2k8sᚗioᚋapiᚋcoreᚋv1ᚐPodIP(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOPodNetworkChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodNetworkChaosᚄ(ctx context.Context, sel ast.SelectionSet, v []*v1alpha1.PodNetworkChaos) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNPodNetworkChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐPodNetworkChaos(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOPodStressChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐPodStressChaosᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.PodStressChaos) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNPodStressChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐPodStressChaos(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOProcess2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐProcessᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Process) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNProcess2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐProcess(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOProcessStress2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐProcessStressᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.ProcessStress) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNProcessStress2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋpkgᚋctrlᚋserverᚋmodelᚐProcessStress(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalORateSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRateSpec(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.RateSpec) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._RateSpec(ctx, sel, v) +} + +func (ec *executionContext) marshalORawIPSet2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRawIPSetᚄ(ctx context.Context, sel ast.SelectionSet, v []v1alpha1.RawIPSet) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNRawIPSet2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRawIPSet(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalORawIptables2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRawIptablesᚄ(ctx context.Context, sel ast.SelectionSet, v []v1alpha1.RawIptables) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNRawIptables2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRawIptables(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalORawTrafficControl2ᚕgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRawTrafficControlᚄ(ctx context.Context, sel ast.SelectionSet, v []v1alpha1.RawTrafficControl) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNRawTrafficControl2githubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRawTrafficControl(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalORecord2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRecordᚄ(ctx context.Context, sel ast.SelectionSet, v []*v1alpha1.Record) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNRecord2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐRecord(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOReorderSpec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐReorderSpec(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.ReorderSpec) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._ReorderSpec(ctx, sel, v) +} + +func (ec *executionContext) marshalOStressChaos2ᚕᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐStressChaosᚄ(ctx context.Context, sel ast.SelectionSet, v []*v1alpha1.StressChaos) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNStressChaos2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐStressChaos(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalOStressors2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐStressors(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.Stressors) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._Stressors(ctx, sel, v) +} + +func (ec *executionContext) unmarshalOString2string(ctx context.Context, v interface{}) (string, error) { + res, err := graphql.UnmarshalString(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + res := graphql.MarshalString(v) + return res +} + +func (ec *executionContext) unmarshalOString2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { + if v == nil { + return nil, nil + } + var vSlice []interface{} + if v != nil { + vSlice = graphql.CoerceList(v) + } + var err error + res := make([]string, len(vSlice)) + for i := range vSlice { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) + res[i], err = ec.unmarshalNString2string(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + +func (ec *executionContext) marshalOString2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + for i := range v { + ret[i] = ec.marshalNString2string(ctx, sel, v[i]) + } + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) unmarshalOString2ᚕᚕstringᚄ(ctx context.Context, v interface{}) ([][]string, error) { + if v == nil { + return nil, nil + } + var vSlice []interface{} + if v != nil { + vSlice = graphql.CoerceList(v) + } + var err error + res := make([][]string, len(vSlice)) + for i := range vSlice { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) + res[i], err = ec.unmarshalNString2ᚕstringᚄ(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + +func (ec *executionContext) marshalOString2ᚕᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v [][]string) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + for i := range v { + ret[i] = ec.marshalNString2ᚕstringᚄ(ctx, sel, v[i]) + } + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalString(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalString(*v) + return res +} + +func (ec *executionContext) unmarshalOTime2ᚖtimeᚐTime(ctx context.Context, v interface{}) (*time.Time, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalTime(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOTime2ᚖtimeᚐTime(ctx context.Context, sel ast.SelectionSet, v *time.Time) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalTime(*v) + return res +} + +func (ec *executionContext) marshalOTimespec2ᚖgithubᚗcomᚋchaosᚑmeshᚋchaosᚑmeshᚋapiᚋv1alpha1ᚐTimespec(ctx context.Context, sel ast.SelectionSet, v *v1alpha1.Timespec) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._Timespec(ctx, sel, v) +} + +func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Field) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx context.Context, sel ast.SelectionSet, v *introspection.Schema) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec.___Schema(ctx, sel, v) +} + +func (ec *executionContext) marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec.___Type(ctx, sel, v) +} + +// endregion ***************************** type.gotpl ***************************** diff --git a/pkg/ctrl/server/k8s-utils.go b/pkg/ctrl/server/k8s-utils.go new file mode 100644 index 0000000000..43ab8390b8 --- /dev/null +++ b/pkg/ctrl/server/k8s-utils.go @@ -0,0 +1,105 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package server + +import ( + "context" + "strings" + + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + ctrlconfig "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/model" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/pod" +) + +const DefaultNamespace = "default" + +func componentLabels(component model.Component) map[string]string { + var componentLabel string + switch component { + case model.ComponentManager: + componentLabel = "controller-manager" + case model.ComponentDaemon: + componentLabel = "chaos-daemon" + case model.ComponentDashboard: + componentLabel = "chaos-dashboard" + case model.ComponentDNSServer: + componentLabel = "chaos-dns-server" + default: + return nil + } + return map[string]string{ + "app.kubernetes.io/component": componentLabel, + } +} + +func parseNamespacedName(namespacedName string) types.NamespacedName { + parts := strings.Split(namespacedName, "/") + return types.NamespacedName{ + Namespace: parts[0], + Name: parts[1], + } +} + +// GetPods returns pod list and corresponding chaos daemon +func GetPods(ctx context.Context, status v1alpha1.ChaosStatus, selectorSpec v1alpha1.PodSelectorSpec, c client.Client) ([]v1.Pod, []v1.Pod, error) { + pods, err := pod.SelectPods(ctx, c, c, selectorSpec, ctrlconfig.ControllerCfg.ClusterScoped, ctrlconfig.ControllerCfg.TargetNamespace, false) + if err != nil { + return nil, nil, errors.Wrap(err, "failed to SelectPods") + } + if len(pods) == 0 { + return nil, nil, nil + } + + daemonMap, err := getDaemonMap(ctx, c) + if err != nil { + return nil, nil, errors.Wrap(err, "get daemon map") + } + + var chaosDaemons []v1.Pod + // get chaos daemon + for _, chaosPod := range pods { + daemon, exist := daemonMap[chaosPod.Spec.NodeName] + if !exist { + return nil, nil, errors.Errorf("no daemons found for pod %s", chaosPod.GetName()) + } + chaosDaemons = append(chaosDaemons, daemon) + } + + return pods, chaosDaemons, nil +} + +// GetDaemonMap returns a map of node name to daemon pod +func getDaemonMap(ctx context.Context, c client.Client) (map[string]v1.Pod, error) { + var list v1.PodList + labels := componentLabels(model.ComponentDaemon) + if err := c.List(ctx, &list, client.MatchingLabels(labels)); err != nil { + return nil, errors.Wrapf(err, "list daemons by label %v", labels) + } + + daemonMap := map[string]v1.Pod{} + for _, d := range list.Items { + if d.Spec.NodeName != "" { + daemonMap[d.Spec.NodeName] = d + } + } + return daemonMap, nil +} diff --git a/pkg/ctrl/server/model/models_gen.go b/pkg/ctrl/server/model/models_gen.go new file mode 100644 index 0000000000..deeb57aebd --- /dev/null +++ b/pkg/ctrl/server/model/models_gen.go @@ -0,0 +1,133 @@ +// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. + +package model + +import ( + "fmt" + "io" + "strconv" + + v1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type Cgroups struct { + Raw string `json:"raw"` + CPU *CgroupsCPU `json:"cpu"` + Memory *CgroupsMemory `json:"memory"` +} + +type CgroupsCPU struct { + Quota int `json:"quota"` + Period int `json:"period"` +} + +type CgroupsMemory struct { + Limit int64 `json:"limit"` +} + +type Fd struct { + Fd string `json:"fd"` + Target string `json:"target"` +} + +type KillProcessResult struct { + Pid string `json:"pid"` + Command string `json:"command"` +} + +type MutablePod struct { + Pod *v1.Pod `json:"pod"` + KillProcesses []*KillProcessResult `json:"killProcesses"` + CleanTcs []string `json:"cleanTcs"` + CleanIptables []string `json:"cleanIptables"` +} + +type Namespace struct { + Ns string `json:"ns"` + Component []*v1.Pod `json:"component"` + Pod []*v1.Pod `json:"pod"` + Stresschaos []*v1alpha1.StressChaos `json:"stresschaos"` + Iochaos []*v1alpha1.IOChaos `json:"iochaos"` + Podiochaos []*v1alpha1.PodIOChaos `json:"podiochaos"` + Httpchaos []*v1alpha1.HTTPChaos `json:"httpchaos"` + Podhttpchaos []*v1alpha1.PodHttpChaos `json:"podhttpchaos"` + Networkchaos []*v1alpha1.NetworkChaos `json:"networkchaos"` + Podnetworkchaos []*v1alpha1.PodNetworkChaos `json:"podnetworkchaos"` +} + +type PodSelectorInput struct { + Namespaces []string `json:"namespaces"` + Nodes []string `json:"nodes"` + Pods map[string]interface{} `json:"pods"` + NodeSelectors map[string]interface{} `json:"nodeSelectors"` + FieldSelectors map[string]interface{} `json:"fieldSelectors"` + LabelSelectors map[string]interface{} `json:"labelSelectors"` + AnnotationSelectors map[string]interface{} `json:"annotationSelectors"` + PodPhaseSelectors []string `json:"podPhaseSelectors"` +} + +type PodStressChaos struct { + StressChaos *v1alpha1.StressChaos `json:"stressChaos"` + Pod *v1.Pod `json:"pod"` + Cgroups *Cgroups `json:"cgroups"` + ProcessStress []*ProcessStress `json:"processStress"` +} + +type Process struct { + Pod *v1.Pod `json:"pod"` + Pid string `json:"pid"` + Command string `json:"command"` + Fds []*Fd `json:"fds"` +} + +type ProcessStress struct { + Process *Process `json:"process"` + Cgroup string `json:"cgroup"` +} + +type Component string + +const ( + ComponentManager Component = "MANAGER" + ComponentDaemon Component = "DAEMON" + ComponentDashboard Component = "DASHBOARD" + ComponentDNSServer Component = "DNSSERVER" +) + +var AllComponent = []Component{ + ComponentManager, + ComponentDaemon, + ComponentDashboard, + ComponentDNSServer, +} + +func (e Component) IsValid() bool { + switch e { + case ComponentManager, ComponentDaemon, ComponentDashboard, ComponentDNSServer: + return true + } + return false +} + +func (e Component) String() string { + return string(e) +} + +func (e *Component) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = Component(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid Component", str) + } + return nil +} + +func (e Component) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} diff --git a/pkg/ctrl/server/mount.go b/pkg/ctrl/server/mount.go new file mode 100644 index 0000000000..64533a62f3 --- /dev/null +++ b/pkg/ctrl/server/mount.go @@ -0,0 +1,46 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package server + +import ( + "context" + "strings" + + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/pkg/bpm" +) + +// GetMounts returns mounts info +// The output looks like: +// ``` +// proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0 +// sys /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0 +// dev /dev devtmpfs rw,nosuid,relatime,size=16283300k,nr_inodes=4070825,mode=755,inode64 0 0 +// run /run tmpfs rw,nosuid,nodev,relatime,mode=755,inode64 0 0 +// tmpfs /dev/shm tmpfs rw,nosuid,nodev,inode64 0 0 +// cgroup2 /sys/fs/cgroup cgroup2 rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot 0 0 +// tmpfs /run/user/1000 tmpfs rw,nosuid,nodev,relatime,size=3258252k,nr_inodes=814563,mode=700,uid=1000,gid=1000,inode64 0 0 +// ``` +func (r *Resolver) GetMounts(ctx context.Context, pod *v1.Pod) ([]string, error) { + cmd := "cat /proc/mounts" + out, err := r.ExecBypass(ctx, pod, cmd, bpm.PidNS, bpm.MountNS) + if err != nil { + return nil, errors.Wrapf(err, "run command %s failed", cmd) + } + return strings.Split(string(out), "\n"), nil +} diff --git a/pkg/ctrl/server/net.go b/pkg/ctrl/server/net.go new file mode 100644 index 0000000000..397deac607 --- /dev/null +++ b/pkg/ctrl/server/net.go @@ -0,0 +1,80 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package server + +import ( + "context" + "strings" + + "github.com/pingcap/errors" + v1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/pkg/bpm" +) + +// GetIpset returns result of ipset list +func (r *Resolver) GetIpset(ctx context.Context, obj *v1.Pod) (string, error) { + cmd := "ipset list" + return r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.NetNS) +} + +// GetIpset returns result of tc qdisc list +func (r *Resolver) GetTcQdisc(ctx context.Context, obj *v1.Pod) ([]string, error) { + cmd := "tc qdisc list" + rules, err := r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.NetNS) + if err != nil { + return nil, errors.Wrapf(err, "exec `%s`", cmd) + } + return strings.Split(rules, "\n"), nil +} + +// GetIptables returns result of iptables --list +func (r *Resolver) GetIptables(ctx context.Context, obj *v1.Pod) ([]string, error) { + cmd := "iptables --list" + rules, err := r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.NetNS) + if err != nil { + return nil, errors.Wrapf(err, "exec `%s`", cmd) + } + return strings.Split(rules, "\n"), nil +} + +// cleanTcs returns actually cleaned devices +func (r *Resolver) cleanTcs(ctx context.Context, obj *v1.Pod, devices []string) ([]string, error) { + var cleaned []string + for _, device := range devices { + cmd := "tc qdisc del dev " + device + " root" + _, err := r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.NetNS) + if err != nil { + return cleaned, errors.Wrapf(err, "exec `%s`", cmd) + } + cleaned = append(cleaned, device) + } + return cleaned, nil +} + +// cleanIptables returns actually cleaned chains +func (r *Resolver) cleanIptables(ctx context.Context, obj *v1.Pod, chains []string) ([]string, error) { + var cleaned []string + for _, chain := range chains { + cmd := "iptables -F " + chain + _, err := r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.NetNS) + if err != nil { + return cleaned, errors.Wrapf(err, "exec `%s`", cmd) + } + cleaned = append(cleaned, chain) + } + return cleaned, nil +} diff --git a/pkg/ctrl/server/process.go b/pkg/ctrl/server/process.go new file mode 100644 index 0000000000..0ffa0ee267 --- /dev/null +++ b/pkg/ctrl/server/process.go @@ -0,0 +1,108 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package server + +import ( + "context" + "fmt" + "strings" + + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/pkg/bpm" + "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/model" +) + +// GetPidFromPS returns pid-command pairs +func (r *Resolver) GetPidFromPS(ctx context.Context, pod *v1.Pod) ([]*model.Process, error) { + cmd := "ps" + out, err := r.ExecBypass(ctx, pod, cmd, bpm.PidNS, bpm.MountNS) + if err != nil { + return nil, errors.Wrapf(err, "run command %s failed", cmd) + } + outLines := strings.Split(string(out), "\n") + if len(outLines) < 2 { + return nil, errors.New("ps returns empty") + } + titles := strings.Fields(outLines[0]) + var pidColumn, cmdColumn int + for i, t := range titles { + if t == "PID" { + pidColumn = i + } + if t == "COMMAND" || t == "CMD" { + cmdColumn = i + } + } + if pidColumn == 0 && cmdColumn == 0 { + return nil, errors.New("parsing ps error: could not get PID and COMMAND column") + } + + var processes []*model.Process + for _, line := range outLines[1:] { + item := strings.Fields(line) + // break when got empty line + if len(item) == 0 { + break + } + if item[cmdColumn] == cmd { + continue + } + processes = append(processes, &model.Process{ + Pod: pod, + Pid: item[pidColumn], + Command: item[cmdColumn], + }) + } + return processes, nil +} + +// killProcess kill all alive processes in pids +func (r *Resolver) killProcess(ctx context.Context, pod *v1.Pod, pids []string) ([]*model.KillProcessResult, error) { + pidSet := make(map[string]bool) + for _, pid := range pids { + pidSet[pid] = true + } + + // all processes in target pod + allProcess, err := r.GetPidFromPS(ctx, pod) + if err != nil { + return nil, errors.Wrapf(err, "get process on pod %s/%s", pod.Namespace, pod.Name) + } + + // the intersection of all processes and pids + var pidList []string + var killResults []*model.KillProcessResult + + for _, process := range allProcess { + if _, ok := pidSet[process.Pid]; ok { + pidList = append(pidList, process.Pid) + killResults = append(killResults, &model.KillProcessResult{ + Pid: process.Pid, + Command: process.Command, + }) + } + } + if len(pidList) == 0 { + return nil, nil + } + cmd := fmt.Sprintf("kill %s", strings.Join(pids, " ")) + if _, err = r.ExecBypass(ctx, pod, cmd, bpm.PidNS, bpm.MountNS); err != nil { + return nil, errors.Wrapf(err, "run command %s", cmd) + } + return killResults, nil +} diff --git a/pkg/ctrl/server/resolver.go b/pkg/ctrl/server/resolver.go new file mode 100644 index 0000000000..b40919b4af --- /dev/null +++ b/pkg/ctrl/server/resolver.go @@ -0,0 +1,36 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package server + +//go:generate gqlgen +// +// This file will not be regenerated automatically. +// +// It serves as dependency injection for your app, add any dependencies you require here. + +import ( + "github.com/go-logr/logr" + "k8s.io/client-go/kubernetes" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type Resolver struct { + *DaemonHelper + Log logr.Logger + Client client.Client + Clientset *kubernetes.Clientset + NoCacheReader client.Reader +} diff --git a/pkg/ctrl/server/schema.graphqls b/pkg/ctrl/server/schema.graphqls new file mode 100644 index 0000000000..0f1ac83a59 --- /dev/null +++ b/pkg/ctrl/server/schema.graphqls @@ -0,0 +1,1268 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +directive @goModel(model: String, models: [String!]) on OBJECT + | INPUT_OBJECT + | SCALAR + | ENUM + | INTERFACE + | UNION + +directive @goField(forceResolver: Boolean, name: String) on INPUT_FIELD_DEFINITION + | FIELD_DEFINITION + +scalar Time +scalar Map +scalar Int64 + +schema { + query: Query + mutation: Mutation + subscription: Logger +} + +type Query { + namespace(ns: String): [Namespace!] + pods(selector: PodSelectorInput!): [Pod!] +} + +type Mutation { + pod(ns: String! = "default", name: String!): MutablePod +} + +type Logger { + component(ns: String! = "chaos-mesh", component: Component!): String! @goField(forceResolver: true) + pod(ns: String! = "default", name: String!): String! @goField(forceResolver: true) +} + +type Namespace { + ns: String! + component(component: Component!): [Pod!] @goField(forceResolver: true) + pod(name: String): [Pod!] @goField(forceResolver: true) + stresschaos(name: String): [StressChaos!] @goField(forceResolver: true) + iochaos(name: String): [IOChaos!] @goField(forceResolver: true) + podiochaos(name: String): [PodIOChaos!] @goField(forceResolver: true) + httpchaos(name: String): [HTTPChaos!] @goField(forceResolver: true) + podhttpchaos(name: String): [PodHTTPChaos!] @goField(forceResolver: true) + networkchaos(name: String): [NetworkChaos!] @goField(forceResolver: true) + podnetworkchaos(name: String): [PodNetworkChaos!] @goField(forceResolver: true) +} + +type OwnerReference @goModel(model: "k8s.io/apimachinery/pkg/apis/meta/v1.OwnerReference") { + kind: String! + apiVersion: String! + name: String! + uid: String! + controller: Boolean + blockOwnerDeletion: Boolean +} + +enum Component { + MANAGER + DAEMON + DASHBOARD + DNSSERVER +} + +type Process { + pod: Pod! + pid: String! + command: String! + fds: [Fd!] @goField(forceResolver: true) +} + +type KillProcessResult { + pid: String! + command: String! +} + +type Fd { + fd: String! + target: String! +} + +# PodSelectorInput defines the some selectors to select objects. +# If the all selectors are empty, all objects will be used in chaos experiment. +input PodSelectorInput { + # namespaces is a set of namespace to which objects belong. + namespaces: [String!] + + # nodes is a set of node name and objects must belong to these nodes. + nodes: [String!] + + # pods is a map of string keys and a set values that used to select pods. + # The key defines the namespace which pods belong, + # and the each values is a set of pod names. + pods: Map + + # map of string keys and values that can be used to select nodes. + # Selector which must match a node's labels, + # and objects must belong to these selected nodes. + nodeSelectors: Map + + # map of string keys and values that can be used to select objects. + # A selector based on fields. + fieldSelectors: Map + + # map of string keys and values that can be used to select objects. + # A selector based on labels. + labelSelectors: Map + + # map of string keys and values that can be used to select objects. + # A selector based on annotations. + annotationSelectors: Map + + # podPhaseSelectors is a set of condition of a pod at the current time. + # supported value: Pending / Running / Succeeded / Failed / Unknown + podPhaseSelectors: [String!] +} + +type MutablePod { + pod: Pod! + killProcesses(pids: [String!]): [KillProcessResult!] @goField(forceResolver: true) + cleanTcs(devices: [String!]): [String!] @goField(forceResolver: true) + cleanIptables(chains: [String!]): [String!] @goField(forceResolver: true) +} + +type Pod @goModel(model: "k8s.io/api/core/v1.Pod") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + spec: PodSpec! + status: PodStatus! + + logs: String! @goField(forceResolver: true) + daemon: Pod @goField(forceResolver: true) + processes: [Process!] @goField(forceResolver: true) + mounts: [String!] @goField(forceResolver: true) + ipset: String! @goField(forceResolver: true) + tcQdisc: [String!] @goField(forceResolver: true) + iptables: [String!] @goField(forceResolver: true) +} + +# PodStatus represents information about the status of a pod. Status may trail the actual +# state of a system, especially if the node that hosts the pod cannot contact the control +# plane. +type PodStatus @goModel(model: "k8s.io/api/core/v1.PodStatus") { + # The phase of a Pod is a simple, high-level summary of where the Pod is in its lifecycle. + # The conditions array, the reason and message fields, and the individual container status + # arrays contain more detail about the pod's status. + # There are five possible phase values: + # + # Pending: The pod has been accepted by the Kubernetes system, but one or more of the + # container images has not been created. This includes time before being scheduled as + # well as time spent downloading images over the network, which could take a while. + # Running: The pod has been bound to a node, and all of the containers have been created. + # At least one container is still running, or is in the process of starting or restarting. + # Succeeded: All containers in the pod have terminated in success, and will not be restarted. + # Failed: All containers in the pod have terminated, and at least one container has + # terminated in failure. The container either exited with non-zero status or was terminated + # by the system. + # Unknown: For some reason the state of the pod could not be obtained, typically due to an + # error in communicating with the host of the pod. + # + # More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-phase + phase: String! + + # Current service state of pod. + # More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions + conditions: [PodCondition!] + + # A human readable message indicating details about why the pod is in this condition. + message: String! + + # A brief CamelCase message indicating details about why the pod is in this state. + # e.g. 'Evicted' + reason: String! + + # nominatedNodeName is set only when this pod preempts other pods on the node, but it cannot be + # scheduled right away as preemption victims receive their graceful termination periods. + # This field does not guarantee that the pod will be scheduled on this node. Scheduler may decide + # to place the pod elsewhere if other nodes become available sooner. Scheduler may also decide to + # give the resources on this node to a higher priority pod that is created after preemption. + # As a result, this field may be different than PodSpec.nodeName when the pod is + # scheduled. + nominatedNodeName: String! + + # IP address of the host to which the pod is assigned. Empty if not yet scheduled. + hostIP: String! + + # IP address allocated to the pod. Routable at least within the cluster. + # Empty if not yet allocated. + podIP: String! + + # podIPs holds the IP addresses allocated to the pod. If this field is specified, the 0th entry must + # match the podIP field. Pods may be allocated at most 1 value for each of IPv4 and IPv6. This list + # is empty if no IPs have been allocated yet. + podIPs: [PodIP!] + + # RFC 3339 date and time at which the object was acknowledged by the Kubelet. + # This is before the Kubelet pulled the container image(s) for the pod. + startTime: Time + + # The list has one entry per init container in the manifest. The most recent successful + # init container will have ready = true, the most recently started container will have + # startTime set. + # More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-and-container-status + initContainerStatuses: [ContainerStatus!] + + # The list has one entry per container in the manifest. Each entry is currently the output + # of `docker inspect`. + # More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-and-container-status + containerStatuses: [ContainerStatus!] + + # The Quality of Service (QOS) classification assigned to the pod based on resource requirements + # See PodQOSClass type for available QOS classes + # More info: https://git.k8s.io/community/contributors/design-proposals/node/resource-qos.md + qosClass: String! + + # Status for any ephemeral containers that have run in this pod. + # This field is alpha-level and is only populated by servers that enable the EphemeralContainers feature. + ephemeralContainerStatuses: [ContainerStatus!] +} + +# IP address information for entries in the (plural) PodIPs field. +# Each entry includes: +# IP: An IP address allocated to the pod. Routable at least within the cluster. +type PodIP @goModel(model: "k8s.io/api/core/v1.PodIP") { + # ip is an IP address (IPv4 or IPv6) assigned to the pod + ip: String! +} + +# PodCondition contains details for the current condition of this pod. +type PodCondition @goModel(model: "k8s.io/api/core/v1.PodCondition") { + # Type is the type of the condition. + # More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions + type: String! + + # Status is the status of the condition. + # Can be True, False, Unknown. + # More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions + status: String! + + # Last time we probed the condition. + lastProbeTime: Time + + # Last time the condition transitioned from one status to another. + lastTransitionTime: Time + + # Unique, one-word, CamelCase reason for the condition's last transition. + reason: String + + # Human-readable message indicating details about last transition. + message: String +} + +# ContainerStatus contains details for the current status of this container. +type ContainerStatus @goModel(model: "k8s.io/api/core/v1.ContainerStatus") { + # This must be a DNS_LABEL. Each container in a pod must have a unique name. + # Cannot be updated. + name: String! + + # Details about the container's current condition. + State: ContainerState + + # Details about the container's last termination condition. + lastTerminationState: ContainerState + + # Specifies whether the container has passed its readiness probe. + ready: Boolean! + + # The number of times the container has been restarted, currently based on + # the number of dead containers that have not yet been removed. + # Note that this is calculated from dead containers. But those containers are subject to + # garbage collection. This value will get capped at 5 by GC. + restartCount: Int! + + # The image the container is running. + # More info: https://kubernetes.io/docs/concepts/containers/images + # TODO(dchen1107): Which image the container is running with? + image: String! + + # ImageID of the container's image. + imageID: String! + + # Container's ID in the format 'docker://'. + containerID: String! + + # Specifies whether the container has passed its startup probe. + # Initialized as false, becomes true after startupProbe is considered successful. + # Resets to false when the container is restarted, or if kubelet loses state temporarily. + # Is always true when no startupProbe is defined. + started: Boolean +} + +# ContainerState holds a possible state of container. +# Only one of its members may be specified. +# If none of them is specified, the default one is ContainerStateWaiting. +type ContainerState @goModel(model: "k8s.io/api/core/v1.ContainerState") { + # Details about a waiting container + waiting: ContainerStateWaiting + + # Details about a running container + running: ContainerStateRunning + + # Details about a terminated container + terminated: ContainerStateTerminated +} + +# ContainerStateWaiting is a waiting state of a container. +type ContainerStateWaiting @goModel(model: "k8s.io/api/core/v1.ContainerStateWaiting") { + # (brief) reason the container is not yet running. + reason: String + + # Message regarding why the container is not yet running. + message: String +} + +# ContainerStateRunning is a running state of a container. +type ContainerStateRunning @goModel(model: "k8s.io/api/core/v1.ContainerStateRunning") { + # Time at which the container was last (re-)started + startedAt: Time +} + +# ContainerStateTerminated is a terminated state of a container. +type ContainerStateTerminated @goModel(model: "k8s.io/api/core/v1.ContainerStateTerminated") { + # Exit status from the last termination of the container + exitCode: Int! + + # Signal from the last termination of the container + signal: Int + + # (brief) reason from the last termination of the container + reason: String + + # Message regarding the last termination of the container + message: String + + #Time at which previous execution of the container started + startedAt: Time + + # Time at which the container last terminated + finishedAt: Time + + # Container's ID in the format 'docker://' + containerID: String +} + + +# TODO: add more fields +type PodSpec @goModel(model: "k8s.io/api/core/v1.PodSpec") { + # ndeName is a request to schedule this pod onto a specific node. If it is non-empty, + # the scheduler simply schedules this pod onto that node, assuming that it fits resource + # requirements. + nodeName: String! + +} + +type PodIOChaos @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodIOChaos") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + spec: PodIOChaosSpec! + status: PodIOChaosStatus! + + pod: Pod! @goField(forceResolver: true) + ios: [IOChaos!] @goField(forceResolver: true) +} + +# PodIOChaosSpec defines the desired state of PodIOChaos +type PodIOChaosSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodIOChaosSpec") { + # volumeMountPath represents the target mount path + # It must be a root of mount path now. + volumeMountPath: String! + + container: String + + # actions are a list of IOChaos actions + actions: [IOChaosAction!] +} + +type PodIOChaosStatus @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodIOChaosStatus") { + + # pid represents a running toda process id + pid: Int + + # startTime represents the start time of a toda process + startTime: Int + failedMessage: String + observedGeneration: Int +} + +# IOChaosAction defines an possible action of IOChaos +type IOChaosAction @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.IOChaosAction") { + type: String! + + # path represents a glob of injecting path + path: String! + + # methods represents the method that the action will inject in + methods: [String!] + + # percent represents the percent probability of injecting this action + percent: Int + + # faults represents the fault to inject + faults: [IoFault!] + + # Latency represents the latency to inject + latency: String + + # attrOverrides represents the attribution to override + ino: Int64 + size: Int64 + blocks: Int64 + atime: Timespec @goField(forceResolver: true) + mtime: Timespec @goField(forceResolver: true) + ctime: Timespec @goField(forceResolver: true) + kind: String # the file kind + perm: Int + nlink: Int64 + uid: Int64 + gid: Int64 + rdev: Int64 + + # MistakeSpec represents the mistake to inject + + # filling determines what is filled in the miskate data. + filling: String + + # there will be [1, MaxOccurrences] segments of wrong data. + maxOccurrences: Int64 @goField(forceResolver: true) + + # max length of each wrong data segment in bytes + maxLength: Int64 @goField(forceResolver: true) + + # source represents the source of current rules + source: String! +} + +type IoFault @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.IoFault") { + errno: Int! + weight: Int! +} + +# Timespec represents a time +type Timespec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.Timespec") { + sec: Int! + nsec: Int! +} + + +type IOChaos @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.IOChaos") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + spec: IOChaosSpec! + status: IOChaosStatus! + + podios: [PodIOChaos!] @goField(forceResolver: true) +} + +# IOChaosSpec defines the desired state of IOChaos +type IOChaosSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.IOChaosSpec") { + # containerNames indicates list of the name of affected container. + # If not set, the first container will be injected + containerNames: [String!] + + # selector is used to select pods that are used to inject chaos action. + selector: PodSelectorSpec! + + # mode defines the mode to run chaos action. + # supported mode: one / all / fixed / fixed-percent / random-max-percent + mode: String! + + # value is required when the mode is set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. + # If `FixedPodMode`, provide an integer of pods to do chaos action. + # If `FixedPercentPodMod`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + # IF `RandomMaxPercentPodMod`, provide a number from 0-100 to specify the max percent of pods to do chaos action + value: String + + + # action defines the specific pod chaos action. + # Supported action: latency / fault / attrOverride / mistake + action: String! + + # delay defines the value of I/O chaos action delay. + # A delay string is a possibly signed sequence of + # decimal numbers, each with optional fraction and a unit suffix, + # such as "300ms". + # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + delay: String + + # errno defines the error code that returned by I/O action. + # refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html + errno: Int + + # attr defines the overrided attribution + attr: AttrOverrideSpec + + # mistake defines what types of incorrectness are injected to IO operations + mistake: MistakeSpec + + # path defines the path of files for injecting I/O chaos action. + path: String + + # methods defines the I/O methods for injecting I/O chaos action. + # default: all I/O methods. + methods: [String!] + + # percent defines the percentage of injection errors and provides a number from 0-100. + # default: 100. + percent: Int + + # volumePath represents the mount path of injected volume + volumePath: String! + + # duration represents the duration of the chaos action. + # It is required when the action is `PodFailureAction`. + # 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". + duration: String +} + +# AttrOverrideSpec represents an override of attribution +type AttrOverrideSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.AttrOverrideSpec") { + ino: Int + size: Int + blocks: Int + atime: Timespec + mtime: Timespec + ctime: Timespec + kind: String # the file kind + perm: Int + nlink: Int + uid: Int + gid: Int + rdev: Int +} + +# MistakeSpec represents one type of mistake +type MistakeSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.MistakeSpec") { + # filling determines what is filled in the miskate data. + filling: String + + # there will be [1, MaxOccurrences] segments of wrong data. + maxOccurrences: Int + + # max length of each wrong data segment in bytes + maxLength: Int +} + +type IOChaosStatus @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.IOChaosStatus") { + # conditions represents the current global condition of the chaos + conditions: [ChaosCondition!] + + # experiment records the last experiment state. + experiment: ExperimentStatus + + # instances always specifies podhttpchaos generation or empty + instances: Map +} + +type PodHTTPChaos @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaos") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + spec: PodHttpChaosSpec! + status: PodHttpChaosStatus! + + pod: Pod! @goField(forceResolver: true) +} + +# PodHttpChaosSpec defines the desired state of PodHttpChaos. +type PodHttpChaosSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosSpec") { + # rules are a list of injection rule for http request. + rules: [PodHttpChaosRule!]! + + # tls is the tls config, + # will be override if there are multiple HTTPChaos experiments are applied + tls: PodHttpChaosTLS +} + +# PodHttpChaosStatus defines the actual state of PodHttpChaos. +type PodHttpChaosStatus @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosStatus") { + # pid represents a running tproxy process id. + pid: Int + + # startTime represents the start time of a tproxy process. + startTime: Int + + failedMessage: String + observedGeneration: Int +} + +# PodHttpChaosTLS contains the tls config for HTTPChaos +type PodHttpChaosTLS @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosTLS") { + # secretName represents the name of required secret resource + secretName: String! + + # secretNamespace represents the namespace of required secret resource, + # should be the same with deployment/chaos-controller-manager in most cases + secretNamespace: String! + + # certName represents the data name of cert file in secret, `tls.crt` for example + certName: String! + + # keyName represents the data name of key file in secret, `tls.key` for example + keyName: String! + + # caName represents the data name of ca file in secret, `ca.crt` for example + caName: String +} + +# PodHttpChaosRule defines the injection rule for http. +type PodHttpChaosRule @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosRule") { + # target is the object to be selected and injected, . + target: String! + + selector: PodHttpChaosSelector! + + actions: PodHttpChaosActions! + + # source represents the source of current rules + source: String! + + # port represents the target port to be proxy of. + port: Int! +} + +type PodHttpChaosSelector @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosSelector") { + # port represents the target port to be proxy of. + port: Int + + # path is a rule to select target by uri path in http request. + path: String + + # method is a rule to select target by http method in request. + method: String + + # code is a rule to select target by http status code in response. + code: Int + + # requestHeaders is a rule to select target by http headers in request. + # The key-value pairs represent header name and header value pairs. + requestHeaders: Map + + # responseHeaders is a rule to select target by http headers in response. + # The key-value pairs represent header name and header value pairs. + responseHeaders: Map +} + +# PodHttpChaosAction defines possible actions of HttpChaos. +type PodHttpChaosActions @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosActions") { + # abort is a rule to abort a http session. + abort: Boolean + + # delay represents the delay of the target request/response. + # A duration string is a possibly unsigned sequence of + # decimal numbers, each with optional fraction and a unit suffix, + # such as "300ms", "2h45m". + # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + delay: String + + # replace is a rule to replace some contents in target. + replace: PodHttpChaosReplaceActions + + # patch is a rule to patch some contents in target. + patch: PodHttpChaosPatchActions +} + +type HTTPChaos @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.HTTPChaos") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + spec: HTTPChaosSpec! + status: HTTPChaosStatus! + + podhttp: [PodHTTPChaos!] @goField(forceResolver: true) +} + +type HTTPChaosSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.HTTPChaosSpec") { + # selector is used to select pods that are used to inject chaos action. + selector: PodSelectorSpec! + + # mode defines the mode to run chaos action. + # supported mode: one / all / fixed / fixed-percent / random-max-percent + mode: String! + + # value is required when the mode is set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. + # If `FixedPodMode`, provide an integer of pods to do chaos action. + # If `FixedPercentPodMod`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + # IF `RandomMaxPercentPodMod`, provide a number from 0-100 to specify the max percent of pods to do chaos action + value: String + + # target is the object to be selected and injected. + target: String! + + # abort is a rule to abort a http session. + abort: Boolean + + # delay represents the delay of the target request/response. + # A duration string is a possibly unsigned sequence of + # decimal numbers, each with optional fraction and a unit suffix, + # such as "300ms", "2h45m". + # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + delay: String + + # replace is a rule to replace some contents in target. + replace: PodHttpChaosReplaceActions + + # patch is a rule to patch some contents in target. + patch: PodHttpChaosPatchActions + + # port represents the target port to be proxy of. + port: Int + + # path is a rule to select target by uri path in http request. + path: String + + # method is a rule to select target by http method in request. + method: String + + # code is a rule to select target by http status code in response. + code: Int + + # requestHeaders is a rule to select target by http headers in request. + # The key-value pairs represent header name and header value pairs. + requestHeaders: Map + + # responseHeaders is a rule to select target by http headers in response. + # The key-value pairs represent header name and header value pairs. + responseHeaders: Map + + # duration represents the duration of the chaos action. + duration: String +} + +# PodSelectorSpec defines the some selectors to select objects. +# If the all selectors are empty, all objects will be used in chaos experiment. +type PodSelectorSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodSelectorSpec") { + # namespaces is a set of namespace to which objects belong. + namespaces: [String!] + + # nodes is a set of node name and objects must belong to these nodes. + nodes: [String!] + + # pods is a map of string keys and a set values that used to select pods. + # The key defines the namespace which pods belong, + # and the each values is a set of pod names. + pods: Map + + # map of string keys and values that can be used to select nodes. + # Selector which must match a node's labels, + # and objects must belong to these selected nodes. + nodeSelectors: Map + + # map of string keys and values that can be used to select objects. + # A selector based on fields. + fieldSelectors: Map + + # map of string keys and values that can be used to select objects. + # A selector based on labels. + labelSelectors: Map + + # map of string keys and values that can be used to select objects. + # A selector based on annotations. + annotationSelectors: Map + + # podPhaseSelectors is a set of condition of a pod at the current time. + # supported value: Pending / Running / Succeeded / Failed / Unknown + podPhaseSelectors: [String!] +} + +type PodHttpChaosReplaceActions @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosReplaceActions") { + # path is rule to to replace uri path in http request. + path: String + + # method is a rule to replace http method in request. + method: String + + # code is a rule to replace http status code in response. + code: Int + + # body is a rule to replace http message body in target. + body: String + + # queries is a rule to replace uri queries in http request. + # For example, with value `{ "foo": "unknown" }`, the `/?foo=bar` will be altered to `/?foo=unknown`, + queries: Map + + # headers is a rule to replace http headers of target. + # The key-value pairs represent header name and header value pairs. + headers: Map +} + +# PodHttpChaosPatchActions defines possible patch-actions of HttpChaos. +type PodHttpChaosPatchActions @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosPatchActions") { + # body is a rule to patch message body of target. + body: PodHttpChaosPatchBodyAction + + # queries is a rule to append uri queries of target(Request only). + # For example: `[["foo", "bar"], ["foo", "unknown"]]`. + queries: [[String!]!] + + # headers is a rule to append http headers of target. + # For example: `[["Set-Cookie", ""], ["Set-Cookie", ""]]`. + headers: [[String!]!] +} + +# PodHttpChaosPatchBodyAction defines patch body action of HttpChaos. +type PodHttpChaosPatchBodyAction @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodHttpChaosPatchBodyAction") { + # type represents the patch type, only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) currently. + type: String! + + # value is the patch contents. + value: String! +} + +type HTTPChaosStatus @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.HTTPChaosStatus") { + # conditions represents the current global condition of the chaos + conditions: [ChaosCondition!] + + # experiment records the last experiment state. + experiment: ExperimentStatus + + # instances always specifies podhttpchaos generation or empty + instances: Map +} + +type ChaosCondition @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.ChaosCondition") { + type: String! + status: String! + reason: String +} + +type ExperimentStatus @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.ExperimentStatus") { + desiredPhase: String! + + # Records are used to track the running status + Records: [Record!] +} + +type Record @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.Record") { + id: String! + selectorKey: String! + phase: String! +} + +type PodNetworkChaos @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodNetworkChaos") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + spec: PodNetworkChaosSpec! + status: PodNetworkChaosStatus! + + pod: Pod! @goField(forceResolver: true) +} + +# PodNetworkChaosSpec defines the desired state of PodNetworkChaos +type PodNetworkChaosSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodNetworkChaosSpec") { + # The ipset on the pod + ipSets: [RawIPSet!] + + # The iptables rules on the pod + iptables: [RawIptables!] + + # The tc rules on the pod + trafficControls: [RawTrafficControl!] +} + +# PodNetworkChaosStatus defines the observed state of PodNetworkChaos +type PodNetworkChaosStatus @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.PodNetworkChaosStatus") { + failedMessage: String! + observedGeneration: Int! +} + +# RawIPSet represents an ipset on specific pod +type RawIPSet @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.RawIPSet") { + # The name of ipset + name: String! + + ipSetType: String! + + # The contents of ipset + cidrs: [String!]! + + # The contents of ipset. + # Only available when IPSetType is NetPortIPSet. + cidrAndPorts: [CidrAndPort!] + + # The contents of ipset. + # Only available when IPSetType is SetIPSet. + setNames: [String!]! + + # The name and namespace of the source network chaos + source: String! +} + +type CidrAndPort @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.CidrAndPort") { + cidr: String! + port: Int! +} + +# RawIptables represents the iptables rules on specific pod +type RawIptables @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.RawIptables") { + # The name of iptables chain + name: String! + + # The name of related ipset + ipSets: [String!]! + + # The block direction of this iptables rule + direction: String! + + # The name and namespace of the source network chaos + source: String! + + # Device represents the network device to be affected. + device: String +} + +# RawTrafficControl represents the traffic control chaos on specific pod +type RawTrafficControl @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.RawTrafficControl") { + # The type of traffic control + type: String! + + # delay represents the detail about delay action + delay: DelaySpec + + # loss represents the detail about loss action + loss: LossSpec + + # duplicateSpec represents the detail about loss action + duplicate: DuplicateSpec + + # corrupt represents the detail about corrupt action + corrupt: CorruptSpec + + # bandwidth represents the detail about bandwidth control action + bandwidth: BandwidthSpec + + # Rate represents the detail about rate control action + rate: RateSpec + + # The name of target ipset + ipSet: String + + # The name and namespace of the source network chaos + source: String + + # Device represents the network device to be affected. + device: String +} + +# DelaySpec defines detail of a delay action +type DelaySpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.DelaySpec") { + latency: String! + correlation: String + jitter: String + reorder: ReorderSpec +} + +# LossSpec defines detail of a loss action +type LossSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.LossSpec") { + loss: String! + correlation: String +} + +# DuplicateSpec defines detail of a duplicate action +type DuplicateSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.DuplicateSpec") { + duplicate: String! + correlation: String +} + +# CorruptSpec defines detail of a corrupt action +type CorruptSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.CorruptSpec") { + corrupt: String! + correlation: String +} + +# BandwidthSpec defines detail of bandwidth limit. +type BandwidthSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.BandwidthSpec") { + # rate is the speed knob. Allows bps, kbps, mbps, gbps, tbps unit. bps means bytes per second. + rate: String! + + # limit is the number of bytes that can be queued waiting for tokens to become available. + limit: Int! + + # buffer is the maximum amount of bytes that tokens can be available for instantaneously. + buffer: Int! + + # peakrate is the maximum depletion rate of the bucket. + # The peakrate does not need to be set, it is only necessary + # if perfect millisecond timescale shaping is required. + peakrate: Int + + # minburst specifies the size of the peakrate bucket. For perfect + # accuracy, should be set to the MTU of the interface. If a + # peakrate is needed, but some burstiness is acceptable, this + # size can be raised. A 3000 byte minburst allows around 3mbit/s + # of peakrate, given 1000 byte packets. + minburst: Int +} + +type RateSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.RateSpec"){ + # Rate is the speed knob. Allows bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means bytes per second. + rate: String! +} + +# ReorderSpec defines details of packet reorder. +type ReorderSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.ReorderSpec") { + reorder: String! + correlation: String + gap: Int +} + +type NetworkChaos @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.NetworkChaos") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + podnetwork: [PodNetworkChaos!] @goField(forceResolver: true) +} + +type MemoryStressor @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.MemoryStressor") { + # Workers specifies N workers to apply the stressor. + # Maximum 8192 workers can run by stress-ng + workers: Int! + + # Size specifies N bytes consumed per vm worker, default is the total available memory. + # One can specify the size as % of total available memory or in units of B, KB/KiB, + # MB/MiB, GB/GiB, TB/TiB. + size: String + + # extend stress-ng options + options: [String!] +} + +type CPUStressor @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.CPUStressor") { + # Workers specifies N workers to apply the stressor. + # Maximum 8192 workers can run by stress-ng + workers: Int! + + # Load specifies P percent loading per CPU worker. 0 is effectively a sleep (no load) and 100 + # is full loading. + load: Int + + # extend stress-ng options + options: [String!] +} + +type Stressors @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.Stressors") { + memoryStressor: MemoryStressor + cpuStressor: CPUStressor +} + +# StressChaosSpec defines the desired state of StressChaos +type StressChaosSpec @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.StressChaosSpec") { + # containerNames indicates list of the name of affected container. + # If not set, all containers will be injected + containerNames: [String!] + + # selector is used to select pods that are used to inject chaos action. + selector: PodSelectorSpec! + + # mode defines the mode to run chaos action. + # supported mode: one / all / fixed / fixed-percent / random-max-percent + mode: String! + + # value is required when the mode is set to `FixedPodMode` / `FixedPercentPodMod` / `RandomMaxPercentPodMod`. + # If `FixedPodMode`, provide an integer of pods to do chaos action. + # If `FixedPercentPodMod`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + # IF `RandomMaxPercentPodMod`, provide a number from 0-100 to specify the max percent of pods to do chaos action + value: String + + stressors: Stressors + + + # StressngStressors defines plenty of stressors just like `Stressors` except that it's an experimental + # feature and more powerful. You can define stressors in `stress-ng` (see also `man stress-ng`) dialect, + # however not all of the supported stressors are well tested. It maybe retired in later releases. You + # should always use `Stressors` to define the stressors and use this only when you want more stressors + # unsupported by `Stressors`. When both `StressngStressors` and `Stressors` are defined, `StressngStressors` + # wins. + stressngStressors: String + + # duration represents the duration of the chaos action. + # It is required when the action is `PodFailureAction`. + # 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". + duration: String +} + +type StressChaosStatus @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.StressChaosStatus") { + # conditions represents the current global condition of the chaos + conditions: [ChaosCondition!] + + # experiment records the last experiment state. + experiment: ExperimentStatus + + # instances always specifies stressing instances + instances: Map +} + +type StressChaos @goModel(model: "github.com/chaos-mesh/chaos-mesh/api/v1alpha1.StressChaos") { + kind: String! + apiVersion: String! + name: String! + generateName: String! + namespace: String! + selfLink: String! + uid: String! + resourceVersion: String! + generation: Int! + creationTimestamp: Time! + deletionTimestamp: Time + deletionGracePeriodSeconds: Int + labels: Map + annotations: Map + ownerReferences: [OwnerReference!] + finalizers: [String!] + + spec: StressChaosSpec! + + podstress: [PodStressChaos!] @goField(forceResolver: true) +} + +# PodStressChaos is a virtual type to describe relationship between pod and stress chaos +type PodStressChaos { + stressChaos: StressChaos! + + pod: Pod! + cgroups: Cgroups! @goField(forceResolver: true) + processStress: [ProcessStress!] @goField(forceResolver: true) +} + +type Cgroups { + raw: String! + cpu: CgroupsCpu + memory: CgroupsMemory +} + +type CgroupsCpu { + quota: Int! + period: Int! +} + +type CgroupsMemory { + limit: Int64! +} + +type ProcessStress { + process: Process! + cgroup: String! +} diff --git a/pkg/ctrl/server/schema.resolvers.go b/pkg/ctrl/server/schema.resolvers.go new file mode 100644 index 0000000000..3bd2f6d4ef --- /dev/null +++ b/pkg/ctrl/server/schema.resolvers.go @@ -0,0 +1,1431 @@ +package server + +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. + +import ( + "bufio" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "time" + + v1 "k8s.io/api/core/v1" + v11 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/generated" + "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/model" + podSelector "github.com/chaos-mesh/chaos-mesh/pkg/selector/pod" +) + +func (r *attrOverrideSpecResolver) Ino(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) { + if obj.Ino == nil { + return nil, nil + } + ino := (int)(*obj.Ino) + return &ino, nil +} + +func (r *attrOverrideSpecResolver) Size(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) { + if obj.Size == nil { + return nil, nil + } + size := (int)(*obj.Size) + return &size, nil +} + +func (r *attrOverrideSpecResolver) Blocks(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) { + if obj.Blocks == nil { + return nil, nil + } + blocks := (int)(*obj.Blocks) + return &blocks, nil +} + +func (r *attrOverrideSpecResolver) Kind(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*string, error) { + if obj.Kind == nil { + return nil, nil + } + kind := (string)(*obj.Kind) + return &kind, nil +} + +func (r *attrOverrideSpecResolver) Perm(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) { + if obj.Perm == nil { + return nil, nil + } + perm := (int)(*obj.Perm) + return &perm, nil +} + +func (r *attrOverrideSpecResolver) Nlink(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) { + if obj.Nlink == nil { + return nil, nil + } + nlink := (int)(*obj.Nlink) + return &nlink, nil +} + +func (r *attrOverrideSpecResolver) UID(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) { + if obj.UID == nil { + return nil, nil + } + uid := (int)(*obj.UID) + return &uid, nil +} + +func (r *attrOverrideSpecResolver) Gid(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) { + if obj.GID == nil { + return nil, nil + } + gid := (int)(*obj.GID) + return &gid, nil +} + +func (r *attrOverrideSpecResolver) Rdev(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) { + if obj.Rdev == nil { + return nil, nil + } + rdev := (int)(*obj.Rdev) + return &rdev, nil +} + +func (r *bandwidthSpecResolver) Limit(ctx context.Context, obj *v1alpha1.BandwidthSpec) (int, error) { + return int(obj.Limit), nil +} + +func (r *bandwidthSpecResolver) Buffer(ctx context.Context, obj *v1alpha1.BandwidthSpec) (int, error) { + return int(obj.Buffer), nil +} + +func (r *bandwidthSpecResolver) Peakrate(ctx context.Context, obj *v1alpha1.BandwidthSpec) (*int, error) { + if obj.Peakrate == nil { + return nil, nil + } + value := int(*obj.Peakrate) + return &value, nil +} + +func (r *bandwidthSpecResolver) Minburst(ctx context.Context, obj *v1alpha1.BandwidthSpec) (*int, error) { + if obj.Minburst == nil { + return nil, nil + } + value := int(*obj.Minburst) + return &value, nil +} + +func (r *chaosConditionResolver) Type(ctx context.Context, obj *v1alpha1.ChaosCondition) (string, error) { + return string(obj.Type), nil +} + +func (r *chaosConditionResolver) Status(ctx context.Context, obj *v1alpha1.ChaosCondition) (string, error) { + return string(obj.Status), nil +} + +func (r *cidrAndPortResolver) Port(ctx context.Context, obj *v1alpha1.CidrAndPort) (int, error) { + return int(obj.Port), nil +} + +func (r *containerStateRunningResolver) StartedAt(ctx context.Context, obj *v1.ContainerStateRunning) (*time.Time, error) { + return &obj.StartedAt.Time, nil +} + +func (r *containerStateTerminatedResolver) StartedAt(ctx context.Context, obj *v1.ContainerStateTerminated) (*time.Time, error) { + return &obj.StartedAt.Time, nil +} + +func (r *containerStateTerminatedResolver) FinishedAt(ctx context.Context, obj *v1.ContainerStateTerminated) (*time.Time, error) { + return &obj.FinishedAt.Time, nil +} + +func (r *experimentStatusResolver) DesiredPhase(ctx context.Context, obj *v1alpha1.ExperimentStatus) (string, error) { + return string(obj.DesiredPhase), nil +} + +func (r *hTTPChaosResolver) UID(ctx context.Context, obj *v1alpha1.HTTPChaos) (string, error) { + return string(obj.UID), nil +} + +func (r *hTTPChaosResolver) CreationTimestamp(ctx context.Context, obj *v1alpha1.HTTPChaos) (*time.Time, error) { + return &obj.CreationTimestamp.Time, nil +} + +func (r *hTTPChaosResolver) DeletionTimestamp(ctx context.Context, obj *v1alpha1.HTTPChaos) (*time.Time, error) { + return &obj.DeletionTimestamp.Time, nil +} + +func (r *hTTPChaosResolver) Labels(ctx context.Context, obj *v1alpha1.HTTPChaos) (map[string]interface{}, error) { + labels := make(map[string]interface{}) + for k, v := range obj.Labels { + labels[k] = v + } + return labels, nil +} + +func (r *hTTPChaosResolver) Annotations(ctx context.Context, obj *v1alpha1.HTTPChaos) (map[string]interface{}, error) { + annotations := make(map[string]interface{}) + for k, v := range obj.Annotations { + annotations[k] = v + } + return annotations, nil +} + +func (r *hTTPChaosResolver) Podhttp(ctx context.Context, obj *v1alpha1.HTTPChaos) ([]*v1alpha1.PodHttpChaos, error) { + podhttps := make([]*v1alpha1.PodHttpChaos, 0, len(obj.Status.Instances)) + for id := range obj.Status.Instances { + podhttp := new(v1alpha1.PodHttpChaos) + if err := r.Client.Get(ctx, parseNamespacedName(id), podhttp); err != nil { + return nil, err + } + podhttps = append(podhttps, podhttp) + } + return podhttps, nil +} + +func (r *hTTPChaosSpecResolver) Mode(ctx context.Context, obj *v1alpha1.HTTPChaosSpec) (string, error) { + return string(obj.Mode), nil +} + +func (r *hTTPChaosSpecResolver) Target(ctx context.Context, obj *v1alpha1.HTTPChaosSpec) (string, error) { + return string(obj.Target), nil +} + +func (r *hTTPChaosSpecResolver) RequestHeaders(ctx context.Context, obj *v1alpha1.HTTPChaosSpec) (map[string]interface{}, error) { + headers := make(map[string]interface{}) + for k, v := range obj.RequestHeaders { + headers[k] = v + } + return headers, nil +} + +func (r *hTTPChaosSpecResolver) ResponseHeaders(ctx context.Context, obj *v1alpha1.HTTPChaosSpec) (map[string]interface{}, error) { + headers := make(map[string]interface{}) + for k, v := range obj.ResponseHeaders { + headers[k] = v + } + return headers, nil +} + +func (r *hTTPChaosStatusResolver) Instances(ctx context.Context, obj *v1alpha1.HTTPChaosStatus) (map[string]interface{}, error) { + instances := make(map[string]interface{}) + for k, v := range obj.Instances { + instances[k] = v + } + return instances, nil +} + +func (r *iOChaosResolver) UID(ctx context.Context, obj *v1alpha1.IOChaos) (string, error) { + return string(obj.UID), nil +} + +func (r *iOChaosResolver) CreationTimestamp(ctx context.Context, obj *v1alpha1.IOChaos) (*time.Time, error) { + return &obj.CreationTimestamp.Time, nil +} + +func (r *iOChaosResolver) DeletionTimestamp(ctx context.Context, obj *v1alpha1.IOChaos) (*time.Time, error) { + return &obj.DeletionTimestamp.Time, nil +} + +func (r *iOChaosResolver) Labels(ctx context.Context, obj *v1alpha1.IOChaos) (map[string]interface{}, error) { + labels := make(map[string]interface{}) + for k, v := range obj.Labels { + labels[k] = v + } + return labels, nil +} + +func (r *iOChaosResolver) Annotations(ctx context.Context, obj *v1alpha1.IOChaos) (map[string]interface{}, error) { + annotations := make(map[string]interface{}) + for k, v := range obj.Annotations { + annotations[k] = v + } + return annotations, nil +} + +func (r *iOChaosResolver) Podios(ctx context.Context, obj *v1alpha1.IOChaos) ([]*v1alpha1.PodIOChaos, error) { + podios := make([]*v1alpha1.PodIOChaos, 0, len(obj.Status.Instances)) + for id := range obj.Status.Instances { + podio := new(v1alpha1.PodIOChaos) + if err := r.Client.Get(ctx, parseNamespacedName(id), podio); err != nil { + return nil, err + } + podios = append(podios, podio) + } + return podios, nil +} + +func (r *iOChaosActionResolver) Type(ctx context.Context, obj *v1alpha1.IOChaosAction) (string, error) { + return string(obj.Type), nil +} + +func (r *iOChaosActionResolver) Methods(ctx context.Context, obj *v1alpha1.IOChaosAction) ([]string, error) { + methods := make([]string, 0, len(obj.Methods)) + for k, v := range obj.Methods { + methods[k] = string(v) + } + return methods, nil +} + +func (r *iOChaosActionResolver) Ino(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) { + if obj.AttrOverrideSpec == nil || obj.Ino == nil { + return nil, nil + } + ino := (int64)(*obj.Ino) + return &ino, nil +} + +func (r *iOChaosActionResolver) Size(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) { + if obj.AttrOverrideSpec == nil || obj.Size == nil { + return nil, nil + } + size := (int64)(*obj.Size) + return &size, nil +} + +func (r *iOChaosActionResolver) Blocks(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) { + if obj.AttrOverrideSpec == nil || obj.Blocks == nil { + return nil, nil + } + blocks := (int64)(*obj.Blocks) + return &blocks, nil +} + +func (r *iOChaosActionResolver) Atime(ctx context.Context, obj *v1alpha1.IOChaosAction) (*v1alpha1.Timespec, error) { + if obj.AttrOverrideSpec == nil { + return nil, nil + } + return obj.Atime, nil +} + +func (r *iOChaosActionResolver) Mtime(ctx context.Context, obj *v1alpha1.IOChaosAction) (*v1alpha1.Timespec, error) { + if obj.AttrOverrideSpec == nil { + return nil, nil + } + return obj.Mtime, nil +} + +func (r *iOChaosActionResolver) Ctime(ctx context.Context, obj *v1alpha1.IOChaosAction) (*v1alpha1.Timespec, error) { + if obj.AttrOverrideSpec == nil { + return nil, nil + } + return obj.Ctime, nil +} + +func (r *iOChaosActionResolver) Kind(ctx context.Context, obj *v1alpha1.IOChaosAction) (*string, error) { + if obj.AttrOverrideSpec == nil || obj.Kind == nil { + return nil, nil + } + kind := (string)(*obj.Kind) + return &kind, nil +} + +func (r *iOChaosActionResolver) Perm(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int, error) { + if obj.AttrOverrideSpec == nil || obj.Perm == nil { + return nil, nil + } + perm := (int)(*obj.Perm) + return &perm, nil +} + +func (r *iOChaosActionResolver) Nlink(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) { + if obj.AttrOverrideSpec == nil || obj.Nlink == nil { + return nil, nil + } + nlink := (int64)(*obj.Nlink) + return &nlink, nil +} + +func (r *iOChaosActionResolver) UID(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) { + if obj.AttrOverrideSpec == nil || obj.UID == nil { + return nil, nil + } + uid := (int64)(*obj.UID) + return &uid, nil +} + +func (r *iOChaosActionResolver) Gid(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) { + if obj.AttrOverrideSpec == nil || obj.GID == nil { + return nil, nil + } + gid := (int64)(*obj.GID) + return &gid, nil +} + +func (r *iOChaosActionResolver) Rdev(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) { + if obj.AttrOverrideSpec == nil || obj.Rdev == nil { + return nil, nil + } + rdev := (int64)(*obj.Rdev) + return &rdev, nil +} + +func (r *iOChaosActionResolver) Filling(ctx context.Context, obj *v1alpha1.IOChaosAction) (*string, error) { + if obj.MistakeSpec == nil { + return nil, nil + } + filling := string(obj.Filling) + return &filling, nil +} + +func (r *iOChaosActionResolver) MaxOccurrences(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) { + if obj.MistakeSpec == nil { + return nil, nil + } + return &obj.MaxOccurrences, nil +} + +func (r *iOChaosActionResolver) MaxLength(ctx context.Context, obj *v1alpha1.IOChaosAction) (*int64, error) { + if obj.MistakeSpec == nil { + return nil, nil + } + return &obj.MaxLength, nil +} + +func (r *iOChaosSpecResolver) Mode(ctx context.Context, obj *v1alpha1.IOChaosSpec) (string, error) { + return string(obj.Mode), nil +} + +func (r *iOChaosSpecResolver) Action(ctx context.Context, obj *v1alpha1.IOChaosSpec) (string, error) { + return string(obj.Action), nil +} + +func (r *iOChaosSpecResolver) Errno(ctx context.Context, obj *v1alpha1.IOChaosSpec) (*int, error) { + errno := int(obj.Errno) + return &errno, nil +} + +func (r *iOChaosSpecResolver) Methods(ctx context.Context, obj *v1alpha1.IOChaosSpec) ([]string, error) { + methods := make([]string, 0, len(obj.Methods)) + for _, method := range obj.Methods { + methods = append(methods, string(method)) + } + return methods, nil +} + +func (r *iOChaosStatusResolver) Instances(ctx context.Context, obj *v1alpha1.IOChaosStatus) (map[string]interface{}, error) { + instances := make(map[string]interface{}) + for k, v := range obj.Instances { + instances[k] = v + } + return instances, nil +} + +func (r *ioFaultResolver) Errno(ctx context.Context, obj *v1alpha1.IoFault) (int, error) { + return int(obj.Errno), nil +} + +func (r *loggerResolver) Component(ctx context.Context, ns string, component model.Component) (<-chan string, error) { + var list v1.PodList + if err := r.Client.List(ctx, &list, client.MatchingLabels(componentLabels(component)), client.InNamespace(ns)); err != nil { + return nil, err + } + + if len(list.Items) == 0 { + return nil, fmt.Errorf("instance of %s not found", component) + } + + return r.Pod(ctx, list.Items[0].Namespace, list.Items[0].Name) +} + +func (r *loggerResolver) Pod(ctx context.Context, ns string, name string) (<-chan string, error) { + logs, err := r.Clientset.CoreV1().Pods(ns).GetLogs(name, &v1.PodLogOptions{Follow: true}).Stream(ctx) + if err != nil { + return nil, err + } + logChan := make(chan string) + go func() { + defer logs.Close() + reader := bufio.NewReader(logs) + for { + line, err := reader.ReadString('\n') + if err != nil { + r.Log.Error(err, fmt.Sprintf("fail to read log of pod(%s/%s)", ns, name)) + break + } + select { + case logChan <- string(line): + continue + case <-time.NewTimer(time.Minute).C: + r.Log.Info(fmt.Sprintf("client has not read log of pod(%s/%s) for 1m, close channel", ns, name)) + return + } + } + }() + return logChan, nil +} + +func (r *mistakeSpecResolver) Filling(ctx context.Context, obj *v1alpha1.MistakeSpec) (*string, error) { + filling := string(obj.Filling) + return &filling, nil +} + +func (r *mutablePodResolver) KillProcesses(ctx context.Context, obj *model.MutablePod, pids []string) ([]*model.KillProcessResult, error) { + return r.Resolver.killProcess(ctx, obj.Pod, pids) +} + +func (r *mutablePodResolver) CleanTcs(ctx context.Context, obj *model.MutablePod, devices []string) ([]string, error) { + return r.Resolver.cleanTcs(ctx, obj.Pod, devices) +} + +func (r *mutablePodResolver) CleanIptables(ctx context.Context, obj *model.MutablePod, chains []string) ([]string, error) { + return r.Resolver.cleanIptables(ctx, obj.Pod, chains) +} + +func (r *mutationResolver) Pod(ctx context.Context, ns string, name string) (*model.MutablePod, error) { + key := types.NamespacedName{Namespace: ns, Name: name} + pod := new(v1.Pod) + if err := r.Client.Get(ctx, key, pod); err != nil { + return nil, err + } + return &model.MutablePod{Pod: pod}, nil +} + +func (r *namespaceResolver) Component(ctx context.Context, obj *model.Namespace, component model.Component) ([]*v1.Pod, error) { + var list v1.PodList + var pods []*v1.Pod + if err := r.Client.List(ctx, &list, client.MatchingLabels(componentLabels(component)), client.InNamespace(obj.Ns)); err != nil { + return nil, err + } + for i := range list.Items { + pods = append(pods, &list.Items[i]) + } + return pods, nil +} + +func (r *namespaceResolver) Pod(ctx context.Context, obj *model.Namespace, name *string) ([]*v1.Pod, error) { + if name == nil { + var podList v1.PodList + var pods []*v1.Pod + if err := r.Client.List(ctx, &podList, &client.ListOptions{Namespace: obj.Ns}); err != nil { + return nil, err + } + + for i := range podList.Items { + pods = append(pods, &podList.Items[i]) + } + + return pods, nil + } + + key := types.NamespacedName{Namespace: obj.Ns, Name: *name} + pod := new(v1.Pod) + if err := r.Client.Get(ctx, key, pod); err != nil { + return nil, err + } + return []*v1.Pod{pod}, nil +} + +func (r *namespaceResolver) Stresschaos(ctx context.Context, obj *model.Namespace, name *string) ([]*v1alpha1.StressChaos, error) { + if name == nil { + var stressList v1alpha1.StressChaosList + var stresses []*v1alpha1.StressChaos + if err := r.Client.List(ctx, &stressList, &client.ListOptions{Namespace: obj.Ns}); err != nil { + return nil, err + } + + for i := range stressList.Items { + stresses = append(stresses, &stressList.Items[i]) + } + + return stresses, nil + } + + key := types.NamespacedName{Namespace: obj.Ns, Name: *name} + stress := new(v1alpha1.StressChaos) + if err := r.Client.Get(ctx, key, stress); err != nil { + return nil, err + } + return []*v1alpha1.StressChaos{stress}, nil +} + +func (r *namespaceResolver) Iochaos(ctx context.Context, obj *model.Namespace, name *string) ([]*v1alpha1.IOChaos, error) { + if name == nil { + var ioList v1alpha1.IOChaosList + var ios []*v1alpha1.IOChaos + if err := r.Client.List(ctx, &ioList, &client.ListOptions{Namespace: obj.Ns}); err != nil { + return nil, err + } + + for i := range ioList.Items { + ios = append(ios, &ioList.Items[i]) + } + + return ios, nil + } + + key := types.NamespacedName{Namespace: obj.Ns, Name: *name} + io := new(v1alpha1.IOChaos) + if err := r.Client.Get(ctx, key, io); err != nil { + return nil, err + } + return []*v1alpha1.IOChaos{io}, nil +} + +func (r *namespaceResolver) Podiochaos(ctx context.Context, obj *model.Namespace, name *string) ([]*v1alpha1.PodIOChaos, error) { + if name == nil { + var ioList v1alpha1.PodIOChaosList + var ios []*v1alpha1.PodIOChaos + if err := r.Client.List(ctx, &ioList, &client.ListOptions{Namespace: obj.Ns}); err != nil { + return nil, err + } + + for i := range ioList.Items { + ios = append(ios, &ioList.Items[i]) + } + + return ios, nil + } + + key := types.NamespacedName{Namespace: obj.Ns, Name: *name} + io := new(v1alpha1.PodIOChaos) + if err := r.Client.Get(ctx, key, io); err != nil { + return nil, err + } + + return []*v1alpha1.PodIOChaos{io}, nil +} + +func (r *namespaceResolver) Httpchaos(ctx context.Context, obj *model.Namespace, name *string) ([]*v1alpha1.HTTPChaos, error) { + if name == nil { + var httpList v1alpha1.HTTPChaosList + var https []*v1alpha1.HTTPChaos + if err := r.Client.List(ctx, &httpList, &client.ListOptions{Namespace: obj.Ns}); err != nil { + return nil, err + } + + for i := range httpList.Items { + https = append(https, &httpList.Items[i]) + } + + return https, nil + } + + key := types.NamespacedName{Namespace: obj.Ns, Name: *name} + http := new(v1alpha1.HTTPChaos) + if err := r.Client.Get(ctx, key, http); err != nil { + return nil, err + } + return []*v1alpha1.HTTPChaos{http}, nil +} + +func (r *namespaceResolver) Podhttpchaos(ctx context.Context, obj *model.Namespace, name *string) ([]*v1alpha1.PodHttpChaos, error) { + if name == nil { + var httpList v1alpha1.PodHttpChaosList + var https []*v1alpha1.PodHttpChaos + if err := r.Client.List(ctx, &httpList, &client.ListOptions{Namespace: obj.Ns}); err != nil { + return nil, err + } + + for i := range httpList.Items { + https = append(https, &httpList.Items[i]) + } + + return https, nil + } + + key := types.NamespacedName{Namespace: obj.Ns, Name: *name} + http := new(v1alpha1.PodHttpChaos) + if err := r.Client.Get(ctx, key, http); err != nil { + return nil, err + } + return []*v1alpha1.PodHttpChaos{http}, nil +} + +func (r *namespaceResolver) Networkchaos(ctx context.Context, obj *model.Namespace, name *string) ([]*v1alpha1.NetworkChaos, error) { + if name == nil { + var networkList v1alpha1.NetworkChaosList + var networks []*v1alpha1.NetworkChaos + if err := r.Client.List(ctx, &networkList, &client.ListOptions{Namespace: obj.Ns}); err != nil { + return nil, err + } + + for i := range networkList.Items { + networks = append(networks, &networkList.Items[i]) + } + + return networks, nil + } + + key := types.NamespacedName{Namespace: obj.Ns, Name: *name} + network := new(v1alpha1.NetworkChaos) + if err := r.Client.Get(ctx, key, network); err != nil { + return nil, err + } + return []*v1alpha1.NetworkChaos{network}, nil +} + +func (r *namespaceResolver) Podnetworkchaos(ctx context.Context, obj *model.Namespace, name *string) ([]*v1alpha1.PodNetworkChaos, error) { + if name == nil { + var networkList v1alpha1.PodNetworkChaosList + var networks []*v1alpha1.PodNetworkChaos + if err := r.Client.List(ctx, &networkList, &client.ListOptions{Namespace: obj.Ns}); err != nil { + return nil, err + } + + for i := range networkList.Items { + networks = append(networks, &networkList.Items[i]) + } + + return networks, nil + } + + key := types.NamespacedName{Namespace: obj.Ns, Name: *name} + network := new(v1alpha1.PodNetworkChaos) + if err := r.Client.Get(ctx, key, network); err != nil { + return nil, err + } + return []*v1alpha1.PodNetworkChaos{network}, nil +} + +func (r *networkChaosResolver) UID(ctx context.Context, obj *v1alpha1.NetworkChaos) (string, error) { + return string(obj.UID), nil +} + +func (r *networkChaosResolver) CreationTimestamp(ctx context.Context, obj *v1alpha1.NetworkChaos) (*time.Time, error) { + return &obj.CreationTimestamp.Time, nil +} + +func (r *networkChaosResolver) DeletionTimestamp(ctx context.Context, obj *v1alpha1.NetworkChaos) (*time.Time, error) { + return &obj.DeletionTimestamp.Time, nil +} + +func (r *networkChaosResolver) Labels(ctx context.Context, obj *v1alpha1.NetworkChaos) (map[string]interface{}, error) { + labels := make(map[string]interface{}) + for k, v := range obj.Labels { + labels[k] = v + } + return labels, nil +} + +func (r *networkChaosResolver) Annotations(ctx context.Context, obj *v1alpha1.NetworkChaos) (map[string]interface{}, error) { + annotations := make(map[string]interface{}) + for k, v := range obj.Annotations { + annotations[k] = v + } + return annotations, nil +} + +func (r *networkChaosResolver) Podnetwork(ctx context.Context, obj *v1alpha1.NetworkChaos) ([]*v1alpha1.PodNetworkChaos, error) { + podnetworks := make([]*v1alpha1.PodNetworkChaos, 0, len(obj.Status.Instances)) + for id := range obj.Status.Instances { + podnetwork := new(v1alpha1.PodNetworkChaos) + if err := r.Client.Get(ctx, parseNamespacedName(id), podnetwork); err != nil { + return nil, err + } + podnetworks = append(podnetworks, podnetwork) + } + return podnetworks, nil +} + +func (r *ownerReferenceResolver) UID(ctx context.Context, obj *v11.OwnerReference) (string, error) { + return string(obj.UID), nil +} + +func (r *podResolver) UID(ctx context.Context, obj *v1.Pod) (string, error) { + return string(obj.UID), nil +} + +func (r *podResolver) CreationTimestamp(ctx context.Context, obj *v1.Pod) (*time.Time, error) { + return &obj.CreationTimestamp.Time, nil +} + +func (r *podResolver) DeletionTimestamp(ctx context.Context, obj *v1.Pod) (*time.Time, error) { + return &obj.DeletionTimestamp.Time, nil +} + +func (r *podResolver) Labels(ctx context.Context, obj *v1.Pod) (map[string]interface{}, error) { + labels := make(map[string]interface{}) + for k, v := range obj.Labels { + labels[k] = v + } + return labels, nil +} + +func (r *podResolver) Annotations(ctx context.Context, obj *v1.Pod) (map[string]interface{}, error) { + annotations := make(map[string]interface{}) + for k, v := range obj.Annotations { + annotations[k] = v + } + return annotations, nil +} + +func (r *podResolver) Logs(ctx context.Context, obj *v1.Pod) (string, error) { + logs, err := r.Clientset.CoreV1().Pods(obj.Namespace).GetLogs(obj.Name, &v1.PodLogOptions{}).Stream(ctx) + if err != nil { + return "", err + } + defer logs.Close() + data, err := io.ReadAll(logs) + if err != nil { + return "", err + } + return string(data), nil +} + +func (r *podResolver) Daemon(ctx context.Context, obj *v1.Pod) (*v1.Pod, error) { + daemons, err := getDaemonMap(ctx, r.Client) + if err != nil { + return nil, err + } + + daemon, exist := daemons[obj.Spec.NodeName] + if !exist { + return nil, fmt.Errorf("daemon of pod(%s/%s) not found", obj.Namespace, obj.Name) + } + return &daemon, nil +} + +func (r *podResolver) Processes(ctx context.Context, obj *v1.Pod) ([]*model.Process, error) { + return r.GetPidFromPS(ctx, obj) +} + +func (r *podResolver) Mounts(ctx context.Context, obj *v1.Pod) ([]string, error) { + return r.GetMounts(ctx, obj) +} + +func (r *podResolver) Ipset(ctx context.Context, obj *v1.Pod) (string, error) { + return r.GetIpset(ctx, obj) +} + +func (r *podResolver) TcQdisc(ctx context.Context, obj *v1.Pod) ([]string, error) { + return r.GetTcQdisc(ctx, obj) +} + +func (r *podResolver) Iptables(ctx context.Context, obj *v1.Pod) ([]string, error) { + return r.GetIptables(ctx, obj) +} + +func (r *podConditionResolver) Type(ctx context.Context, obj *v1.PodCondition) (string, error) { + return string(obj.Type), nil +} + +func (r *podConditionResolver) Status(ctx context.Context, obj *v1.PodCondition) (string, error) { + return string(obj.Status), nil +} + +func (r *podConditionResolver) LastProbeTime(ctx context.Context, obj *v1.PodCondition) (*time.Time, error) { + return &obj.LastProbeTime.Time, nil +} + +func (r *podConditionResolver) LastTransitionTime(ctx context.Context, obj *v1.PodCondition) (*time.Time, error) { + return &obj.LastTransitionTime.Time, nil +} + +func (r *podHTTPChaosResolver) UID(ctx context.Context, obj *v1alpha1.PodHttpChaos) (string, error) { + return string(obj.UID), nil +} + +func (r *podHTTPChaosResolver) CreationTimestamp(ctx context.Context, obj *v1alpha1.PodHttpChaos) (*time.Time, error) { + return &obj.CreationTimestamp.Time, nil +} + +func (r *podHTTPChaosResolver) DeletionTimestamp(ctx context.Context, obj *v1alpha1.PodHttpChaos) (*time.Time, error) { + return &obj.DeletionTimestamp.Time, nil +} + +func (r *podHTTPChaosResolver) Labels(ctx context.Context, obj *v1alpha1.PodHttpChaos) (map[string]interface{}, error) { + labels := make(map[string]interface{}) + for k, v := range obj.Labels { + labels[k] = v + } + return labels, nil +} + +func (r *podHTTPChaosResolver) Annotations(ctx context.Context, obj *v1alpha1.PodHttpChaos) (map[string]interface{}, error) { + annotations := make(map[string]interface{}) + for k, v := range obj.Annotations { + annotations[k] = v + } + return annotations, nil +} + +func (r *podHTTPChaosResolver) Pod(ctx context.Context, obj *v1alpha1.PodHttpChaos) (*v1.Pod, error) { + pod := new(v1.Pod) + if err := r.Client.Get(ctx, types.NamespacedName{Namespace: obj.Namespace, Name: obj.Name}, pod); err != nil { + return nil, err + } + return pod, nil +} + +func (r *podHttpChaosReplaceActionsResolver) Body(ctx context.Context, obj *v1alpha1.PodHttpChaosReplaceActions) (*string, error) { + data, err := json.Marshal(obj.Body) + if err != nil { + return nil, err + } + + body := string(data) + return &body, nil +} + +func (r *podHttpChaosReplaceActionsResolver) Queries(ctx context.Context, obj *v1alpha1.PodHttpChaosReplaceActions) (map[string]interface{}, error) { + queries := make(map[string]interface{}) + for k, v := range obj.Queries { + queries[k] = v + } + return queries, nil +} + +func (r *podHttpChaosReplaceActionsResolver) Headers(ctx context.Context, obj *v1alpha1.PodHttpChaosReplaceActions) (map[string]interface{}, error) { + headers := make(map[string]interface{}) + for k, v := range obj.Headers { + headers[k] = v + } + return headers, nil +} + +func (r *podHttpChaosRuleResolver) Target(ctx context.Context, obj *v1alpha1.PodHttpChaosRule) (string, error) { + return string(obj.Target), nil +} + +func (r *podHttpChaosSelectorResolver) RequestHeaders(ctx context.Context, obj *v1alpha1.PodHttpChaosSelector) (map[string]interface{}, error) { + headers := make(map[string]interface{}) + for k, v := range obj.RequestHeaders { + headers[k] = v + } + return headers, nil +} + +func (r *podHttpChaosSelectorResolver) ResponseHeaders(ctx context.Context, obj *v1alpha1.PodHttpChaosSelector) (map[string]interface{}, error) { + headers := make(map[string]interface{}) + for k, v := range obj.ResponseHeaders { + headers[k] = v + } + return headers, nil +} + +func (r *podIOChaosResolver) UID(ctx context.Context, obj *v1alpha1.PodIOChaos) (string, error) { + return string(obj.UID), nil +} + +func (r *podIOChaosResolver) CreationTimestamp(ctx context.Context, obj *v1alpha1.PodIOChaos) (*time.Time, error) { + return &obj.CreationTimestamp.Time, nil +} + +func (r *podIOChaosResolver) DeletionTimestamp(ctx context.Context, obj *v1alpha1.PodIOChaos) (*time.Time, error) { + return &obj.DeletionTimestamp.Time, nil +} + +func (r *podIOChaosResolver) Labels(ctx context.Context, obj *v1alpha1.PodIOChaos) (map[string]interface{}, error) { + labels := make(map[string]interface{}) + for k, v := range obj.Labels { + labels[k] = v + } + return labels, nil +} + +func (r *podIOChaosResolver) Annotations(ctx context.Context, obj *v1alpha1.PodIOChaos) (map[string]interface{}, error) { + annotations := make(map[string]interface{}) + for k, v := range obj.Annotations { + annotations[k] = v + } + return annotations, nil +} + +func (r *podIOChaosResolver) Pod(ctx context.Context, obj *v1alpha1.PodIOChaos) (*v1.Pod, error) { + pod := new(v1.Pod) + key := types.NamespacedName{Namespace: obj.Namespace, Name: obj.Name} + if err := r.Client.Get(ctx, key, pod); err != nil { + return nil, err + } + return pod, nil +} + +func (r *podIOChaosResolver) Ios(ctx context.Context, obj *v1alpha1.PodIOChaos) ([]*v1alpha1.IOChaos, error) { + ioNames := make(map[string]bool) + for _, action := range obj.Spec.Actions { + ioNames[action.Source] = true + } + + ios := make([]*v1alpha1.IOChaos, 0, len(ioNames)) + for name := range ioNames { + namespaced := parseNamespacedName(name) + io := new(v1alpha1.IOChaos) + if err := r.Client.Get(ctx, namespaced, io); err != nil { + return nil, err + } + ios = append(ios, io) + } + return ios, nil +} + +func (r *podNetworkChaosResolver) UID(ctx context.Context, obj *v1alpha1.PodNetworkChaos) (string, error) { + return string(obj.UID), nil +} + +func (r *podNetworkChaosResolver) CreationTimestamp(ctx context.Context, obj *v1alpha1.PodNetworkChaos) (*time.Time, error) { + return &obj.CreationTimestamp.Time, nil +} + +func (r *podNetworkChaosResolver) DeletionTimestamp(ctx context.Context, obj *v1alpha1.PodNetworkChaos) (*time.Time, error) { + return &obj.DeletionTimestamp.Time, nil +} + +func (r *podNetworkChaosResolver) Labels(ctx context.Context, obj *v1alpha1.PodNetworkChaos) (map[string]interface{}, error) { + labels := make(map[string]interface{}) + for k, v := range obj.Labels { + labels[k] = v + } + return labels, nil +} + +func (r *podNetworkChaosResolver) Annotations(ctx context.Context, obj *v1alpha1.PodNetworkChaos) (map[string]interface{}, error) { + annotations := make(map[string]interface{}) + for k, v := range obj.Annotations { + annotations[k] = v + } + return annotations, nil +} + +func (r *podNetworkChaosResolver) Pod(ctx context.Context, obj *v1alpha1.PodNetworkChaos) (*v1.Pod, error) { + pod := new(v1.Pod) + if err := r.Client.Get(ctx, types.NamespacedName{Namespace: obj.Namespace, Name: obj.Name}, pod); err != nil { + return nil, err + } + return pod, nil +} + +func (r *podSelectorSpecResolver) Pods(ctx context.Context, obj *v1alpha1.PodSelectorSpec) (map[string]interface{}, error) { + pods := make(map[string]interface{}) + for k, v := range obj.Pods { + pods[k] = v + } + return pods, nil +} + +func (r *podSelectorSpecResolver) NodeSelectors(ctx context.Context, obj *v1alpha1.PodSelectorSpec) (map[string]interface{}, error) { + selectors := make(map[string]interface{}) + for k, v := range obj.NodeSelectors { + selectors[k] = v + } + return selectors, nil +} + +func (r *podSelectorSpecResolver) FieldSelectors(ctx context.Context, obj *v1alpha1.PodSelectorSpec) (map[string]interface{}, error) { + selectors := make(map[string]interface{}) + for k, v := range obj.FieldSelectors { + selectors[k] = v + } + return selectors, nil +} + +func (r *podSelectorSpecResolver) LabelSelectors(ctx context.Context, obj *v1alpha1.PodSelectorSpec) (map[string]interface{}, error) { + selectors := make(map[string]interface{}) + for k, v := range obj.LabelSelectors { + selectors[k] = v + } + return selectors, nil +} + +func (r *podSelectorSpecResolver) AnnotationSelectors(ctx context.Context, obj *v1alpha1.PodSelectorSpec) (map[string]interface{}, error) { + selectors := make(map[string]interface{}) + for k, v := range obj.AnnotationSelectors { + selectors[k] = v + } + return selectors, nil +} + +func (r *podStatusResolver) Phase(ctx context.Context, obj *v1.PodStatus) (string, error) { + return string(obj.Phase), nil +} + +func (r *podStatusResolver) StartTime(ctx context.Context, obj *v1.PodStatus) (*time.Time, error) { + return &obj.StartTime.Time, nil +} + +func (r *podStatusResolver) QosClass(ctx context.Context, obj *v1.PodStatus) (string, error) { + return string(obj.QOSClass), nil +} + +func (r *podStressChaosResolver) Cgroups(ctx context.Context, obj *model.PodStressChaos) (*model.Cgroups, error) { + return r.GetCgroups(ctx, obj) +} + +func (r *podStressChaosResolver) ProcessStress(ctx context.Context, obj *model.PodStressChaos) ([]*model.ProcessStress, error) { + processes, err := r.Pod().Processes(ctx, obj.Pod) + if err != nil { + return nil, err + } + + var processStress []*model.ProcessStress + for _, process := range processes { + cgroup, err := r.GetCgroup(ctx, obj.Pod, process.Pid) + if err != nil { + r.Log.Error(err, "get cgroup for process", "pid", process.Pid) + // ignore this process + continue + } + + processStress = append(processStress, &model.ProcessStress{ + Process: process, + Cgroup: cgroup, + }) + } + return processStress, nil +} + +func (r *processResolver) Fds(ctx context.Context, obj *model.Process) ([]*model.Fd, error) { + return r.GetFdsOfProcess(ctx, obj), nil +} + +func (r *queryResolver) Namespace(ctx context.Context, ns *string) ([]*model.Namespace, error) { + if ns == nil { + var nsList v1.NamespaceList + var namespaces []*model.Namespace + if err := r.Client.List(ctx, &nsList); err != nil { + return nil, err + } + + for _, ns := range nsList.Items { + namespaces = append(namespaces, &model.Namespace{Ns: ns.Name}) + } + + return namespaces, nil + } + return []*model.Namespace{{Ns: *ns}}, nil +} + +func (r *queryResolver) Pods(ctx context.Context, selector model.PodSelectorInput) ([]*v1.Pod, error) { + spec := v1alpha1.PodSelectorSpec{ + Pods: map[string][]string{}, + NodeSelectors: map[string]string{}, + Nodes: selector.Nodes, + PodPhaseSelectors: selector.PodPhaseSelectors, + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: selector.Namespaces, + FieldSelectors: map[string]string{}, + LabelSelectors: map[string]string{}, + AnnotationSelectors: map[string]string{}, + }, + } + + for ns, p := range selector.Pods { + if pod, ok := p.(string); ok { + spec.Pods[ns] = []string{pod} + } + + if pods, ok := p.([]string); ok { + spec.Pods[ns] = pods + } + } + + for k, s := range selector.NodeSelectors { + if selector, ok := s.(string); ok { + spec.NodeSelectors[k] = selector + } + } + + for k, s := range selector.FieldSelectors { + if selector, ok := s.(string); ok { + spec.FieldSelectors[k] = selector + } + } + + for k, s := range selector.LabelSelectors { + if selector, ok := s.(string); ok { + spec.LabelSelectors[k] = selector + } + } + + for k, s := range selector.AnnotationSelectors { + if selector, ok := s.(string); ok { + spec.AnnotationSelectors[k] = selector + } + } + + selectImpl := podSelector.New(podSelector.Params{ + Client: r.Client, + Reader: r.Client, + }) + pods, err := selectImpl.Select(ctx, &v1alpha1.PodSelector{Selector: spec, Mode: v1alpha1.AllMode}) + if err != nil { + if errors.Is(err, podSelector.ErrNoPodSelected) { + return nil, nil + } + return nil, err + } + var list []*v1.Pod + for _, pod := range pods { + p := pod + list = append(list, &p.Pod) + } + return list, nil +} + +func (r *rawIPSetResolver) IPSetType(ctx context.Context, obj *v1alpha1.RawIPSet) (string, error) { + return string(obj.IPSetType), nil +} + +func (r *rawIptablesResolver) Direction(ctx context.Context, obj *v1alpha1.RawIptables) (string, error) { + return string(obj.Direction), nil +} + +func (r *rawTrafficControlResolver) Type(ctx context.Context, obj *v1alpha1.RawTrafficControl) (string, error) { + return string(obj.Type), nil +} + +func (r *recordResolver) Phase(ctx context.Context, obj *v1alpha1.Record) (string, error) { + return string(obj.Phase), nil +} + +func (r *stressChaosResolver) UID(ctx context.Context, obj *v1alpha1.StressChaos) (string, error) { + return string(obj.UID), nil +} + +func (r *stressChaosResolver) CreationTimestamp(ctx context.Context, obj *v1alpha1.StressChaos) (*time.Time, error) { + return &obj.CreationTimestamp.Time, nil +} + +func (r *stressChaosResolver) DeletionTimestamp(ctx context.Context, obj *v1alpha1.StressChaos) (*time.Time, error) { + return &obj.DeletionTimestamp.Time, nil +} + +func (r *stressChaosResolver) Labels(ctx context.Context, obj *v1alpha1.StressChaos) (map[string]interface{}, error) { + labels := make(map[string]interface{}) + for k, v := range obj.Labels { + labels[k] = v + } + return labels, nil +} + +func (r *stressChaosResolver) Annotations(ctx context.Context, obj *v1alpha1.StressChaos) (map[string]interface{}, error) { + annotations := make(map[string]interface{}) + for k, v := range obj.Annotations { + annotations[k] = v + } + return annotations, nil +} + +func (r *stressChaosResolver) Podstress(ctx context.Context, obj *v1alpha1.StressChaos) ([]*model.PodStressChaos, error) { + pods, _, err := GetPods(ctx, obj.Status.ChaosStatus, obj.Spec.Selector, r.Client) + if err != nil { + return nil, err + } + + var podStress []*model.PodStressChaos + for _, pod := range pods { + p := pod + podStress = append(podStress, &model.PodStressChaos{ + StressChaos: obj, + Pod: &p, + }) + } + return podStress, nil +} + +func (r *stressChaosSpecResolver) Mode(ctx context.Context, obj *v1alpha1.StressChaosSpec) (string, error) { + return string(obj.Mode), nil +} + +func (r *stressChaosStatusResolver) Instances(ctx context.Context, obj *v1alpha1.StressChaosStatus) (map[string]interface{}, error) { + instances := make(map[string]interface{}) + for k, v := range obj.Instances { + instances[k] = v + } + return instances, nil +} + +// AttrOverrideSpec returns generated.AttrOverrideSpecResolver implementation. +func (r *Resolver) AttrOverrideSpec() generated.AttrOverrideSpecResolver { + return &attrOverrideSpecResolver{r} +} + +// BandwidthSpec returns generated.BandwidthSpecResolver implementation. +func (r *Resolver) BandwidthSpec() generated.BandwidthSpecResolver { return &bandwidthSpecResolver{r} } + +// ChaosCondition returns generated.ChaosConditionResolver implementation. +func (r *Resolver) ChaosCondition() generated.ChaosConditionResolver { + return &chaosConditionResolver{r} +} + +// CidrAndPort returns generated.CidrAndPortResolver implementation. +func (r *Resolver) CidrAndPort() generated.CidrAndPortResolver { return &cidrAndPortResolver{r} } + +// ContainerStateRunning returns generated.ContainerStateRunningResolver implementation. +func (r *Resolver) ContainerStateRunning() generated.ContainerStateRunningResolver { + return &containerStateRunningResolver{r} +} + +// ContainerStateTerminated returns generated.ContainerStateTerminatedResolver implementation. +func (r *Resolver) ContainerStateTerminated() generated.ContainerStateTerminatedResolver { + return &containerStateTerminatedResolver{r} +} + +// ExperimentStatus returns generated.ExperimentStatusResolver implementation. +func (r *Resolver) ExperimentStatus() generated.ExperimentStatusResolver { + return &experimentStatusResolver{r} +} + +// HTTPChaos returns generated.HTTPChaosResolver implementation. +func (r *Resolver) HTTPChaos() generated.HTTPChaosResolver { return &hTTPChaosResolver{r} } + +// HTTPChaosSpec returns generated.HTTPChaosSpecResolver implementation. +func (r *Resolver) HTTPChaosSpec() generated.HTTPChaosSpecResolver { return &hTTPChaosSpecResolver{r} } + +// HTTPChaosStatus returns generated.HTTPChaosStatusResolver implementation. +func (r *Resolver) HTTPChaosStatus() generated.HTTPChaosStatusResolver { + return &hTTPChaosStatusResolver{r} +} + +// IOChaos returns generated.IOChaosResolver implementation. +func (r *Resolver) IOChaos() generated.IOChaosResolver { return &iOChaosResolver{r} } + +// IOChaosAction returns generated.IOChaosActionResolver implementation. +func (r *Resolver) IOChaosAction() generated.IOChaosActionResolver { return &iOChaosActionResolver{r} } + +// IOChaosSpec returns generated.IOChaosSpecResolver implementation. +func (r *Resolver) IOChaosSpec() generated.IOChaosSpecResolver { return &iOChaosSpecResolver{r} } + +// IOChaosStatus returns generated.IOChaosStatusResolver implementation. +func (r *Resolver) IOChaosStatus() generated.IOChaosStatusResolver { return &iOChaosStatusResolver{r} } + +// IoFault returns generated.IoFaultResolver implementation. +func (r *Resolver) IoFault() generated.IoFaultResolver { return &ioFaultResolver{r} } + +// Logger returns generated.LoggerResolver implementation. +func (r *Resolver) Logger() generated.LoggerResolver { return &loggerResolver{r} } + +// MistakeSpec returns generated.MistakeSpecResolver implementation. +func (r *Resolver) MistakeSpec() generated.MistakeSpecResolver { return &mistakeSpecResolver{r} } + +// MutablePod returns generated.MutablePodResolver implementation. +func (r *Resolver) MutablePod() generated.MutablePodResolver { return &mutablePodResolver{r} } + +// Mutation returns generated.MutationResolver implementation. +func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} } + +// Namespace returns generated.NamespaceResolver implementation. +func (r *Resolver) Namespace() generated.NamespaceResolver { return &namespaceResolver{r} } + +// NetworkChaos returns generated.NetworkChaosResolver implementation. +func (r *Resolver) NetworkChaos() generated.NetworkChaosResolver { return &networkChaosResolver{r} } + +// OwnerReference returns generated.OwnerReferenceResolver implementation. +func (r *Resolver) OwnerReference() generated.OwnerReferenceResolver { + return &ownerReferenceResolver{r} +} + +// Pod returns generated.PodResolver implementation. +func (r *Resolver) Pod() generated.PodResolver { return &podResolver{r} } + +// PodCondition returns generated.PodConditionResolver implementation. +func (r *Resolver) PodCondition() generated.PodConditionResolver { return &podConditionResolver{r} } + +// PodHTTPChaos returns generated.PodHTTPChaosResolver implementation. +func (r *Resolver) PodHTTPChaos() generated.PodHTTPChaosResolver { return &podHTTPChaosResolver{r} } + +// PodHttpChaosReplaceActions returns generated.PodHttpChaosReplaceActionsResolver implementation. +func (r *Resolver) PodHttpChaosReplaceActions() generated.PodHttpChaosReplaceActionsResolver { + return &podHttpChaosReplaceActionsResolver{r} +} + +// PodHttpChaosRule returns generated.PodHttpChaosRuleResolver implementation. +func (r *Resolver) PodHttpChaosRule() generated.PodHttpChaosRuleResolver { + return &podHttpChaosRuleResolver{r} +} + +// PodHttpChaosSelector returns generated.PodHttpChaosSelectorResolver implementation. +func (r *Resolver) PodHttpChaosSelector() generated.PodHttpChaosSelectorResolver { + return &podHttpChaosSelectorResolver{r} +} + +// PodIOChaos returns generated.PodIOChaosResolver implementation. +func (r *Resolver) PodIOChaos() generated.PodIOChaosResolver { return &podIOChaosResolver{r} } + +// PodNetworkChaos returns generated.PodNetworkChaosResolver implementation. +func (r *Resolver) PodNetworkChaos() generated.PodNetworkChaosResolver { + return &podNetworkChaosResolver{r} +} + +// PodSelectorSpec returns generated.PodSelectorSpecResolver implementation. +func (r *Resolver) PodSelectorSpec() generated.PodSelectorSpecResolver { + return &podSelectorSpecResolver{r} +} + +// PodStatus returns generated.PodStatusResolver implementation. +func (r *Resolver) PodStatus() generated.PodStatusResolver { return &podStatusResolver{r} } + +// PodStressChaos returns generated.PodStressChaosResolver implementation. +func (r *Resolver) PodStressChaos() generated.PodStressChaosResolver { + return &podStressChaosResolver{r} +} + +// Process returns generated.ProcessResolver implementation. +func (r *Resolver) Process() generated.ProcessResolver { return &processResolver{r} } + +// Query returns generated.QueryResolver implementation. +func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} } + +// RawIPSet returns generated.RawIPSetResolver implementation. +func (r *Resolver) RawIPSet() generated.RawIPSetResolver { return &rawIPSetResolver{r} } + +// RawIptables returns generated.RawIptablesResolver implementation. +func (r *Resolver) RawIptables() generated.RawIptablesResolver { return &rawIptablesResolver{r} } + +// RawTrafficControl returns generated.RawTrafficControlResolver implementation. +func (r *Resolver) RawTrafficControl() generated.RawTrafficControlResolver { + return &rawTrafficControlResolver{r} +} + +// Record returns generated.RecordResolver implementation. +func (r *Resolver) Record() generated.RecordResolver { return &recordResolver{r} } + +// StressChaos returns generated.StressChaosResolver implementation. +func (r *Resolver) StressChaos() generated.StressChaosResolver { return &stressChaosResolver{r} } + +// StressChaosSpec returns generated.StressChaosSpecResolver implementation. +func (r *Resolver) StressChaosSpec() generated.StressChaosSpecResolver { + return &stressChaosSpecResolver{r} +} + +// StressChaosStatus returns generated.StressChaosStatusResolver implementation. +func (r *Resolver) StressChaosStatus() generated.StressChaosStatusResolver { + return &stressChaosStatusResolver{r} +} + +type attrOverrideSpecResolver struct{ *Resolver } +type bandwidthSpecResolver struct{ *Resolver } +type chaosConditionResolver struct{ *Resolver } +type cidrAndPortResolver struct{ *Resolver } +type containerStateRunningResolver struct{ *Resolver } +type containerStateTerminatedResolver struct{ *Resolver } +type experimentStatusResolver struct{ *Resolver } +type hTTPChaosResolver struct{ *Resolver } +type hTTPChaosSpecResolver struct{ *Resolver } +type hTTPChaosStatusResolver struct{ *Resolver } +type iOChaosResolver struct{ *Resolver } +type iOChaosActionResolver struct{ *Resolver } +type iOChaosSpecResolver struct{ *Resolver } +type iOChaosStatusResolver struct{ *Resolver } +type ioFaultResolver struct{ *Resolver } +type loggerResolver struct{ *Resolver } +type mistakeSpecResolver struct{ *Resolver } +type mutablePodResolver struct{ *Resolver } +type mutationResolver struct{ *Resolver } +type namespaceResolver struct{ *Resolver } +type networkChaosResolver struct{ *Resolver } +type ownerReferenceResolver struct{ *Resolver } +type podResolver struct{ *Resolver } +type podConditionResolver struct{ *Resolver } +type podHTTPChaosResolver struct{ *Resolver } +type podHttpChaosReplaceActionsResolver struct{ *Resolver } +type podHttpChaosRuleResolver struct{ *Resolver } +type podHttpChaosSelectorResolver struct{ *Resolver } +type podIOChaosResolver struct{ *Resolver } +type podNetworkChaosResolver struct{ *Resolver } +type podSelectorSpecResolver struct{ *Resolver } +type podStatusResolver struct{ *Resolver } +type podStressChaosResolver struct{ *Resolver } +type processResolver struct{ *Resolver } +type queryResolver struct{ *Resolver } +type rawIPSetResolver struct{ *Resolver } +type rawIptablesResolver struct{ *Resolver } +type rawTrafficControlResolver struct{ *Resolver } +type recordResolver struct{ *Resolver } +type stressChaosResolver struct{ *Resolver } +type stressChaosSpecResolver struct{ *Resolver } +type stressChaosStatusResolver struct{ *Resolver } diff --git a/pkg/curl/doc.go b/pkg/curl/doc.go new file mode 100644 index 0000000000..b00e8cd195 --- /dev/null +++ b/pkg/curl/doc.go @@ -0,0 +1,17 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package curl contains the tools about rendering and parsing curl command +package curl diff --git a/pkg/curl/parser.go b/pkg/curl/parser.go new file mode 100644 index 0000000000..598ff2f207 --- /dev/null +++ b/pkg/curl/parser.go @@ -0,0 +1,99 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package curl + +import ( + "strings" + + "github.com/pkg/errors" + flag "github.com/spf13/pflag" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +func parseCommands(command Commands) (*CommandFlags, error) { + flagset := flag.NewFlagSet("curl", flag.ContinueOnError) + flagset.ParseErrorsWhitelist.UnknownFlags = true + + // these parts of flags are referenced to the manual of curl + flagset.BoolP("silent", "s", true, "silent mode") + location := flagset.BoolP("location", "L", false, "follow the location") + requestMethod := flagset.StringP("request", "X", "GET", "request method") + rawHeader := flagset.StringArrayP("header", "H", []string{}, "HTTP extra header") + data := flagset.StringP("data", "d", "", "data") + err := flagset.Parse(command) + if err != nil { + return nil, err + } + + // first non-flag arg is the command itself, use the second non-flag arg as the url. + if flag.NArg() > 1 { + return nil, errors.New("can not find the url") + } + url := flagset.Arg(1) + + isJson := false + var header Header + if len(*rawHeader) > 0 { + header = Header{} + } + for _, item := range *rawHeader { + k, v := parseHeader(item) + if k == HeaderContentType && v == ApplicationJson { + isJson = true + continue + } + header[k] = append(header[k], v) + } + if len(header) == 0 { + header = nil + } + + return &CommandFlags{ + Method: *requestMethod, + URL: url, + Header: header, + Body: *data, + FollowLocation: *location, + JsonContent: isJson, + }, nil +} + +func ParseWorkflowTaskTemplate(template *v1alpha1.Template) (*RequestForm, error) { + if !IsValidRenderedTask(template) { + return nil, errors.New("invalid request, this task is not rendered by curl-render") + } + parsedFlags, err := parseCommands(template.Task.Container.Command) + if err != nil { + return nil, err + } + return &RequestForm{ + CommandFlags: *parsedFlags, + Name: template.Name, + }, nil +} + +func IsValidRenderedTask(template *v1alpha1.Template) bool { + return template.Type == v1alpha1.TypeTask && strings.HasSuffix(template.Task.Container.Name, nameSuffix) +} + +func parseHeader(headerKV string) (key, value string) { + kv := strings.SplitN(headerKV, ":", 2) + + key = strings.TrimSpace(kv[0]) + value = strings.TrimSpace(kv[1]) + return +} diff --git a/pkg/curl/parser_test.go b/pkg/curl/parser_test.go new file mode 100644 index 0000000000..cddd2eaf15 --- /dev/null +++ b/pkg/curl/parser_test.go @@ -0,0 +1,51 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package curl + +import "fmt" + +func Example_parseCommands() { + cmd := []string{"curl", "-i", "-s", "-L", "https://github.com/chaos-mesh/chaos-mesh"} + flags, err := parseCommands(cmd) + if err != nil { + fmt.Println(err.Error()) + } + + fmt.Printf("%+v", flags) + // Output: &{Method:GET URL:https://github.com/chaos-mesh/chaos-mesh Header:map[] Body: FollowLocation:true JsonContent:false} +} + +func Example_parseCommands_withCustomHeader() { + cmd := []string{"curl", "-i", "-s", "-L", "-H", "User-Agent: Go-http-client/1.1", "https://github.com/chaos-mesh/chaos-mesh"} + flags, err := parseCommands(cmd) + if err != nil { + fmt.Println(err.Error()) + } + + fmt.Printf("%+v", flags) + // Output: &{Method:GET URL:https://github.com/chaos-mesh/chaos-mesh Header:map[User-Agent:[Go-http-client/1.1]] Body: FollowLocation:true JsonContent:false} +} + +func Example_parseCommands_postJson() { + cmd := []string{"curl", "-i", "-s", "-X", "POST", "-d", "{\"foo\": \"bar\"}", "-H", "Content-Type: application/json", "https://jsonplaceholder.typicode.com/posts"} + flags, err := parseCommands(cmd) + if err != nil { + fmt.Println(err.Error()) + } + + fmt.Printf("%+v", flags) + // Output: &{Method:POST URL:https://jsonplaceholder.typicode.com/posts Header:map[] Body:{"foo": "bar"} FollowLocation:false JsonContent:true} +} diff --git a/pkg/curl/render.go b/pkg/curl/render.go new file mode 100644 index 0000000000..41b19f9e2e --- /dev/null +++ b/pkg/curl/render.go @@ -0,0 +1,88 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package curl + +import ( + "fmt" + "net/http" + + corev1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +const image = "curlimages/curl:7.78.0" + +const nameSuffix = "-rendered-http-request" + +func renderCommands(request CommandFlags) (Commands, error) { + // TODO: validation of request + result := []string{"curl", "-i", "-s"} + + // follow the request + if request.FollowLocation { + result = append(result, "-L") + } + + if request.Method != http.MethodGet { + result = append(result, "-X", request.Method) + + if len(request.Body) > 0 { + result = append(result, "-d", request.Body) + } + } + + renderedHeaders := http.Header{} + for k, v := range request.Header { + renderedHeaders[k] = v + } + if request.JsonContent { + if request.Header == nil { + request.Header = Header{} + } + renderedHeaders[HeaderContentType] = []string{ApplicationJson} + } + + for key, values := range renderedHeaders { + for _, value := range values { + result = append(result, "-H", fmt.Sprintf("%s: %s", key, value)) + } + } + + result = append(result, request.URL) + + return result, nil +} + +func RenderWorkflowTaskTemplate(request RequestForm) (*v1alpha1.Template, error) { + commands, err := renderCommands(request.CommandFlags) + if err != nil { + return nil, err + } + containerName := fmt.Sprintf("%s%s", request.Name, nameSuffix) + return &v1alpha1.Template{ + Name: request.Name, + Type: v1alpha1.TypeTask, + Task: &v1alpha1.Task{ + Container: &corev1.Container{ + Name: containerName, + Image: image, + Command: commands, + }, + }, + ConditionalBranches: nil, + }, nil +} diff --git a/pkg/curl/render_test.go b/pkg/curl/render_test.go new file mode 100644 index 0000000000..337375c720 --- /dev/null +++ b/pkg/curl/render_test.go @@ -0,0 +1,68 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package curl + +import ( + "fmt" + "net/http" + "strings" +) + +// some example usage of renderCommands +// notice that the output could not be used in shell directly, you need quotes and escape +func Example_renderCommands() { + commands, _ := renderCommands(CommandFlags{ + Method: http.MethodGet, + URL: "https://github.com/chaos-mesh/chaos-mesh", + Header: nil, + Body: "", + FollowLocation: true, + JsonContent: false, + }) + + fmt.Println(strings.Join(commands, " ")) + // Output: curl -i -s -L https://github.com/chaos-mesh/chaos-mesh +} + +func Example_renderCommands_withCustomHeader() { + commands, _ := renderCommands(CommandFlags{ + Method: http.MethodGet, + URL: "https://github.com/chaos-mesh/chaos-mesh", + Header: Header{ + "User-Agent": []string{"Go-http-client/1.1"}, + }, + Body: "", + FollowLocation: true, + JsonContent: false, + }) + + fmt.Println(strings.Join(commands, " ")) + // Output: curl -i -s -L -H User-Agent: Go-http-client/1.1 https://github.com/chaos-mesh/chaos-mesh +} + +func Example_renderCommands_postJson() { + commands, _ := renderCommands(CommandFlags{ + Method: http.MethodPost, + URL: "https://jsonplaceholder.typicode.com/posts", + Header: nil, + Body: "{\"foo\": \"bar\"}", + FollowLocation: false, + JsonContent: true, + }) + + fmt.Println(strings.Join(commands, " ")) + // Output: curl -i -s -X POST -d {"foo": "bar"} -H Content-Type: application/json https://jsonplaceholder.typicode.com/posts +} diff --git a/pkg/curl/roundtrip_test.go b/pkg/curl/roundtrip_test.go new file mode 100644 index 0000000000..c06edfd28e --- /dev/null +++ b/pkg/curl/roundtrip_test.go @@ -0,0 +1,98 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package curl + +import ( + "net/http" + "testing" + + . "github.com/onsi/gomega" +) + +// Maybe we need some fuzzing test + +func TestRoundTrip(t *testing.T) { + RegisterTestingT(t) + tests := []struct { + name string + flags CommandFlags + }{ + { + name: "simple get", + flags: CommandFlags{ + Method: http.MethodGet, + URL: "github.com/chaos-mesh/chaos-mesh", + Header: nil, + Body: "", + FollowLocation: false, + JsonContent: false, + }, + }, { + name: "get with header", + flags: CommandFlags{ + Method: http.MethodGet, + URL: "https://github.com/chaos-mesh/chaos-mesh", + Header: Header{ + "User-Agent": []string{"Go-http-client/1.1"}, + }, + Body: "", + FollowLocation: false, + JsonContent: false, + }, + }, { + name: "post json", + flags: CommandFlags{ + Method: http.MethodPost, + URL: "https://jsonplaceholder.typicode.com/posts", + Header: nil, + Body: "{\"foo\": \"bar\"}", + FollowLocation: false, + JsonContent: true, + }, + }, { + name: "post json with custom header", + flags: CommandFlags{ + Method: http.MethodPost, + URL: "https://jsonplaceholder.typicode.com/posts", + Header: Header{ + "User-Agent": []string{"Go-http-client/1.1"}, + }, + Body: "{\"foo\": \"bar\"}", + FollowLocation: false, + JsonContent: true, + }, + }, { + name: "get with following location", + flags: CommandFlags{ + Method: http.MethodGet, + URL: "www.google.com", + Header: nil, + Body: "", + FollowLocation: true, + JsonContent: false, + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + commands, err := renderCommands(test.flags) + Expect(err).ShouldNot(HaveOccurred()) + parsedFlags, err := parseCommands(commands) + Expect(err).ShouldNot(HaveOccurred()) + Expect(parsedFlags).To(Equal(&test.flags), "rendered commands %+v", commands) + }) + } +} diff --git a/pkg/curl/types.go b/pkg/curl/types.go new file mode 100644 index 0000000000..17d9d370cf --- /dev/null +++ b/pkg/curl/types.go @@ -0,0 +1,40 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package curl + +const HeaderContentType = "Content-Type" +const ApplicationJson = "application/json" + +// RequestForm should contain all the fields shown on frontend +type RequestForm struct { + CommandFlags + Name string `json:"name"` +} + +// Header is copied from http.Header, for speed up swagger_spec code generator without --parseDependency +type Header map[string][]string + +// CommandFlags could be parsed from flags of curl command line. +type CommandFlags struct { + Method string `json:"method"` + URL string `json:"url"` + Header Header `json:"header"` + Body string `json:"body"` + FollowLocation bool `json:"followLocation"` + JsonContent bool `json:"jsonContent"` +} + +type Commands []string diff --git a/pkg/dashboard/apiserver/archive/archive.go b/pkg/dashboard/apiserver/archive/archive.go new file mode 100644 index 0000000000..fc3aa5fe39 --- /dev/null +++ b/pkg/dashboard/apiserver/archive/archive.go @@ -0,0 +1,592 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package archive + +import ( + "context" + "encoding/json" + "net/http" + "reflect" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/jinzhu/gorm" + "github.com/pkg/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/types" + u "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/utils" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +// Service defines a handler service for archives. +type Service struct { + archive core.ExperimentStore + archiveSchedule core.ScheduleStore + event core.EventStore + workflowStore core.WorkflowStore + conf *config.ChaosDashboardConfig +} + +func NewService( + archive core.ExperimentStore, + archiveSchedule core.ScheduleStore, + event core.EventStore, + workflowStore core.WorkflowStore, + conf *config.ChaosDashboardConfig, +) *Service { + return &Service{ + archive: archive, + archiveSchedule: archiveSchedule, + event: event, + workflowStore: workflowStore, + conf: conf, + } +} + +// Register archives RouterGroup. +func Register(r *gin.RouterGroup, s *Service) { + endpoint := r.Group("/archives") + endpoint.Use(func(c *gin.Context) { + u.AuthMiddleware(c, s.conf) + }) + + endpoint.GET("", s.list) + endpoint.GET("/:uid", s.get) + endpoint.DELETE("/:uid", s.delete) + endpoint.DELETE("", s.batchDelete) + + endpoint.GET("/schedules", s.listSchedule) + endpoint.GET("/schedules/:uid", s.detailSchedule) + endpoint.DELETE("/schedules/:uid", s.deleteSchedule) + endpoint.DELETE("/schedules", s.batchDeleteSchedule) + + endpoint.GET("/workflows", s.listWorkflow) + endpoint.GET("/workflows/:uid", s.detailWorkflow) + endpoint.DELETE("/workflows/:uid", s.deleteWorkflow) + endpoint.DELETE("/workflows", s.batchDeleteWorkflow) +} + +// @Summary Get archived chaos experiments. +// @Description Get archived chaos experiments. +// @Tags archives +// @Produce json +// @Param namespace query string false "namespace" +// @Param name query string false "name" +// @Param kind query string false "kind" Enums(PodChaos, IOChaos, NetworkChaos, TimeChaos, KernelChaos, StressChaos) +// @Success 200 {array} types.Archive +// @Router /archives [get] +// @Failure 500 {object} u.APIError +func (s *Service) list(c *gin.Context) { + kind := c.Query("kind") + name := c.Query("name") + ns := c.Query("namespace") + if len(ns) == 0 && !s.conf.ClusterScoped && + len(s.conf.TargetNamespace) != 0 { + ns = s.conf.TargetNamespace + } + + metas, err := s.archive.ListMeta(context.Background(), kind, ns, name, true) + if err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.NewWithNoMessage()) + return + } + + archives := make([]types.Archive, 0) + + for _, meta := range metas { + archives = append(archives, types.Archive{ + UID: meta.UID, + Kind: meta.Kind, + Namespace: meta.Namespace, + Name: meta.Name, + Created: meta.StartTime.Format(time.RFC3339), + }) + } + + c.JSON(http.StatusOK, archives) +} + +// @Summary Get an archived chaos experiment. +// @Description Get the archived chaos experiment's detail by uid. +// @Tags archives +// @Produce json +// @Param uid path string true "the archive uid" +// @Success 200 {object} types.ArchiveDetail +// @Failure 404 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /archives/{uid} [get] +func (s *Service) get(c *gin.Context) { + uid := c.Param("uid") + exp, err := s.archive.FindByUID(context.Background(), uid) + if err != nil { + if gorm.IsRecordNotFoundError(err) { + u.SetAPIError(c, u.ErrNotFound.New("Experiment "+uid+" not found")) + } else { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + } + + return + } + + chaos := v1alpha1.AllKinds()[exp.Kind].SpawnObject() + _ = json.Unmarshal([]byte(exp.Experiment), chaos) + + c.JSON(http.StatusOK, &types.ArchiveDetail{ + Archive: types.Archive{ + UID: exp.UID, + Kind: exp.Kind, + Name: exp.Name, + Namespace: exp.Namespace, + Created: exp.StartTime.Format(time.RFC3339), + }, + KubeObject: core.KubeObjectDesc{ + TypeMeta: metav1.TypeMeta{ + APIVersion: reflect.ValueOf(chaos).Elem().FieldByName("APIVersion").String(), + Kind: reflect.ValueOf(chaos).Elem().FieldByName("Kind").String(), + }, + Meta: core.KubeObjectMeta{ + Namespace: reflect.ValueOf(chaos).Elem().FieldByName("Namespace").String(), + Name: reflect.ValueOf(chaos).Elem().FieldByName("Name").String(), + Labels: reflect.ValueOf(chaos).Elem().FieldByName("Labels").Interface().(map[string]string), + Annotations: reflect.ValueOf(chaos).Elem().FieldByName("Annotations").Interface().(map[string]string), + }, + Spec: reflect.ValueOf(chaos).Elem().FieldByName("Spec").Interface(), + }, + }) +} + +// @Summary Delete the specified archived experiment. +// @Description Delete the specified archived experiment. +// @Tags archives +// @Produce json +// @Param uid path string true "uid" +// @Success 200 {object} u.Response +// @Failure 500 {object} u.APIError +// @Router /archives/{uid} [delete] +func (s *Service) delete(c *gin.Context) { + var ( + err error + exp *core.Experiment + ) + + uid := c.Param("uid") + + if exp, err = s.archive.FindByUID(context.Background(), uid); err != nil { + if gorm.IsRecordNotFoundError(err) { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrBadRequest.New("the archived experiment is not found")) + } else { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + } + return + } + + if err = s.archive.Delete(context.Background(), exp); err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + } else { + if err = s.event.DeleteByUID(context.Background(), uid); err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + } else { + c.JSON(http.StatusOK, u.ResponseSuccess) + } + } +} + +// @Summary Delete the specified archived experiment. +// @Description Delete the specified archived experiment. +// @Tags archives +// @Produce json +// @Param uids query string true "uids" +// @Success 200 {object} u.Response +// @Failure 500 {object} u.APIError +// @Router /archives [delete] +func (s *Service) batchDelete(c *gin.Context) { + var ( + err error + uidSlice []string + ) + + uids := c.Query("uids") + if uids == "" { + c.Status(http.StatusBadRequest) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(errors.New("uids cannot be empty"))) + return + } + uidSlice = strings.Split(uids, ",") + + if err = s.archive.DeleteByUIDs(context.Background(), uidSlice); err != nil { + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + c.Status(http.StatusInternalServerError) + return + } + if err = s.event.DeleteByUIDs(context.Background(), uidSlice); err != nil { + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + c.Status(http.StatusInternalServerError) + return + } + + c.JSON(http.StatusOK, u.ResponseSuccess) +} + +// @Summary Get archived schedule experiments. +// @Description Get archived schedule experiments. +// @Tags archives +// @Produce json +// @Param namespace query string false "namespace" +// @Param name query string false "name" +// @Success 200 {array} types.Archive +// @Router /archives/schedules [get] +// @Failure 500 {object} u.APIError +func (s *Service) listSchedule(c *gin.Context) { + name := c.Query("name") + ns := c.Query("namespace") + + metas, err := s.archiveSchedule.ListMeta(context.Background(), ns, name, true) + if err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.NewWithNoMessage()) + return + } + + archives := make([]types.Archive, 0) + + for _, meta := range metas { + archives = append(archives, types.Archive{ + UID: meta.UID, + Kind: meta.Kind, + Namespace: meta.Namespace, + Name: meta.Name, + Created: meta.StartTime.Format(time.RFC3339), + }) + } + + c.JSON(http.StatusOK, archives) +} + +// @Summary Get the detail of an archived schedule experiment. +// @Description Get the detail of an archived schedule experiment. +// @Tags archives +// @Produce json +// @Param uid path string true "uid" +// @Success 200 {object} types.ArchiveDetail +// @Failure 500 {object} u.APIError +// @Router /archives/schedules/{uid} [get] +func (s *Service) detailSchedule(c *gin.Context) { + var ( + err error + detail types.ArchiveDetail + ) + uid := c.Param("uid") + + if uid == "" { + c.Status(http.StatusBadRequest) + _ = c.Error(u.ErrBadRequest.New("uid cannot be empty")) + return + } + + exp, err := s.archiveSchedule.FindByUID(context.Background(), uid) + if err != nil { + if gorm.IsRecordNotFoundError(err) { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrBadRequest.New("the archived schedule is not found")) + } else { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.NewWithNoMessage()) + } + return + } + + sch := &v1alpha1.Schedule{} + if err := json.Unmarshal([]byte(exp.Schedule), &sch); err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + + detail = types.ArchiveDetail{ + Archive: types.Archive{ + UID: exp.UID, + Kind: exp.Kind, + Name: exp.Name, + Namespace: exp.Namespace, + Created: exp.StartTime.Format(time.RFC3339), + }, + KubeObject: core.KubeObjectDesc{ + TypeMeta: metav1.TypeMeta{ + APIVersion: sch.APIVersion, + Kind: sch.Kind, + }, + Meta: core.KubeObjectMeta{ + Name: sch.Name, + Namespace: sch.Namespace, + Labels: sch.Labels, + Annotations: sch.Annotations, + }, + Spec: sch.Spec, + }, + } + + c.JSON(http.StatusOK, detail) +} + +// @Summary Delete the specified archived schedule. +// @Description Delete the specified archived schedule. +// @Tags archives +// @Produce json +// @Param uid path string true "uid" +// @Success 200 {object} u.Response +// @Failure 500 {object} u.APIError +// @Router /archives/schedules/{uid} [delete] +func (s *Service) deleteSchedule(c *gin.Context) { + var ( + err error + exp *core.Schedule + ) + + uid := c.Param("uid") + + if exp, err = s.archiveSchedule.FindByUID(context.Background(), uid); err != nil { + if gorm.IsRecordNotFoundError(err) { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrBadRequest.New("the archived schedule is not found")) + } else { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + } + return + } + + if err = s.archiveSchedule.Delete(context.Background(), exp); err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + } else { + if err = s.event.DeleteByUID(context.Background(), uid); err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + } else { + c.JSON(http.StatusOK, u.ResponseSuccess) + } + } +} + +// @Summary Delete the specified archived schedule. +// @Description Delete the specified archived schedule. +// @Tags archives +// @Produce json +// @Param uids query string true "uids" +// @Success 200 {object} u.Response +// @Failure 500 {object} u.APIError +// @Router /archives/schedules [delete] +func (s *Service) batchDeleteSchedule(c *gin.Context) { + var ( + err error + uidSlice []string + ) + + uids := c.Query("uids") + if uids == "" { + c.Status(http.StatusBadRequest) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(errors.New("uids cannot be empty"))) + return + } + uidSlice = strings.Split(uids, ",") + + if err = s.archiveSchedule.DeleteByUIDs(context.Background(), uidSlice); err != nil { + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + c.Status(http.StatusInternalServerError) + return + } + if err = s.event.DeleteByUIDs(context.Background(), uidSlice); err != nil { + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + c.Status(http.StatusInternalServerError) + return + } + + c.JSON(http.StatusOK, u.ResponseSuccess) +} + +// @Summary Get archived workflow. +// @Description Get archived workflow. +// @Tags archives +// @Produce json +// @Param namespace query string false "namespace" +// @Param name query string false "name" +// @Success 200 {array} types.Archive +// @Router /archives/workflows [get] +// @Failure 500 {object} u.APIError +func (s *Service) listWorkflow(c *gin.Context) { + name := c.Query("name") + ns := c.Query("namespace") + + metas, err := s.workflowStore.ListMeta(context.Background(), ns, name, true) + if err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.NewWithNoMessage()) + return + } + + archives := make([]types.Archive, 0) + + for _, meta := range metas { + archives = append(archives, types.Archive{ + UID: meta.UID, + Kind: v1alpha1.KindWorkflow, + Namespace: meta.Namespace, + Name: meta.Name, + Created: meta.CreatedAt.Format(time.RFC3339), + }) + } + + c.JSON(http.StatusOK, archives) +} + +// @Summary Get the detail of an archived workflow. +// @Description Get the detail of an archived workflow. +// @Tags archives +// @Produce json +// @Param uid path string true "uid" +// @Success 200 {object} types.ArchiveDetail +// @Failure 500 {object} u.APIError +// @Router /archives/workflows/{uid} [get] +func (s *Service) detailWorkflow(c *gin.Context) { + var ( + err error + detail types.ArchiveDetail + ) + uid := c.Param("uid") + + if uid == "" { + c.Status(http.StatusBadRequest) + _ = c.Error(u.ErrBadRequest.New("uid cannot be empty")) + return + } + + meta, err := s.workflowStore.FindByUID(context.Background(), uid) + if err != nil { + if gorm.IsRecordNotFoundError(err) { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrBadRequest.New("the archived workflow is not found")) + } else { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.NewWithNoMessage()) + } + return + } + + workflow := &v1alpha1.Workflow{} + if err := json.Unmarshal([]byte(meta.Workflow), &workflow); err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + + detail = types.ArchiveDetail{ + Archive: types.Archive{ + UID: meta.UID, + Kind: v1alpha1.KindWorkflow, + Name: meta.Name, + Namespace: meta.Namespace, + Created: meta.CreatedAt.Format(time.RFC3339), + }, + KubeObject: core.KubeObjectDesc{ + TypeMeta: metav1.TypeMeta{ + APIVersion: workflow.APIVersion, + Kind: workflow.Kind, + }, + Meta: core.KubeObjectMeta{ + Name: workflow.Name, + Namespace: workflow.Namespace, + Labels: workflow.Labels, + Annotations: workflow.Annotations, + }, + Spec: workflow.Spec, + }, + } + + c.JSON(http.StatusOK, detail) +} + +// @Summary Delete the specified archived workflow. +// @Description Delete the specified archived workflow. +// @Tags archives +// @Produce json +// @Param uid path string true "uid" +// @Success 200 {object} u.Response +// @Failure 500 {object} u.APIError +// @Router /archives/workflows/{uid} [delete] +func (s *Service) deleteWorkflow(c *gin.Context) { + var ( + err error + ) + + uid := c.Param("uid") + + if err = s.workflowStore.DeleteByUID(context.Background(), uid); err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + } else { + if err = s.event.DeleteByUID(context.Background(), uid); err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + } else { + c.JSON(http.StatusOK, u.ResponseSuccess) + } + } +} + +// @Summary Delete the specified archived workflows. +// @Description Delete the specified archived workflows. +// @Tags archives +// @Produce json +// @Param uids query string true "uids" +// @Success 200 {object} u.Response +// @Failure 500 {object} u.APIError +// @Router /archives/workflows [delete] +func (s *Service) batchDeleteWorkflow(c *gin.Context) { + var ( + err error + uidSlice []string + ) + + uids := c.Query("uids") + if uids == "" { + c.Status(http.StatusBadRequest) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(errors.New("uids cannot be empty"))) + return + } + uidSlice = strings.Split(uids, ",") + + if err = s.workflowStore.DeleteByUIDs(context.Background(), uidSlice); err != nil { + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + c.Status(http.StatusInternalServerError) + return + } + if err = s.event.DeleteByUIDs(context.Background(), uidSlice); err != nil { + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + c.Status(http.StatusInternalServerError) + return + } + + c.JSON(http.StatusOK, u.ResponseSuccess) +} diff --git a/pkg/dashboard/apiserver/archive/archive_test.go b/pkg/dashboard/apiserver/archive/archive_test.go new file mode 100644 index 0000000000..de591d2ba4 --- /dev/null +++ b/pkg/dashboard/apiserver/archive/archive_test.go @@ -0,0 +1,686 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package archive + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/gin-gonic/gin" + "github.com/jinzhu/gorm" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/pkg/errors" + "github.com/stretchr/testify/mock" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/types" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" + pkgmock "github.com/chaos-mesh/chaos-mesh/pkg/mock" +) + +// MockExperimentStore is a mock type for ExperimentStore +type MockExperimentStore struct { + mock.Mock +} + +// MockScheduleStore is a mock type for ScheduleStore +type MockScheduleStore struct { + mock.Mock +} + +func TestEvent(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "types.Archive Suite") +} + +func (m *MockExperimentStore) ListMeta(ctx context.Context, kind, namespace, name string, archived bool) ([]*core.ExperimentMeta, error) { + var res []*core.ExperimentMeta + var err error + if kind == "testKind" { + expMeta := &core.ExperimentMeta{ + UID: "testUID", + Kind: "testKind", + Name: "testName", + Namespace: "testNamespace", + Action: "testAction", + StartTime: time.Time{}, + FinishTime: &time.Time{}, + Archived: true, + } + res = append(res, expMeta) + } else { + err = errors.New("test err") + } + return res, err +} + +func (m *MockExperimentStore) FindByUID(ctx context.Context, UID string) (*core.Experiment, error) { + var res *core.Experiment + var err error + switch UID { + case "testPodChaos": + chaos := v1alpha1.PodChaos{} + jsonStr, _ := json.Marshal(chaos) + res = &core.Experiment{ + ExperimentMeta: core.ExperimentMeta{ + UID: UID, + Kind: v1alpha1.KindPodChaos, + Name: "testName", + Namespace: "testNamespace", + Action: "testAction", + StartTime: time.Time{}, + FinishTime: &time.Time{}, + Archived: true, + }, + Experiment: string(jsonStr), + } + case "testIOChaos": + chaos := v1alpha1.IOChaos{} + jsonStr, _ := json.Marshal(chaos) + res = &core.Experiment{ + ExperimentMeta: core.ExperimentMeta{ + UID: UID, + Kind: v1alpha1.KindIOChaos, + Name: "testName", + Namespace: "testNamespace", + Action: "testAction", + StartTime: time.Time{}, + FinishTime: &time.Time{}, + Archived: true, + }, + Experiment: string(jsonStr), + } + case "testNetworkChaos": + chaos := v1alpha1.NetworkChaos{} + jsonStr, _ := json.Marshal(chaos) + res = &core.Experiment{ + ExperimentMeta: core.ExperimentMeta{ + UID: UID, + Kind: v1alpha1.KindNetworkChaos, + Name: "testName", + Namespace: "testNamespace", + Action: "testAction", + StartTime: time.Time{}, + FinishTime: &time.Time{}, + Archived: true, + }, + Experiment: string(jsonStr), + } + case "testTimeChaos": + chaos := v1alpha1.TimeChaos{} + jsonStr, _ := json.Marshal(chaos) + res = &core.Experiment{ + ExperimentMeta: core.ExperimentMeta{ + UID: UID, + Kind: v1alpha1.KindTimeChaos, + Name: "testName", + Namespace: "testNamespace", + Action: "testAction", + StartTime: time.Time{}, + FinishTime: &time.Time{}, + Archived: true, + }, + Experiment: string(jsonStr), + } + case "testKernelChaos": + chaos := v1alpha1.KernelChaos{} + jsonStr, _ := json.Marshal(chaos) + res = &core.Experiment{ + ExperimentMeta: core.ExperimentMeta{ + UID: UID, + Kind: v1alpha1.KindKernelChaos, + Name: "testName", + Namespace: "testNamespace", + Action: "testAction", + StartTime: time.Time{}, + FinishTime: &time.Time{}, + Archived: true, + }, + Experiment: string(jsonStr), + } + case "testStressChaos": + chaos := v1alpha1.StressChaos{} + jsonStr, _ := json.Marshal(chaos) + res = &core.Experiment{ + ExperimentMeta: core.ExperimentMeta{ + UID: UID, + Kind: v1alpha1.KindStressChaos, + Name: "testName", + Namespace: "testNamespace", + Action: "testAction", + StartTime: time.Time{}, + FinishTime: &time.Time{}, + Archived: true, + }, + Experiment: string(jsonStr), + } + case "testOtherChaos": + res = &core.Experiment{ + ExperimentMeta: core.ExperimentMeta{ + UID: UID, + Kind: "OtherChaos", + Name: "testName", + Namespace: "testNamespace", + Action: "testAction", + StartTime: time.Time{}, + FinishTime: &time.Time{}, + Archived: true, + }, + Experiment: "", + } + case "testErrRecordNotFound": + err = gorm.ErrRecordNotFound + default: + err = errors.New("test err") + } + return res, err +} + +func (m *MockExperimentStore) FindMetaByUID(ctx context.Context, UID string) (*core.ExperimentMeta, error) { + var res *core.ExperimentMeta + var err error + switch UID { + case "tsetUID": + res = &core.ExperimentMeta{ + UID: "testUID", + Kind: "testKind", + Name: "testName", + Namespace: "testNamespace", + Action: "testAction", + StartTime: time.Time{}, + FinishTime: &time.Time{}, + Archived: true, + } + case "testErrRecordNotFound": + err = gorm.ErrRecordNotFound + default: + err = errors.New("test err") + } + return res, err +} + +func (m *MockExperimentStore) FindManagedByNamespaceName(ctx context.Context, namespace, name string) ([]*core.Experiment, error) { + panic("implement me") +} + +func (m *MockExperimentStore) Set(context.Context, *core.Experiment) error { + panic("implement me") +} + +func (m *MockExperimentStore) Archive(ctx context.Context, namespace, name string) error { + panic("implement me") +} + +func (m *MockExperimentStore) Delete(context.Context, *core.Experiment) error { + panic("implement me") +} + +func (m *MockExperimentStore) DeleteByFinishTime(context.Context, time.Duration) error { + panic("implement me") +} + +func (m *MockExperimentStore) DeleteIncompleteExperiments(context.Context) error { + panic("implement me") +} + +func (m *MockExperimentStore) DeleteByUIDs(context.Context, []string) error { + panic("implement me") +} + +func (m *MockScheduleStore) ListMeta(ctx context.Context, namespace, name string, archived bool) ([]*core.ScheduleMeta, error) { + var res []*core.ScheduleMeta + var err error + if name == "testScheduleName" { + schMeta := &core.ScheduleMeta{ + UID: "testUID", + Kind: "testKind", + Name: "testScheduleName", + Namespace: "testNamespace", + Action: "testAction", + StartTime: time.Time{}, + FinishTime: &time.Time{}, + Archived: true, + } + res = append(res, schMeta) + } else { + err = errors.New("test err") + } + return res, err +} + +func (m *MockScheduleStore) FindByUID(ctx context.Context, UID string) (*core.Schedule, error) { + var res *core.Schedule + var err error + switch UID { + case "testPodChaos": + sch := v1alpha1.Schedule{} + jsonStr, _ := json.Marshal(sch) + res = &core.Schedule{ + ScheduleMeta: core.ScheduleMeta{ + UID: UID, + Kind: v1alpha1.KindPodChaos, + Name: "testName", + Namespace: "testNamespace", + Action: "testAction", + StartTime: time.Time{}, + FinishTime: &time.Time{}, + Archived: true, + }, + Schedule: string(jsonStr), + } + case "testErrRecordNotFound": + err = gorm.ErrRecordNotFound + default: + err = errors.New("test err") + } + return res, err +} + +func (m *MockScheduleStore) FindMetaByUID(context.Context, string) (*core.ScheduleMeta, error) { + panic("implement me") +} + +func (m *MockScheduleStore) Set(context.Context, *core.Schedule) error { + panic("implement me") +} + +func (m *MockScheduleStore) Archive(ctx context.Context, namespace, name string) error { + panic("implement me") +} + +func (m *MockScheduleStore) Delete(context.Context, *core.Schedule) error { + panic("implement me") +} + +func (m *MockScheduleStore) DeleteByFinishTime(context.Context, time.Duration) error { + panic("implement me") +} + +func (m *MockScheduleStore) DeleteByUIDs(context.Context, []string) error { + panic("implement me") +} + +func (m *MockScheduleStore) DeleteIncompleteSchedules(context.Context) error { + panic("implement me") +} + +var _ = Describe("event", func() { + var router *gin.Engine + BeforeEach(func() { + pkgmock.With("AuthMiddleware", true) + + mockExpStore := new(MockExperimentStore) + mockSchStore := new(MockScheduleStore) + + s := Service{ + archive: mockExpStore, + archiveSchedule: mockSchStore, + event: nil, + conf: &config.ChaosDashboardConfig{ + ClusterScoped: true, + }, + } + router = gin.Default() + r := router.Group("/api") + endpoint := r.Group("/archives") + + endpoint.GET("", s.list) + endpoint.GET("/:uid", s.get) + + endpoint.GET("/schedules", s.listSchedule) + endpoint.GET("/schedules/:uid", s.detailSchedule) + }) + + AfterEach(func() { + // Add any setup steps that needs to be executed after each test + pkgmock.Reset("AuthMiddleware") + }) + + Context("List", func() { + It("success", func() { + response := []types.Archive{ + { + UID: "testUID", + Kind: "testKind", + Namespace: "testNamespace", + Name: "testName", + Created: time.Time{}.Format(time.RFC3339), + }, + } + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives?kind=testKind", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusOK)) + responseBody, err := json.Marshal(response) + Expect(err).ShouldNot(HaveOccurred()) + Expect(rr.Body.Bytes()).Should(Equal(responseBody)) + }) + + It("test err", func() { + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) + }) + }) + + Context("Detail", func() { + It("testPodChaos", func() { + chaos := &v1alpha1.PodChaos{} + response := types.ArchiveDetail{ + Archive: types.Archive{ + UID: "testPodChaos", + Kind: v1alpha1.KindPodChaos, + Namespace: "testNamespace", + Name: "testName", + Created: time.Time{}.Format(time.RFC3339), + }, + KubeObject: core.KubeObjectDesc{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "", + Kind: "", + }, + Meta: core.KubeObjectMeta{ + Name: "", + Namespace: "", + Labels: nil, + Annotations: nil, + }, + Spec: chaos.Spec, + }, + } + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives/testPodChaos", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusOK)) + responseBody, err := json.Marshal(response) + Expect(err).ShouldNot(HaveOccurred()) + Expect(rr.Body.Bytes()).Should(Equal(responseBody)) + }) + + It("testIOChaos", func() { + chaos := &v1alpha1.IOChaos{} + response := types.ArchiveDetail{ + Archive: types.Archive{ + UID: "testIOChaos", + Kind: v1alpha1.KindIOChaos, + Namespace: "testNamespace", + Name: "testName", + Created: time.Time{}.Format(time.RFC3339), + }, + KubeObject: core.KubeObjectDesc{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "", + Kind: "", + }, + Meta: core.KubeObjectMeta{ + Name: "", + Namespace: "", + Labels: nil, + Annotations: nil, + }, + Spec: chaos.Spec, + }, + } + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives/testIOChaos", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusOK)) + responseBody, err := json.Marshal(response) + Expect(err).ShouldNot(HaveOccurred()) + Expect(rr.Body.Bytes()).Should(Equal(responseBody)) + }) + + It("testNetworkChaos", func() { + chaos := &v1alpha1.NetworkChaos{} + response := types.ArchiveDetail{ + Archive: types.Archive{ + UID: "testNetworkChaos", + Kind: v1alpha1.KindNetworkChaos, + Namespace: "testNamespace", + Name: "testName", + Created: time.Time{}.Format(time.RFC3339), + }, + KubeObject: core.KubeObjectDesc{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "", + Kind: "", + }, + Meta: core.KubeObjectMeta{ + Name: "", + Namespace: "", + Labels: nil, + Annotations: nil, + }, + Spec: chaos.Spec, + }, + } + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives/testNetworkChaos", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusOK)) + responseBody, err := json.Marshal(response) + Expect(err).ShouldNot(HaveOccurred()) + Expect(rr.Body.Bytes()).Should(Equal(responseBody)) + }) + + It("testTimeChaos", func() { + chaos := &v1alpha1.TimeChaos{} + response := types.ArchiveDetail{ + Archive: types.Archive{ + UID: "testTimeChaos", + Kind: v1alpha1.KindTimeChaos, + Namespace: "testNamespace", + Name: "testName", + Created: time.Time{}.Format(time.RFC3339), + }, + KubeObject: core.KubeObjectDesc{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "", + Kind: "", + }, + Meta: core.KubeObjectMeta{ + Name: "", + Namespace: "", + Labels: nil, + Annotations: nil, + }, + Spec: chaos.Spec, + }, + } + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives/testTimeChaos", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusOK)) + responseBody, err := json.Marshal(response) + Expect(err).ShouldNot(HaveOccurred()) + Expect(rr.Body.Bytes()).Should(Equal(responseBody)) + }) + + It("testKernelChaos", func() { + chaos := &v1alpha1.KernelChaos{} + response := types.ArchiveDetail{ + Archive: types.Archive{ + UID: "testKernelChaos", + Kind: v1alpha1.KindKernelChaos, + Namespace: "testNamespace", + Name: "testName", + Created: time.Time{}.Format(time.RFC3339), + }, + KubeObject: core.KubeObjectDesc{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "", + Kind: "", + }, + Meta: core.KubeObjectMeta{ + Name: "", + Namespace: "", + Labels: nil, + Annotations: nil, + }, + Spec: chaos.Spec, + }, + } + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives/testKernelChaos", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusOK)) + responseBody, err := json.Marshal(response) + Expect(err).ShouldNot(HaveOccurred()) + Expect(rr.Body.Bytes()).Should(Equal(responseBody)) + }) + + It("testStressChaos", func() { + chaos := &v1alpha1.StressChaos{} + response := types.ArchiveDetail{ + Archive: types.Archive{ + UID: "testStressChaos", + Kind: v1alpha1.KindStressChaos, + Namespace: "testNamespace", + Name: "testName", + Created: time.Time{}.Format(time.RFC3339), + }, + KubeObject: core.KubeObjectDesc{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "", + Kind: "", + }, + Meta: core.KubeObjectMeta{ + Name: "", + Namespace: "", + Labels: nil, + Annotations: nil, + }, + Spec: chaos.Spec, + }, + } + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives/testStressChaos", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusOK)) + responseBody, err := json.Marshal(response) + Expect(err).ShouldNot(HaveOccurred()) + Expect(rr.Body.Bytes()).Should(Equal(responseBody)) + }) + + It("testOtherChaos", func() { + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives/testOtherChaos", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) + }) + + It("testErrRecordNotFound", func() { + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives/testErrRecordNotFound", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusNotFound)) + }) + + It("test err", func() { + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives/testErr", nil) + router.ServeHTTP(rr, request) + fmt.Println(rr.Code) + Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) + }) + }) + + Context("ListSchedule", func() { + It("success", func() { + response := []types.Archive{ + { + UID: "testUID", + Kind: "testKind", + Namespace: "testNamespace", + Name: "testScheduleName", + Created: time.Time{}.Format(time.RFC3339), + }, + } + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives/schedules?name=testScheduleName", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusOK)) + responseBody, err := json.Marshal(response) + Expect(err).ShouldNot(HaveOccurred()) + Expect(rr.Body.Bytes()).Should(Equal(responseBody)) + }) + + It("test err", func() { + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives/schedules", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) + }) + }) + + Context("DetailSchedule", func() { + It("testPodChaos", func() { + sch := &v1alpha1.Schedule{} + response := types.ArchiveDetail{ + Archive: types.Archive{ + UID: "testPodChaos", + Kind: v1alpha1.KindPodChaos, + Namespace: "testNamespace", + Name: "testName", + Created: time.Time{}.Format(time.RFC3339), + }, + KubeObject: core.KubeObjectDesc{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "", + Kind: "", + }, + Meta: core.KubeObjectMeta{ + Name: "", + Namespace: "", + Labels: nil, + Annotations: nil, + }, + Spec: sch.Spec, + }, + } + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives/schedules/testPodChaos", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusOK)) + responseBody, err := json.Marshal(response) + Expect(err).ShouldNot(HaveOccurred()) + Expect(rr.Body.Bytes()).Should(Equal(responseBody)) + }) + + It("testErrRecordNotFound", func() { + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives/schedules/testErrRecordNotFound", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) + }) + + It("test err", func() { + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/archives/schedules/testErr", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) + }) + }) +}) diff --git a/pkg/dashboard/apiserver/auth/gcp/middleware.go b/pkg/dashboard/apiserver/auth/gcp/middleware.go new file mode 100644 index 0000000000..ceb5c6ce51 --- /dev/null +++ b/pkg/dashboard/apiserver/auth/gcp/middleware.go @@ -0,0 +1,59 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gcp + +import ( + "time" + + "github.com/gin-gonic/gin" + "golang.org/x/oauth2" + + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/utils" +) + +func (s *Service) Middleware(c *gin.Context) { + ctx := c.Request.Context() + + s.logger.Info("handling gcp middleware") + if c.Request.Header.Get("X-Authorization-Method") != "gcp" { + c.Next() + return + } + + expiry, err := time.Parse(time.RFC3339, c.Request.Header.Get("X-Authorization-Expiry")) + if err != nil { + utils.SetAPIError(c, utils.ErrInternalServer.WrapWithNoMessage(err)) + return + } + oauth := s.getOauthConfig(c) + token, err := oauth.TokenSource(ctx, &oauth2.Token{ + AccessToken: c.Request.Header.Get("X-Authorization-AccessToken"), + RefreshToken: c.Request.Header.Get("X-Authorization-RefreshToken"), + Expiry: expiry, + }).Token() + + if err != nil { + utils.SetAPIError(c, utils.ErrInternalServer.WrapWithNoMessage(err)) + return + } + + s.logger.Info("setting request header") + token.SetAuthHeader(c.Request) + s.logger.Info("setting request header", "header", c.Request.Header) + setCookie(c, token) + + c.Next() +} diff --git a/pkg/dashboard/apiserver/auth/gcp/service.go b/pkg/dashboard/apiserver/auth/gcp/service.go new file mode 100644 index 0000000000..5f7e6e5c07 --- /dev/null +++ b/pkg/dashboard/apiserver/auth/gcp/service.go @@ -0,0 +1,114 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gcp + +import ( + "net/http" + "net/url" + "path" + + "github.com/gin-gonic/gin" + "github.com/go-logr/logr" + "golang.org/x/oauth2" + "golang.org/x/oauth2/google" + + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/utils" +) + +type Service struct { + clientId string + clientSecret string + rootUrl *url.URL + logger logr.Logger +} + +// NewService returns an experiment service instance. +func NewService( + conf *config.ChaosDashboardConfig, + logger logr.Logger, +) (*Service, error) { + rootUrl, err := url.Parse(conf.RootUrl) + if err != nil { + return nil, err + } + if rootUrl.Path == "" { + rootUrl.Path = "/" + } + + return &Service{ + clientId: conf.GcpClientId, + clientSecret: conf.GcpClientSecret, + rootUrl: rootUrl, + logger: logger.WithName("gcp auth api"), + }, nil +} + +// Register mounts HTTP handler on the mux. +func Register(r *gin.RouterGroup, s *Service, conf *config.ChaosDashboardConfig) { + // If the gcp security mode is not set, just skip the registration + if !conf.GcpSecurityMode { + return + } + + r.Use(s.Middleware) + + endpoint := r.Group("/auth/gcp") + endpoint.GET("/redirect", s.handleRedirect) + endpoint.GET("/callback", s.authCallback) +} + +func (s *Service) getOauthConfig(c *gin.Context) oauth2.Config { + url := *s.rootUrl + url.Path = path.Join(s.rootUrl.Path, "./api/auth/gcp/callback") + + return oauth2.Config{ + ClientID: s.clientId, + ClientSecret: s.clientSecret, + RedirectURL: url.String(), + Scopes: []string{ + "email", "profile", + "https://www.googleapis.com/auth/userinfo.email", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/cloud-platform", + }, + Endpoint: google.Endpoint, + } +} + +func (s *Service) handleRedirect(c *gin.Context) { + oauth := s.getOauthConfig(c) + uri := oauth.AuthCodeURL("", oauth2.AccessTypeOffline, oauth2.ApprovalForce) + + c.Redirect(http.StatusFound, uri) +} + +func (s *Service) authCallback(c *gin.Context) { + ctx := c.Request.Context() + + oauth := s.getOauthConfig(c) + oauth2Token, err := oauth.Exchange(ctx, c.Request.URL.Query().Get("code"), oauth2.AccessTypeOffline, oauth2.ApprovalForce) + if err != nil { + utils.SetAPIError(c, utils.ErrInternalServer.WrapWithNoMessage(err)) + return + } + + setCookie(c, oauth2Token) + target := url.URL{ + Path: "/", + } + c.Redirect(http.StatusFound, target.RequestURI()) +} diff --git a/pkg/dashboard/apiserver/auth/gcp/utils.go b/pkg/dashboard/apiserver/auth/gcp/utils.go new file mode 100644 index 0000000000..295d60b5d3 --- /dev/null +++ b/pkg/dashboard/apiserver/auth/gcp/utils.go @@ -0,0 +1,29 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gcp + +import ( + "time" + + "github.com/gin-gonic/gin" + "golang.org/x/oauth2" +) + +func setCookie(c *gin.Context, token *oauth2.Token) { + c.SetCookie("access_token", token.AccessToken, 0, "", "", false, false) + c.SetCookie("refresh_token", token.RefreshToken, 0, "", "", false, false) + c.SetCookie("expiry", token.Expiry.Format(time.RFC3339), 0, "", "", false, false) +} diff --git a/pkg/dashboard/apiserver/common/common.go b/pkg/dashboard/apiserver/common/common.go new file mode 100644 index 0000000000..a87161679d --- /dev/null +++ b/pkg/dashboard/apiserver/common/common.go @@ -0,0 +1,584 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package common + +import ( + "context" + "crypto/rand" + "fmt" + "math/big" + "net/http" + "sort" + "strings" + + "github.com/gin-gonic/gin" + "github.com/go-logr/logr" + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/clientpool" + "github.com/chaos-mesh/chaos-mesh/pkg/config" + apiservertypes "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/types" + u "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/utils" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic/namespace" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/physicalmachine" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/pod" +) + +const ( + roleManager = "manager" + roleViewer = "viewer" + + serviceAccountTemplate = `kind: ServiceAccount +apiVersion: v1 +metadata: + namespace: %s + name: %s +` + roleTemplate = `kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + namespace: %s + name: %s +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["chaos-mesh.org"] + resources: [ "*" ] + verbs: [%s] +` + clusterRoleTemplate = `kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: %s +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["chaos-mesh.org"] + resources: [ "*" ] + verbs: [%s] +` + roleBindingTemplate = `apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: %s + namespace: %s +subjects: +- kind: ServiceAccount + name: %s + namespace: %s +roleRef: + kind: Role + name: %s + apiGroup: rbac.authorization.k8s.io +` + clusterRoleBindingTemplate = `apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: %s +subjects: +- kind: ServiceAccount + name: %s + namespace: %s +roleRef: + kind: ClusterRole + name: %s + apiGroup: rbac.authorization.k8s.io +` +) + +// Service defines a handler service for cluster common objects. +type Service struct { + // this kubeCli use the local token, used for list namespace of the K8s cluster + kubeCli client.Client + conf *config.ChaosDashboardConfig + logger logr.Logger +} + +// NewService returns an experiment service instance. +func NewService( + conf *config.ChaosDashboardConfig, + kubeCli client.Client, + logger logr.Logger, +) *Service { + return &Service{ + conf: conf, + kubeCli: kubeCli, + logger: logger.WithName("common-api"), + } +} + +// Register mounts our HTTP handler on the mux. +func Register(r *gin.RouterGroup, s *Service) { + endpoint := r.Group("/common") + + endpoint.POST("/pods", s.listPods) + endpoint.GET("/namespaces", s.listNamespaces) + endpoint.GET("/chaos-available-namespaces", s.getChaosAvailableNamespaces) + endpoint.GET("/kinds", s.getKinds) + endpoint.GET("/labels", s.getLabels) + endpoint.GET("/annotations", s.getAnnotations) + endpoint.GET("/config", s.getConfig) + endpoint.GET("/rbac-config", s.getRbacConfig) + endpoint.POST("/physicalmachines", s.listPhysicalMachines) + endpoint.GET("/physicalmachine-labels", s.getPhysicalMachineLabels) + endpoint.GET("/physicalmachine-annotations", s.getPhysicalMachineAnnotations) +} + +// @Summary Get pods from Kubernetes cluster. +// @Description Get pods from Kubernetes cluster. +// @Tags common +// @Produce json +// @Param request body v1alpha1.PodSelectorSpec true "Request body" +// @Success 200 {array} apiservertypes.Pod +// @Failure 500 {object} u.APIError +// @Router /common/pods [post] +func (s *Service) listPods(c *gin.Context) { + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + _ = c.Error(u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + + selector := v1alpha1.PodSelectorSpec{} + if err := c.ShouldBindJSON(&selector); err != nil { + c.Status(http.StatusBadRequest) + _ = c.Error(u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + ctx := context.TODO() + filteredPods, err := pod.SelectPods(ctx, kubeCli, nil, selector, s.conf.ClusterScoped, s.conf.TargetNamespace, s.conf.EnableFilterNamespace) + if err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + + pods := make([]apiservertypes.Pod, 0, len(filteredPods)) + for _, pod := range filteredPods { + pods = append(pods, apiservertypes.Pod{ + Name: pod.Name, + IP: pod.Status.PodIP, + Namespace: pod.Namespace, + State: string(pod.Status.Phase), + }) + } + + c.JSON(http.StatusOK, pods) +} + +// @Summary Get all namespaces from Kubernetes cluster. +// @Description Get all from Kubernetes cluster. +// @Deprecated This API only works within cluster scoped mode. Please use /common/chaos-available-namespaces instead. +// @Tags common +// @Produce json +// @Success 200 {array} string +// @Router /common/namespaces [get] +// @Failure 500 {object} u.APIError +func (s *Service) listNamespaces(c *gin.Context) { + var namespaces sort.StringSlice + + var nsList v1.NamespaceList + if err := s.kubeCli.List(context.Background(), &nsList); err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + namespaces = make(sort.StringSlice, 0, len(nsList.Items)) + for _, ns := range nsList.Items { + namespaces = append(namespaces, ns.Name) + } + + sort.Sort(namespaces) + c.JSON(http.StatusOK, namespaces) +} + +// @Summary Get all namespaces which could inject chaos(explosion scope) from Kubernetes cluster. +// @Description Get all namespaces which could inject chaos(explosion scope) from Kubernetes cluster. +// @Tags common +// @Produce json +// @Success 200 {array} string +// @Router /common/chaos-available-namespaces [get] +// @Failure 500 {object} u.APIError +func (s *Service) getChaosAvailableNamespaces(c *gin.Context) { + var namespaces sort.StringSlice + + if s.conf.ClusterScoped { + var nsList v1.NamespaceList + if err := s.kubeCli.List(context.Background(), &nsList); err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + namespaces = make(sort.StringSlice, 0, len(nsList.Items)) + for _, ns := range nsList.Items { + if s.conf.EnableFilterNamespace && !namespace.CheckNamespace(context.TODO(), s.kubeCli, ns.Name, s.logger) { + continue + } + namespaces = append(namespaces, ns.Name) + } + } else { + namespaces = append(namespaces, s.conf.TargetNamespace) + } + + sort.Sort(namespaces) + c.JSON(http.StatusOK, namespaces) +} + +// @Summary Get all chaos kinds from Kubernetes cluster. +// @Description Get all chaos kinds from Kubernetes cluster. +// @Tags common +// @Produce json +// @Success 200 {array} string +// @Router /common/kinds [get] +// @Failure 500 {object} u.APIError +func (s *Service) getKinds(c *gin.Context) { + var kinds []string + + allKinds := v1alpha1.AllKinds() + for name := range allKinds { + kinds = append(kinds, name) + } + + sort.Strings(kinds) + c.JSON(http.StatusOK, kinds) +} + +// @Summary Get the labels of the pods in the specified namespace from Kubernetes cluster. +// @Description Get the labels of the pods in the specified namespace from Kubernetes cluster. +// @Tags common +// @Produce json +// @Param podNamespaceList query string true "The pod's namespace list, split by ," +// @Success 200 {object} u.MapStringSliceResponse +// @Router /common/labels [get] +// @Failure 500 {object} u.APIError +func (s *Service) getLabels(c *gin.Context) { + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + _ = c.Error(u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + + podNamespaceList := c.Query("podNamespaceList") + + if len(podNamespaceList) == 0 { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(errors.New("podNamespaceList is required"))) + return + } + + selector := v1alpha1.PodSelectorSpec{} + nsList := strings.Split(podNamespaceList, ",") + selector.Namespaces = nsList + + ctx := context.TODO() + filteredPods, err := pod.SelectPods(ctx, kubeCli, nil, selector, s.conf.ClusterScoped, s.conf.TargetNamespace, s.conf.EnableFilterNamespace) + if err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + + labels := make(u.MapStringSliceResponse) + for _, pod := range filteredPods { + for k, v := range pod.Labels { + if _, ok := labels[k]; ok { + if !inSlice(v, labels[k]) { + labels[k] = append(labels[k], v) + } + } else { + labels[k] = []string{v} + } + } + } + + c.JSON(http.StatusOK, labels) +} + +// @Summary Get the annotations of the pods in the specified namespace from Kubernetes cluster. +// @Description Get the annotations of the pods in the specified namespace from Kubernetes cluster. +// @Tags common +// @Produce json +// @Param podNamespaceList query string true "The pod's namespace list, split by ," +// @Success 200 {object} u.MapStringSliceResponse +// @Router /common/annotations [get] +// @Failure 500 {object} u.APIError +func (s *Service) getAnnotations(c *gin.Context) { + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + _ = c.Error(u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + + podNamespaceList := c.Query("podNamespaceList") + + if len(podNamespaceList) == 0 { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(errors.New("podNamespaceList is required"))) + return + } + + selector := v1alpha1.PodSelectorSpec{} + nsList := strings.Split(podNamespaceList, ",") + selector.Namespaces = nsList + + ctx := context.TODO() + filteredPods, err := pod.SelectPods(ctx, kubeCli, nil, selector, s.conf.ClusterScoped, s.conf.TargetNamespace, s.conf.EnableFilterNamespace) + if err != nil { + c.Status(http.StatusInternalServerError) + _ = c.Error(u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + + annotations := make(u.MapStringSliceResponse) + for _, pod := range filteredPods { + for k, v := range pod.Annotations { + if _, ok := annotations[k]; ok { + if !inSlice(v, annotations[k]) { + annotations[k] = append(annotations[k], v) + } + } else { + annotations[k] = []string{v} + } + } + } + + c.JSON(http.StatusOK, annotations) +} + +// @Summary Get the config of Dashboard. +// @Description Get the config of Dashboard. +// @Tags common +// @Produce json +// @Success 200 {object} config.ChaosDashboardConfig +// @Router /common/config [get] +// @Failure 500 {object} u.APIError +func (s *Service) getConfig(c *gin.Context) { + c.JSON(http.StatusOK, s.conf) +} + +// @Summary Get the rbac config according to the user's choice. +// @Description Get the rbac config according to the user's choice. +// @Tags common +// @Produce json +// @Param namespace query string false "The namespace of RBAC" +// @Param role query string false "The role of RBAC" +// @Success 200 {object} map[string]string +// @Router /common/rbac-config [get] +// @Failure 500 {object} u.APIError +func (s *Service) getRbacConfig(c *gin.Context) { + namespace := c.Query("namespace") + roleType := c.Query("role") + + var serviceAccount, role, roleBinding, verbs string + randomStr := randomStringWithCharset(5, charset) + + scope := namespace + if len(namespace) == 0 { + namespace = "default" + scope = "cluster" + } + if roleType == roleManager { + verbs = `"get", "list", "watch", "create", "delete", "patch", "update"` + } else if roleType == roleViewer { + verbs = `"get", "list", "watch"` + } else { + c.Status(http.StatusBadRequest) + _ = c.Error(u.ErrBadRequest.WrapWithNoMessage(errors.New("roleType is neither manager nor viewer"))) + return + } + + serviceAccountName := fmt.Sprintf("account-%s-%s-%s", scope, roleType, randomStr) + roleName := fmt.Sprintf("role-%s-%s-%s", scope, roleType, randomStr) + roleBindingName := fmt.Sprintf("bind-%s-%s-%s", scope, roleType, randomStr) + + serviceAccount = fmt.Sprintf(serviceAccountTemplate, namespace, serviceAccountName) + if scope == "cluster" { + role = fmt.Sprintf(clusterRoleTemplate, roleName, verbs) + roleBinding = fmt.Sprintf(clusterRoleBindingTemplate, roleBindingName, serviceAccountName, namespace, roleName) + } else { + role = fmt.Sprintf(roleTemplate, namespace, roleName, verbs) + roleBinding = fmt.Sprintf(roleBindingTemplate, roleBindingName, namespace, serviceAccountName, namespace, roleName) + } + + rbacMap := make(map[string]string) + rbacMap[serviceAccountName] = serviceAccount + "\n---\n" + role + "\n---\n" + roleBinding + + c.JSON(http.StatusOK, rbacMap) +} + +// @Summary Get physicalMachines from Kubernetes cluster. +// @Description Get physicalMachines from Kubernetes cluster. +// @Tags common +// @Produce json +// @Param request body v1alpha1.PhysicalMachineSelectorSpec true "Request body" +// @Success 200 {array} apiservertypes.PhysicalMachine +// @Failure 500 {object} u.APIError +// @Router /common/physicalmachines [post] +func (s *Service) listPhysicalMachines(c *gin.Context) { + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + + selector := v1alpha1.PhysicalMachineSelectorSpec{} + if err := c.ShouldBindJSON(&selector); err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + ctx := context.TODO() + filtered, err := physicalmachine.SelectPhysicalMachines(ctx, kubeCli, nil, selector, s.conf.ClusterScoped, s.conf.TargetNamespace, s.conf.EnableFilterNamespace, s.logger) + if err != nil { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + + physicalMachines := make([]apiservertypes.PhysicalMachine, 0, len(filtered)) + for _, pm := range filtered { + physicalMachines = append(physicalMachines, apiservertypes.PhysicalMachine{ + Name: pm.Name, + Namespace: pm.Namespace, + Address: pm.Spec.Address, + }) + } + + c.JSON(http.StatusOK, physicalMachines) +} + +// @Summary Get the labels of the physicalMachines in the specified namespace from Kubernetes cluster. +// @Description Get the labels of the physicalMachines in the specified namespace from Kubernetes cluster. +// @Tags common +// @Produce json +// @Param physicalMachineNamespaceList query string true "The physicalMachine's namespace list, split by ," +// @Success 200 {object} u.MapStringSliceResponse +// @Router /common/physicalmachine-labels [get] +// @Failure 500 {object} u.APIError +func (s *Service) getPhysicalMachineLabels(c *gin.Context) { + + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + + physicalMachineNamespaceList := c.Query("physicalMachineNamespaceList") + + if len(physicalMachineNamespaceList) == 0 { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(errors.New("physicalMachineNamespaceList is required"))) + return + } + + selector := v1alpha1.PhysicalMachineSelectorSpec{} + nsList := strings.Split(physicalMachineNamespaceList, ",") + selector.Namespaces = nsList + + ctx := context.TODO() + filtered, err := physicalmachine.SelectPhysicalMachines(ctx, kubeCli, nil, selector, s.conf.ClusterScoped, s.conf.TargetNamespace, s.conf.EnableFilterNamespace, s.logger) + if err != nil { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + + labels := make(u.MapStringSliceResponse) + for _, obj := range filtered { + for k, v := range obj.Labels { + if _, ok := labels[k]; ok { + if !inSlice(v, labels[k]) { + labels[k] = append(labels[k], v) + } + } else { + labels[k] = []string{v} + } + } + } + + c.JSON(http.StatusOK, labels) +} + +// @Summary Get the annotations of the physicalMachines in the specified namespace from Kubernetes cluster. +// @Description Get the annotations of the physicalMachines in the specified namespace from Kubernetes cluster. +// @Tags common +// @Produce json +// @Param physicalMachineNamespaceList query string true "The physicalMachine's namespace list, split by ," +// @Success 200 {object} u.MapStringSliceResponse +// @Router /common/physicalmachine-annotations [get] +// @Failure 500 {object} u.APIError +func (s *Service) getPhysicalMachineAnnotations(c *gin.Context) { + + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + + physicalMachineNamespaceList := c.Query("physicalMachineNamespaceList") + + if len(physicalMachineNamespaceList) == 0 { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(errors.New("physicalMachineNamespaceList is required"))) + return + } + selector := v1alpha1.PhysicalMachineSelectorSpec{} + nsList := strings.Split(physicalMachineNamespaceList, ",") + selector.Namespaces = nsList + + ctx := context.TODO() + filtered, err := physicalmachine.SelectPhysicalMachines(ctx, kubeCli, nil, selector, s.conf.ClusterScoped, s.conf.TargetNamespace, s.conf.EnableFilterNamespace, s.logger) + if err != nil { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + + annotations := make(u.MapStringSliceResponse) + for _, obj := range filtered { + for k, v := range obj.Annotations { + if _, ok := annotations[k]; ok { + if !inSlice(v, annotations[k]) { + annotations[k] = append(annotations[k], v) + } + } else { + annotations[k] = []string{v} + } + } + } + + c.JSON(http.StatusOK, annotations) +} + +// inSlice checks given string in string slice or not. +func inSlice(v string, sl []string) bool { + for _, vv := range sl { + if vv == v { + return true + } + } + return false +} + +const charset = "abcdefghijklmnopqrstuvwxyz" + +func randomStringWithCharset(length int, charset string) string { + b := make([]byte, length) + for i := range b { + num, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset)))) + b[i] = charset[num.Int64()] + } + return string(b) +} diff --git a/pkg/dashboard/apiserver/event/event.go b/pkg/dashboard/apiserver/event/event.go new file mode 100644 index 0000000000..7dd2269706 --- /dev/null +++ b/pkg/dashboard/apiserver/event/event.go @@ -0,0 +1,285 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package event + +import ( + "context" + "net/http" + "sort" + "strconv" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-logr/logr" + "github.com/jinzhu/gorm" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/clientpool" + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + u "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/utils" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +// Service defines a handler service for events. +type Service struct { + event core.EventStore + workflowStore core.WorkflowStore + conf *config.ChaosDashboardConfig + logger logr.Logger +} + +func NewService( + event core.EventStore, + workflowStore core.WorkflowStore, + conf *config.ChaosDashboardConfig, + logger logr.Logger, +) *Service { + return &Service{ + event: event, + workflowStore: workflowStore, + conf: conf, + logger: logger.WithName("events"), + } +} + +// Register events RouterGroup. +func Register(r *gin.RouterGroup, s *Service) { + endpoint := r.Group("/events") + endpoint.Use(func(c *gin.Context) { + u.AuthMiddleware(c, s.conf) + }) + + endpoint.GET("", s.list) + endpoint.GET("/:id", s.get) + endpoint.GET("/workflow/:uid", s.cascadeFetchEventsForWorkflow) +} + +const layout = "2006-01-02 15:04:05" + +// @Summary list events. +// @Description Get events from db. +// @Tags events +// @Produce json +// @Param created_at query string false "The create time of events" +// @Param name query string false "The name of the object" +// @Param namespace query string false "The namespace of the object" +// @Param object_id query string false "The UID of the object" +// @Param kind query string false "kind" Enums(PodChaos, IOChaos, NetworkChaos, TimeChaos, KernelChaos, StressChaos, AWSChaos, GCPChaos, DNSChaos, Schedule) +// @Param limit query number false "The max length of events list" +// @Success 200 {array} core.Event +// @Failure 500 {object} u.APIError +// @Router /events [get] +func (s *Service) list(c *gin.Context) { + ns := c.Query("namespace") + + if ns == "" && !s.conf.ClusterScoped && s.conf.TargetNamespace != "" { + ns = s.conf.TargetNamespace + + s.logger.V(1).Info("Replace query namespace", "ns", ns) + } + + start, _ := time.Parse(time.RFC3339, c.Query("start")) + end, _ := time.Parse(time.RFC3339, c.Query("end")) + + filter := core.Filter{ + ObjectID: c.Query("object_id"), + Start: start.UTC().Format(layout), + End: end.UTC().Format(layout), + Namespace: ns, + Name: c.Query("name"), + Kind: c.Query("kind"), + Limit: c.Query("limit"), + } + + events, err := s.event.ListByFilter(context.Background(), filter) + if err != nil { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + + return + } + + c.JSON(http.StatusOK, events) +} + +// @Summary cascadeFetchEventsForWorkflow list all events for Workflow and related WorkflowNode. +// @Description list all events for Workflow and related WorkflowNode. +// @Tags events +// @Produce json +// @Param uid path string true "The UID of the Workflow" +// @Param namespace query string false "The namespace of the object" +// @Param limit query number false "The max length of events list" +// @Success 200 {array} core.Event +// @Failure 500 {object} u.APIError +// @Router /events/workflow/{uid} [get] +func (s *Service) cascadeFetchEventsForWorkflow(c *gin.Context) { + ctx := c.Request.Context() + ns := c.Query("namespace") + uid := c.Param("uid") + start, _ := time.Parse(time.RFC3339, c.Query("start")) + end, _ := time.Parse(time.RFC3339, c.Query("end")) + limit := 0 + limitString := c.Query("limit") + if len(limitString) > 0 { + parsedLimit, err := strconv.Atoi(limitString) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.Wrap(err, "parameter limit should be a integer")) + return + } + limit = parsedLimit + } + + if ns == "" && !s.conf.ClusterScoped && s.conf.TargetNamespace != "" { + ns = s.conf.TargetNamespace + + s.logger.V(1).Info("Replace query namespace", "ns", ns) + } + + // we should fetch the events for Workflow and related WorkflowNode, so we need namespaced name at first + workflowEntity, err := s.workflowStore.FindByUID(ctx, uid) + if err != nil { + if gorm.IsRecordNotFoundError(err) { + u.SetAPIError(c, u.ErrNotFound.Wrap(err, "this requested workflow is not found, uid: %s", uid)) + } else { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + } + return + } + + // if workflow has been archived, the Workflow CR and WorkflowNode CR also has been deleted from kubernetes, it's + // no way to "cascade fetch" anymore + if workflowEntity.Archived { + u.SetAPIError(c, u.ErrBadRequest.New("this requested workflow already been archived, can not list events for it")) + return + } + + kubeClient, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + + // fetch all related WorkflowNodes + workflowNodeList := v1alpha1.WorkflowNodeList{} + controlledByThisWorkflow, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{MatchLabels: map[string]string{ + v1alpha1.LabelWorkflow: workflowEntity.Name, + }}) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + err = kubeClient.List(ctx, &workflowNodeList, &client.ListOptions{ + Namespace: ns, + LabelSelector: controlledByThisWorkflow, + }) + if err != nil { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + + result := make([]*core.Event, 0) + // fetch events of Workflow + eventsForWorkflow, err := s.event.ListByFilter(ctx, core.Filter{ + ObjectID: uid, + Namespace: ns, + Start: start.UTC().Format(layout), + End: end.UTC().Format(layout), + }) + if err != nil { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + result = append(result, eventsForWorkflow...) + + // fetch all events of WorkflowNodes + for _, workflowNode := range workflowNodeList.Items { + eventsForWorkflowNode, err := s.event.ListByFilter(ctx, core.Filter{ + Namespace: ns, + Name: workflowNode.GetName(), + Start: start.UTC().Format(layout), + End: end.UTC().Format(layout), + }) + if err != nil { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + result = append(result, eventsForWorkflowNode...) + } + + // sort by CreatedAt + sort.Slice(result, func(i, j int) bool { + return result[i].CreatedAt.UnixNano() > result[j].CreatedAt.UnixNano() + }) + + if limit > 0 && len(result) > limit { + c.JSON(http.StatusOK, result[:limit]) + return + } + c.JSON(http.StatusOK, result) +} + +// @Summary Get an event. +// @Description Get the event from db by ID. +// @Tags events +// @Produce json +// @Param id path uint true "The event ID" +// @Success 200 {object} core.Event +// @Failure 400 {object} u.APIError +// @Failure 404 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /events/{id} [get] +func (s *Service) get(c *gin.Context) { + id, ns := c.Param("id"), c.Query("namespace") + + if id == "" { + u.SetAPIError(c, u.ErrBadRequest.New("ID cannot be empty")) + + return + } + + intID, err := strconv.Atoi(id) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.New("ID is not a number")) + + return + } + + if ns == "" && !s.conf.ClusterScoped && s.conf.TargetNamespace != "" { + ns = s.conf.TargetNamespace + + s.logger.V(1).Info("Replace query namespace", "ns", ns) + } + + event, err := s.event.Find(context.Background(), uint(intID)) + if err != nil { + if gorm.IsRecordNotFoundError(err) { + u.SetAPIError(c, u.ErrNotFound.New("Event "+id+" not found")) + } else { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + } + + return + } + + if len(ns) != 0 && event.Namespace != ns { + u.SetAPIError(c, u.ErrInternalServer.New("The namespace of event %s is %s instead of the %s in the request", id, event.Namespace, ns)) + + return + } + + c.JSON(http.StatusOK, event) +} diff --git a/pkg/dashboard/apiserver/event/event_test.go b/pkg/dashboard/apiserver/event/event_test.go new file mode 100644 index 0000000000..71733df1e5 --- /dev/null +++ b/pkg/dashboard/apiserver/event/event_test.go @@ -0,0 +1,200 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package event + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/gin-gonic/gin" + "github.com/jinzhu/gorm" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/pkg/errors" + "github.com/stretchr/testify/mock" + + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" + pkgmock "github.com/chaos-mesh/chaos-mesh/pkg/mock" +) + +// MockEventService is a mock of core.EventStore +type MockEventService struct { + mock.Mock +} + +func (m *MockEventService) List(context.Context) ([]*core.Event, error) { + panic("implement me") +} + +func (m *MockEventService) ListByExperiment(context.Context, string, string, string) ([]*core.Event, error) { + panic("implement me") +} + +func (m *MockEventService) ListByUID(context.Context, string) ([]*core.Event, error) { + panic("implement me") +} + +func (m *MockEventService) ListByUIDs(context.Context, []string) ([]*core.Event, error) { + panic("implement me") +} + +func (m *MockEventService) ListByFilter(ctx context.Context, filter core.Filter) ([]*core.Event, error) { + var res []*core.Event + var err error + if filter.ObjectID == "testUID" { + event := &core.Event{ + ID: 0, + CreatedAt: time.Time{}, + Kind: "testKind", + Type: "testType", + Reason: "testReason", + Message: "testMessage", + Name: "testName", + Namespace: "testNamespace", + ObjectID: "testUID", + } + res = append(res, event) + } else { + err = errors.New("test err") + } + return res, err +} + +func (m *MockEventService) Find(_ context.Context, id uint) (*core.Event, error) { + var res *core.Event + var err error + if id == 0 { + res = &core.Event{ + ID: 0, + CreatedAt: time.Time{}, + Kind: "testKind", + Type: "testType", + Reason: "testReason", + Message: "testMessage", + Name: "testName", + Namespace: "testNamespace", + ObjectID: "testUID", + } + } else { + if id == 1 { + err = gorm.ErrRecordNotFound + } else { + err = errors.New("test err") + } + } + return res, err +} + +func (m *MockEventService) Create(context.Context, *core.Event) error { + panic("implement me") +} + +func (m *MockEventService) DeleteByUIDs(context.Context, []string) error { + panic("implement me") +} + +func (m *MockEventService) DeleteByCreateTime(context.Context, time.Duration) error { + panic("implement me") +} + +func (m *MockEventService) DeleteByUID(context.Context, string) error { + panic("implement me") +} + +func (m *MockEventService) DeleteByTime(context.Context, string, string) error { + panic("implement me") +} + +func (m *MockEventService) DeleteByDuration(context.Context, time.Duration) error { + panic("implement me") +} + +func TestEvent(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Event Suite") +} + +var _ = Describe("event", func() { + var router *gin.Engine + BeforeEach(func() { + pkgmock.With("AuthMiddleware", true) + + mockes := new(MockEventService) + + var s = Service{ + conf: &config.ChaosDashboardConfig{ + ClusterScoped: true, + }, + event: mockes, + } + router = gin.Default() + r := router.Group("/api") + endpoint := r.Group("/events") + endpoint.GET("", s.list) + endpoint.GET("/:id", s.get) + }) + + AfterEach(func() { + // Add any teardown steps that needs to be executed after each test + pkgmock.Reset("AuthMiddleware") + }) + + Context("ListEvents", func() { + It("success", func() { + response := []*core.Event{ + { + ID: 0, + CreatedAt: time.Time{}, + Kind: "testKind", + Type: "testType", + Reason: "testReason", + Message: "testMessage", + Name: "testName", + Namespace: "testNamespace", + ObjectID: "testUID", + }, + } + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/events?object_id=testUID", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusOK)) + responseBody, err := json.Marshal(response) + Expect(err).ShouldNot(HaveOccurred()) + Expect(rr.Body.Bytes()).Should(Equal(responseBody)) + }) + + It("test err", func() { + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/events?object_id=err", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusInternalServerError)) + }) + }) + + Context("GetEvent", func() { + It("not found", func() { + rr := httptest.NewRecorder() + request, _ := http.NewRequest(http.MethodGet, "/api/events/1", nil) + router.ServeHTTP(rr, request) + Expect(rr.Code).Should(Equal(http.StatusNotFound)) + }) + }) +}) diff --git a/pkg/dashboard/apiserver/experiment/experiment.go b/pkg/dashboard/apiserver/experiment/experiment.go new file mode 100644 index 0000000000..5e7c5243f1 --- /dev/null +++ b/pkg/dashboard/apiserver/experiment/experiment.go @@ -0,0 +1,620 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package experiment + +import ( + "context" + "encoding/json" + "net/http" + "reflect" + "sort" + "strings" + "sync" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-logr/logr" + "github.com/jinzhu/gorm" + "golang.org/x/sync/errgroup" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/common/finalizers" + "github.com/chaos-mesh/chaos-mesh/pkg/clientpool" + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + apiservertypes "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/types" + u "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/utils" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" + "github.com/chaos-mesh/chaos-mesh/pkg/status" +) + +// Service defines a handler service for experiments. +type Service struct { + archive core.ExperimentStore + event core.EventStore + config *config.ChaosDashboardConfig + scheme *runtime.Scheme + log logr.Logger +} + +func NewService( + archive core.ExperimentStore, + event core.EventStore, + config *config.ChaosDashboardConfig, + scheme *runtime.Scheme, + log logr.Logger, +) *Service { + return &Service{ + archive: archive, + event: event, + config: config, + scheme: scheme, + log: log, + } +} + +// Register experiments RouterGroup. +func Register(r *gin.RouterGroup, s *Service) { + endpoint := r.Group("/experiments") + + endpoint.GET("", s.list) + endpoint.POST("", s.create) + endpoint.GET("/:uid", s.get) + endpoint.DELETE("/:uid", s.delete) + endpoint.DELETE("", s.batchDelete) + endpoint.PUT("/pause/:uid", s.pause) + endpoint.PUT("/start/:uid", s.start) + endpoint.GET("/state", s.state) +} + +// @Summary List chaos experiments. +// @Description Get chaos experiments from k8s clusters in real time. +// @Tags experiments +// @Produce json +// @Param namespace query string false "filter exps by namespace" +// @Param name query string false "filter exps by name" +// @Param kind query string false "filter exps by kind" Enums(PodChaos, NetworkChaos, IOChaos, StressChaos, KernelChaos, TimeChaos, DNSChaos, AWSChaos, GCPChaos, JVMChaos, HTTPChaos) +// @Param status query string false "filter exps by status" Enums(Injecting, Running, Finished, Paused) +// @Success 200 {array} apiservertypes.Experiment +// @Failure 400 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /experiments [get] +func (s *Service) list(c *gin.Context) { + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + ns, name, kind := c.Query("namespace"), c.Query("name"), c.Query("kind") + + if ns == "" && !s.config.ClusterScoped && s.config.TargetNamespace != "" { + ns = s.config.TargetNamespace + + s.log.V(1).Info("Replace query namespace", "ns", ns) + } + + exps := make([]*apiservertypes.Experiment, 0) + for k, chaosKind := range v1alpha1.AllKinds() { + if kind != "" && k != kind { + continue + } + + list := chaosKind.SpawnList() + if err := kubeCli.List(context.Background(), list, &client.ListOptions{Namespace: ns}); err != nil { + u.SetAPImachineryError(c, err) + + return + } + + for _, item := range list.GetItems() { + chaosName := item.GetName() + + if name != "" && chaosName != name { + continue + } + + exps = append(exps, &apiservertypes.Experiment{ + ObjectBase: core.ObjectBase{ + Namespace: item.GetNamespace(), + Name: chaosName, + Kind: item.GetObjectKind().GroupVersionKind().Kind, + UID: string(item.GetUID()), + Created: item.GetCreationTimestamp().Format(time.RFC3339), + }, + Status: status.GetChaosStatus(item.(v1alpha1.InnerObject)), + }) + } + } + + sort.Slice(exps, func(i, j int) bool { + return exps[i].Created > exps[j].Created + }) + + c.JSON(http.StatusOK, exps) +} + +// @Summary Create a new chaos experiment. +// @Description Pass a JSON object to create a new chaos experiment. The schema for JSON is the same as the YAML schema for the Kubernetes object. +// @Tags experiments +// @Accept json +// @Produce json +// @Param chaos body map[string]interface{} true "the chaos definition" +// @Success 200 {object} map[string]interface{} +// @Failure 400 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /experiments [post] +func (s *Service) create(c *gin.Context) { + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + var exp map[string]interface{} + if err = u.ShouldBindBodyWithJSON(c, &exp); err != nil { + return + } + kind := exp["kind"].(string) + + if chaosKind, ok := v1alpha1.AllKinds()[kind]; ok { + chaos := chaosKind.SpawnObject() + reflect.ValueOf(chaos).Elem().FieldByName("ObjectMeta").Set(reflect.ValueOf(metav1.ObjectMeta{})) + + if err = u.ShouldBindBodyWithJSON(c, chaos); err != nil { + return + } + + if err = kubeCli.Create(context.Background(), chaos); err != nil { + u.SetAPImachineryError(c, err) + + return + } + } else { + u.SetAPIError(c, u.ErrBadRequest.New("Kind "+kind+" is not supported")) + + return + } + + c.JSON(http.StatusOK, exp) +} + +// @Summary Get a chaos experiment. +// @Description Get the chaos experiment's detail by uid. +// @Tags experiments +// @Produce json +// @Param uid path string true "the experiment uid" +// @Success 200 {object} apiservertypes.ExperimentDetail +// @Failure 400 {object} u.APIError +// @Failure 404 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /experiments/{uid} [get] +func (s *Service) get(c *gin.Context) { + var ( + exp *core.Experiment + expDetail *apiservertypes.ExperimentDetail + ) + + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + uid := c.Param("uid") + if exp, err = s.archive.FindByUID(context.Background(), uid); err != nil { + if gorm.IsRecordNotFoundError(err) { + u.SetAPIError(c, u.ErrNotFound.New("Experiment "+uid+" not found")) + } else { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + } + + return + } + + ns, name, kind := exp.Namespace, exp.Name, exp.Kind + + if chaosKind, ok := v1alpha1.AllKinds()[kind]; ok { + expDetail = s.findChaosInCluster(c, kubeCli, types.NamespacedName{Namespace: ns, Name: name}, chaosKind.SpawnObject()) + + if expDetail == nil { + return + } + } else { + u.SetAPIError(c, u.ErrBadRequest.New("Kind "+kind+" is not supported")) + + return + } + + c.JSON(http.StatusOK, expDetail) +} + +func (s *Service) findChaosInCluster(c *gin.Context, kubeCli client.Client, namespacedName types.NamespacedName, chaos client.Object) *apiservertypes.ExperimentDetail { + if err := kubeCli.Get(context.Background(), namespacedName, chaos); err != nil { + u.SetAPImachineryError(c, err) + + return nil + } + + gvk, err := apiutil.GVKForObject(chaos, s.scheme) + if err != nil { + u.SetAPImachineryError(c, err) + + return nil + } + + kind := gvk.Kind + + return &apiservertypes.ExperimentDetail{ + Experiment: apiservertypes.Experiment{ + ObjectBase: core.ObjectBase{ + Namespace: reflect.ValueOf(chaos).MethodByName("GetNamespace").Call(nil)[0].String(), + Name: reflect.ValueOf(chaos).MethodByName("GetName").Call(nil)[0].String(), + Kind: kind, + UID: reflect.ValueOf(chaos).MethodByName("GetUID").Call(nil)[0].String(), + Created: reflect.ValueOf(chaos).MethodByName("GetCreationTimestamp").Call(nil)[0].Interface().(metav1.Time).Format(time.RFC3339), + }, + Status: status.GetChaosStatus(chaos.(v1alpha1.InnerObject)), + }, + KubeObject: core.KubeObjectDesc{ + TypeMeta: metav1.TypeMeta{ + APIVersion: gvk.GroupVersion().String(), + Kind: kind, + }, + Meta: core.KubeObjectMeta{ + Namespace: reflect.ValueOf(chaos).Elem().FieldByName("Namespace").String(), + Name: reflect.ValueOf(chaos).Elem().FieldByName("Name").String(), + Labels: reflect.ValueOf(chaos).Elem().FieldByName("Labels").Interface().(map[string]string), + Annotations: reflect.ValueOf(chaos).Elem().FieldByName("Annotations").Interface().(map[string]string), + }, + Spec: reflect.ValueOf(chaos).Elem().FieldByName("Spec").Interface(), + }, + } +} + +// @Summary Delete a chaos experiment. +// @Description Delete the chaos experiment by uid. +// @Tags experiments +// @Produce json +// @Param uid path string true "the experiment uid" +// @Param force query string false "force" Enums(true, false) +// @Success 200 {object} u.Response +// @Failure 400 {object} u.APIError +// @Failure 404 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /experiments/{uid} [delete] +func (s *Service) delete(c *gin.Context) { + var ( + exp *core.Experiment + ) + + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + uid := c.Param("uid") + if exp, err = s.archive.FindByUID(context.Background(), uid); err != nil { + if gorm.IsRecordNotFoundError(err) { + u.SetAPIError(c, u.ErrNotFound.New("Experiment "+uid+" not found")) + } else { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + } + + return + } + + ns, name, kind, force := exp.Namespace, exp.Name, exp.Kind, c.DefaultQuery("force", "false") + if ok := checkAndDeleteChaos(c, kubeCli, types.NamespacedName{Namespace: ns, Name: name}, kind, force); !ok { + return + } + + c.JSON(http.StatusOK, u.ResponseSuccess) +} + +// @Summary Batch delete chaos experiments. +// @Description Batch delete chaos experiments by uids. +// @Tags experiments +// @Produce json +// @Param uids query string true "the experiment uids, split with comma. Example: ?uids=uid1,uid2" +// @Param force query string false "force" Enums(true, false) +// @Success 200 {object} u.Response +// @Failure 400 {object} u.APIError +// @Failure 404 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /experiments [delete] +func (s *Service) batchDelete(c *gin.Context) { + var ( + exp *core.Experiment + ) + + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + uids := c.Query("uids") + if uids == "" { + u.SetAPIError(c, u.ErrInternalServer.New("The uids cannot be empty")) + + return + } + + uidSlice, force := strings.Split(uids, ","), c.DefaultQuery("force", "false") + + if len(uidSlice) > 100 { + u.SetAPIError(c, u.ErrInternalServer.New("Too many uids, please delete less than 100 at a time")) + + return + } + + for _, uid := range uidSlice { + if exp, err = s.archive.FindByUID(context.Background(), uid); err != nil { + if gorm.IsRecordNotFoundError(err) { + u.SetAPIError(c, u.ErrNotFound.New("Experiment "+uid+" not found")) + } else { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + } + + return + } + + ns, name, kind := exp.Namespace, exp.Name, exp.Kind + if ok := checkAndDeleteChaos(c, kubeCli, types.NamespacedName{Namespace: ns, Name: name}, kind, force); !ok { + return + } + } + + c.JSON(http.StatusOK, u.ResponseSuccess) +} + +func checkAndDeleteChaos(c *gin.Context, kubeCli client.Client, namespacedName types.NamespacedName, kind string, force string) bool { + var ( + chaosKind *v1alpha1.ChaosKind + ok bool + err error + ) + + if chaosKind, ok = v1alpha1.AllKinds()[kind]; !ok { + u.SetAPIError(c, u.ErrBadRequest.New("Kind "+kind+" is not supported")) + + return false + } + + ctx := context.Background() + chaos := chaosKind.SpawnObject() + + if err = kubeCli.Get(ctx, namespacedName, chaos); err != nil { + u.SetAPImachineryError(c, err) + + return false + } + + if force == "true" { + if err = retry.RetryOnConflict(retry.DefaultRetry, func() error { + return forceClean(kubeCli, chaos) + }); err != nil { + u.SetAPIError(c, u.ErrInternalServer.New("Forced deletion failed")) + + return false + } + } + + if err := kubeCli.Delete(ctx, chaos); err != nil { + u.SetAPImachineryError(c, err) + + return false + } + + return true +} + +func forceClean(kubeCli client.Client, chaos client.Object) error { + annotations := chaos.(metav1.Object).GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + + annotations[finalizers.AnnotationCleanFinalizer] = finalizers.AnnotationCleanFinalizerForced + chaos.(metav1.Object).SetAnnotations(annotations) + + return kubeCli.Update(context.Background(), chaos) +} + +// @Summary Pause a chaos experiment. +// @Description Pause a chaos experiment. +// @Tags experiments +// @Produce json +// @Param uid path string true "the experiment uid" +// @Success 200 {object} u.Response +// @Failure 400 {object} u.APIError +// @Failure 404 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /experiments/pause/{uid} [put] +func (s *Service) pause(c *gin.Context) { + var exp *core.Experiment + + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + uid := c.Param("uid") + if exp, err = s.archive.FindByUID(context.Background(), uid); err != nil { + if gorm.IsRecordNotFoundError(err) { + u.SetAPIError(c, u.ErrNotFound.New("Experiment "+uid+" not found")) + } else { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + } + + return + } + + annotations := map[string]string{ + v1alpha1.PauseAnnotationKey: "true", + } + if err = patchExperiment(kubeCli, exp, annotations); err != nil { + u.SetAPImachineryError(c, err) + + return + } + + c.JSON(http.StatusOK, u.ResponseSuccess) +} + +// @Summary Start a chaos experiment. +// @Description Start a chaos experiment. +// @Tags experiments +// @Produce json +// @Param uid path string true "the experiment uid" +// @Success 200 {object} u.Response +// @Failure 400 {object} u.APIError +// @Failure 404 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /experiments/start/{uid} [put] +func (s *Service) start(c *gin.Context) { + var exp *core.Experiment + + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + uid := c.Param("uid") + if exp, err = s.archive.FindByUID(context.Background(), uid); err != nil { + if gorm.IsRecordNotFoundError(err) { + u.SetAPIError(c, u.ErrNotFound.New("Experiment "+uid+" not found")) + } else { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + } + + return + } + + annotations := map[string]string{ + v1alpha1.PauseAnnotationKey: "false", + } + if err = patchExperiment(kubeCli, exp, annotations); err != nil { + u.SetAPImachineryError(c, err) + + return + } + + c.JSON(http.StatusOK, u.ResponseSuccess) +} + +func patchExperiment(kubeCli client.Client, exp *core.Experiment, annotations map[string]string) error { + chaos := v1alpha1.AllKinds()[exp.Kind].SpawnObject() + + if err := kubeCli.Get(context.Background(), types.NamespacedName{Namespace: exp.Namespace, Name: exp.Name}, chaos); err != nil { + return err + } + + var mergePatch []byte + mergePatch, _ = json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "annotations": annotations, + }, + }) + + return kubeCli.Patch(context.Background(), chaos, client.RawPatch(types.MergePatchType, mergePatch)) +} + +// @Summary Get the status of all experiments. +// @Description Get the status of all experiments. +// @Tags experiments +// @Produce json +// @Param namespace query string false "namespace" +// @Success 200 {object} status.AllChaosStatus +// @Failure 400 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /experiments/state [get] +func (s *Service) state(c *gin.Context) { + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + ns := c.Query("namespace") + if ns == "" && !s.config.ClusterScoped && s.config.TargetNamespace != "" { + ns = s.config.TargetNamespace + + s.log.V(1).Info("Replace query namespace", "ns", ns) + } + + allChaosStatus := status.AllChaosStatus{} + + g, ctx := errgroup.WithContext(context.Background()) + m := &sync.Mutex{} + + var listOptions []client.ListOption + listOptions = append(listOptions, &client.ListOptions{Namespace: ns}) + + for _, chaosKind := range v1alpha1.AllKinds() { + list := chaosKind.SpawnList() + + g.Go(func() error { + if err := kubeCli.List(ctx, list, listOptions...); err != nil { + return err + } + m.Lock() + + for _, item := range list.GetItems() { + s := status.GetChaosStatus(item.(v1alpha1.InnerObject)) + + switch s { + case status.Injecting: + allChaosStatus.Injecting++ + case status.Running: + allChaosStatus.Running++ + case status.Finished: + allChaosStatus.Finished++ + case status.Paused: + allChaosStatus.Paused++ + } + } + + m.Unlock() + return nil + }) + } + + if err = g.Wait(); err != nil { + u.SetAPImachineryError(c, err) + + return + } + + c.JSON(http.StatusOK, allChaosStatus) +} diff --git a/pkg/dashboard/apiserver/experiment/fx.go b/pkg/dashboard/apiserver/experiment/fx.go new file mode 100644 index 0000000000..41d042530a --- /dev/null +++ b/pkg/dashboard/apiserver/experiment/fx.go @@ -0,0 +1,32 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package experiment + +import ( + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/runtime" + + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +func Bootstrap(archive core.ExperimentStore, + event core.EventStore, + config *config.ChaosDashboardConfig, + scheme *runtime.Scheme, + log logr.Logger) *Service { + return NewService(archive, event, config, scheme, log.WithName("experiments")) +} diff --git a/pkg/dashboard/apiserver/handler.go b/pkg/dashboard/apiserver/handler.go new file mode 100644 index 0000000000..5148f350df --- /dev/null +++ b/pkg/dashboard/apiserver/handler.go @@ -0,0 +1,53 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package apiserver + +import ( + "go.uber.org/fx" + + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/archive" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/auth/gcp" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/common" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/event" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/experiment" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/schedule" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/template" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/workflow" +) + +var handlerModule = fx.Options( + fx.Provide( + common.NewService, + experiment.Bootstrap, + schedule.Bootstrap, + workflow.Bootstrap, + event.NewService, + archive.NewService, + gcp.NewService, + template.Bootstrap, + ), + fx.Invoke( + // gcp should register at the first, because it registers a middleware + gcp.Register, + common.Register, + experiment.Register, + schedule.Register, + workflow.Register, + event.Register, + archive.Register, + template.Register, + ), +) diff --git a/pkg/dashboard/apiserver/schedule/fx.go b/pkg/dashboard/apiserver/schedule/fx.go new file mode 100644 index 0000000000..c9a995eae1 --- /dev/null +++ b/pkg/dashboard/apiserver/schedule/fx.go @@ -0,0 +1,32 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package schedule + +import ( + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/runtime" + + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +func Bootstrap(schedule core.ScheduleStore, + event core.EventStore, + config *config.ChaosDashboardConfig, + scheme *runtime.Scheme, + log logr.Logger) *Service { + return NewService(schedule, event, config, scheme, log.WithName("schedules")) +} diff --git a/pkg/dashboard/apiserver/schedule/schedule.go b/pkg/dashboard/apiserver/schedule/schedule.go new file mode 100644 index 0000000000..5fd99938c8 --- /dev/null +++ b/pkg/dashboard/apiserver/schedule/schedule.go @@ -0,0 +1,510 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package schedule + +import ( + "context" + "encoding/json" + "net/http" + "sort" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-logr/logr" + "github.com/jinzhu/gorm" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/clientpool" + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + apiservertypes "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/types" + u "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/utils" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" + "github.com/chaos-mesh/chaos-mesh/pkg/status" +) + +// Service defines a handler service for schedules. +type Service struct { + schedule core.ScheduleStore + event core.EventStore + config *config.ChaosDashboardConfig + scheme *runtime.Scheme + log logr.Logger +} + +func NewService( + schedule core.ScheduleStore, + event core.EventStore, + config *config.ChaosDashboardConfig, + scheme *runtime.Scheme, + log logr.Logger, +) *Service { + return &Service{ + schedule: schedule, + event: event, + config: config, + scheme: scheme, + log: log, + } +} + +// Register schedules RouterGroup. +func Register(r *gin.RouterGroup, s *Service) { + endpoint := r.Group("/schedules") + + endpoint.GET("", s.list) + endpoint.POST("", s.create) + endpoint.GET("/:uid", s.get) + endpoint.DELETE("/:uid", s.delete) + endpoint.DELETE("", s.batchDelete) + endpoint.PUT("/pause/:uid", s.pauseSchedule) + endpoint.PUT("/start/:uid", s.startSchedule) +} + +// @Summary List chaos schedules. +// @Description Get chaos schedules from k8s cluster in real time. +// @Tags schedules +// @Produce json +// @Param namespace query string false "filter schedules by namespace" +// @Param name query string false "filter schedules by name" +// @Success 200 {array} apiservertypes.Schedule +// @Failure 400 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /schedules [get] +func (s *Service) list(c *gin.Context) { + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + ns, name := c.Query("namespace"), c.Query("name") + + if ns == "" && !s.config.ClusterScoped && s.config.TargetNamespace != "" { + ns = s.config.TargetNamespace + + s.log.V(1).Info("Replace query namespace", "ns", ns) + } + + ScheduleList := v1alpha1.ScheduleList{} + if err = kubeCli.List(context.Background(), &ScheduleList, &client.ListOptions{Namespace: ns}); err != nil { + u.SetAPImachineryError(c, err) + + return + } + + sches := make([]*apiservertypes.Schedule, 0) + for _, schedule := range ScheduleList.Items { + if name != "" && schedule.Name != name { + continue + } + + sches = append(sches, &apiservertypes.Schedule{ + ObjectBase: core.ObjectBase{ + Namespace: schedule.Namespace, + Name: schedule.Name, + Kind: string(schedule.Spec.Type), + UID: string(schedule.UID), + Created: schedule.CreationTimestamp.Format(time.RFC3339), + }, + Status: status.GetScheduleStatus(schedule), + }) + } + + sort.Slice(sches, func(i, j int) bool { + return sches[i].Created > sches[j].Created + }) + + c.JSON(http.StatusOK, sches) +} + +// @Summary Create a new schedule. +// @Description Pass a JSON object to create a new schedule. The schema for JSON is the same as the YAML schema for the Kubernetes object. +// @Tags schedules +// @Accept json +// @Produce json +// @Param schedule body v1alpha1.Schedule true "the schedule definition" +// @Success 200 {object} v1alpha1.Schedule +// @Failure 400 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /schedules [post] +func (s *Service) create(c *gin.Context) { + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + var sch v1alpha1.Schedule + if err = u.ShouldBindBodyWithJSON(c, &sch); err != nil { + return + } + + if err = kubeCli.Create(context.Background(), &sch); err != nil { + u.SetAPImachineryError(c, err) + + return + } + + c.JSON(http.StatusOK, sch) +} + +// @Summary Get a schedule. +// @Description Get the schedule's detail by uid. +// @Tags schedules +// @Produce json +// @Param uid path string true "the schedule uid" +// @Success 200 {object} apiservertypes.ScheduleDetail +// @Failure 400 {object} u.APIError +// @Failure 404 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /schedules/{uid} [get] +func (s *Service) get(c *gin.Context) { + var ( + sch *core.Schedule + schDetail *apiservertypes.ScheduleDetail + ) + + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + uid := c.Param("uid") + if sch, err = s.schedule.FindByUID(context.Background(), uid); err != nil { + if gorm.IsRecordNotFoundError(err) { + u.SetAPIError(c, u.ErrBadRequest.New("Schedule "+uid+"not found")) + } else { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + } + + return + } + + ns, name := sch.Namespace, sch.Name + schDetail = s.findScheduleInCluster(c, kubeCli, types.NamespacedName{Namespace: ns, Name: name}) + if schDetail == nil { + return + } + + c.JSON(http.StatusOK, schDetail) +} + +func (s *Service) findScheduleInCluster(c *gin.Context, kubeCli client.Client, namespacedName types.NamespacedName) *apiservertypes.ScheduleDetail { + var sch v1alpha1.Schedule + + if err := kubeCli.Get(context.Background(), namespacedName, &sch); err != nil { + u.SetAPImachineryError(c, err) + + return nil + } + + gvk, err := apiutil.GVKForObject(&sch, s.scheme) + if err != nil { + u.SetAPImachineryError(c, err) + + return nil + } + + UIDList := make([]string, 0) + schType := string(sch.Spec.Type) + chaosKind, ok := v1alpha1.AllScheduleItemKinds()[schType] + if !ok { + u.SetAPIError(c, u.ErrInternalServer.New("Kind "+schType+" is not supported")) + + return nil + } + + selector, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{ + MatchLabels: map[string]string{v1alpha1.LabelManagedBy: sch.Name}, + }) + if err != nil { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + + return nil + } + + chaosList := chaosKind.SpawnList() + err = kubeCli.List(context.Background(), chaosList, &client.ListOptions{ + Namespace: sch.Namespace, + LabelSelector: selector, + }) + if err != nil { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + + return nil + } + + items := chaosList.GetItems() + for _, item := range items { + UIDList = append(UIDList, string(item.GetUID())) + } + + return &apiservertypes.ScheduleDetail{ + Schedule: apiservertypes.Schedule{ + ObjectBase: core.ObjectBase{ + Namespace: sch.Namespace, + Name: sch.Name, + Kind: string(sch.Spec.Type), + UID: string(sch.UID), + Created: sch.CreationTimestamp.Format(time.RFC3339), + }, + Status: status.GetScheduleStatus(sch), + }, + ExperimentUIDs: UIDList, + KubeObject: core.KubeObjectDesc{ + TypeMeta: metav1.TypeMeta{ + APIVersion: gvk.GroupVersion().String(), + Kind: gvk.Kind, + }, + Meta: core.KubeObjectMeta{ + Namespace: sch.Namespace, + Name: sch.Name, + Labels: sch.Labels, + Annotations: sch.Annotations, + }, + Spec: sch.Spec, + }, + } +} + +// @Summary Delete a schedule. +// @Description Delete the schedule by uid. +// @Tags schedules +// @Produce json +// @Param uid path string true "the schedule uid" +// @Success 200 {object} u.Response +// @Failure 400 {object} u.APIError +// @Failure 404 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /schedules/{uid} [delete] +func (s *Service) delete(c *gin.Context) { + var ( + sch *core.Schedule + ) + + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + uid := c.Param("uid") + if sch, err = s.schedule.FindByUID(context.Background(), uid); err != nil { + if gorm.IsRecordNotFoundError(err) { + u.SetAPIError(c, u.ErrNotFound.New("Schedule "+uid+" not found")) + } else { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + } + + return + } + + ns, name := sch.Namespace, sch.Name + if err = checkAndDeleteSchedule(c, kubeCli, types.NamespacedName{Namespace: ns, Name: name}); err != nil { + u.SetAPImachineryError(c, err) + + return + } + + c.JSON(http.StatusOK, u.ResponseSuccess) +} + +// @Summary Batch delete schedules. +// @Description Batch delete schedules by uids. +// @Tags schedules +// @Produce json +// @Param uids query string true "the schedule uids, split with comma. Example: ?uids=uid1,uid2" +// @Success 200 {object} u.Response +// @Failure 400 {object} u.APIError +// @Failure 404 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /schedules [delete] +func (s *Service) batchDelete(c *gin.Context) { + var ( + sch *core.Schedule + ) + + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + uids := c.Query("uids") + if uids == "" { + u.SetAPIError(c, u.ErrInternalServer.New("The uids cannot be empty")) + + return + } + + uidSlice := strings.Split(uids, ",") + + if len(uidSlice) > 100 { + u.SetAPIError(c, u.ErrInternalServer.New("Too many uids, please delete less than 100 at a time")) + + return + } + + for _, uid := range uidSlice { + if sch, err = s.schedule.FindByUID(context.Background(), uid); err != nil { + if gorm.IsRecordNotFoundError(err) { + u.SetAPIError(c, u.ErrNotFound.New("Experiment "+uid+" not found")) + } else { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + } + + return + } + + ns, name := sch.Namespace, sch.Name + if err = checkAndDeleteSchedule(c, kubeCli, types.NamespacedName{Namespace: ns, Name: name}); err != nil { + u.SetAPImachineryError(c, err) + + return + } + + } + + c.JSON(http.StatusOK, u.ResponseSuccess) +} + +func checkAndDeleteSchedule(c *gin.Context, kubeCli client.Client, namespacedName types.NamespacedName) (err error) { + ctx := context.Background() + var sch v1alpha1.Schedule + + if err = kubeCli.Get(ctx, namespacedName, &sch); err != nil { + return + } + + if err = kubeCli.Delete(ctx, &sch); err != nil { + return + } + + return +} + +// @Summary Pause a schedule. +// @Description Pause a schedule. +// @Tags schedules +// @Produce json +// @Param uid path string true "the schedule uid" +// @Success 200 {object} u.Response +// @Failure 400 {object} u.APIError +// @Failure 404 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /schedules/pause/{uid} [put] +func (s *Service) pauseSchedule(c *gin.Context) { + var sch *core.Schedule + + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + uid := c.Param("uid") + if sch, err = s.schedule.FindByUID(context.Background(), uid); err != nil { + if gorm.IsRecordNotFoundError(err) { + u.SetAPIError(c, u.ErrNotFound.New("Experiment "+uid+" not found")) + } else { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + } + + return + } + + annotations := map[string]string{ + v1alpha1.PauseAnnotationKey: "true", + } + if err = patchSchedule(kubeCli, sch, annotations); err != nil { + u.SetAPImachineryError(c, err) + + return + } + c.JSON(http.StatusOK, u.ResponseSuccess) +} + +// @Summary Start a schedule. +// @Description Start a schedule. +// @Tags schedules +// @Produce json +// @Param uid path string true "the schedule uid" +// @Success 200 {object} u.Response +// @Failure 400 {object} u.APIError +// @Failure 404 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /schedules/start/{uid} [put] +func (s *Service) startSchedule(c *gin.Context) { + var sch *core.Schedule + + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + uid := c.Param("uid") + if sch, err = s.schedule.FindByUID(context.Background(), uid); err != nil { + if gorm.IsRecordNotFoundError(err) { + u.SetAPIError(c, u.ErrNotFound.New("Experiment "+uid+" not found")) + } else { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + } + + return + } + + annotations := map[string]string{ + v1alpha1.PauseAnnotationKey: "false", + } + if err = patchSchedule(kubeCli, sch, annotations); err != nil { + u.SetAPImachineryError(c, err) + + return + } + c.JSON(http.StatusOK, u.ResponseSuccess) +} + +func patchSchedule(kubeCli client.Client, sch *core.Schedule, annotations map[string]string) error { + var tmp v1alpha1.Schedule + + if err := kubeCli.Get(context.Background(), types.NamespacedName{Namespace: sch.Namespace, Name: sch.Name}, &tmp); err != nil { + return err + } + + var mergePatch []byte + mergePatch, _ = json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "annotations": annotations, + }, + }) + + return kubeCli.Patch(context.Background(), &tmp, client.RawPatch(types.MergePatchType, mergePatch)) +} diff --git a/pkg/dashboard/apiserver/server.go b/pkg/dashboard/apiserver/server.go new file mode 100644 index 0000000000..d103c404d4 --- /dev/null +++ b/pkg/dashboard/apiserver/server.go @@ -0,0 +1,102 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package apiserver + +import ( + "fmt" + "net" + "net/http" + + "github.com/gin-contrib/pprof" + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "github.com/go-playground/validator/v10" + "github.com/prometheus/client_golang/prometheus" + "go.uber.org/fx" + controllermetrics "sigs.k8s.io/controller-runtime/pkg/metrics" + + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apivalidator" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/swaggerserver" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/uiserver" + "github.com/chaos-mesh/chaos-mesh/pkg/metrics" +) + +var ( + // Module includes the providers (gin engine and api router) and the registers. + Module = fx.Options( + fx.Provide( + newEngine, + newAPIRouter, + ), + handlerModule, + fx.Provide(func() prometheus.Registerer { + return controllermetrics.Registry + }), + fx.Invoke(metrics.NewChaosDashboardMetricsCollector), + fx.Invoke(register), + ) +) + +func register(r *gin.Engine, conf *config.ChaosDashboardConfig) { + listenAddr := net.JoinHostPort(conf.ListenHost, fmt.Sprintf("%d", conf.ListenPort)) + + go r.Run(listenAddr) +} + +func newEngine(config *config.ChaosDashboardConfig) *gin.Engine { + r := gin.Default() + + if config.EnableProfiling { + // default is "/debug/pprof" + pprof.Register(r) + } + + if v, ok := binding.Validator.Engine().(*validator.Validate); ok { + v.RegisterValidation("NameValid", apivalidator.NameValid) + v.RegisterValidation("NamespaceSelectorsValid", apivalidator.NamespaceSelectorsValid) + v.RegisterValidation("MapSelectorsValid", apivalidator.MapSelectorsValid) + v.RegisterValidation("RequirementSelectorsValid", apivalidator.RequirementSelectorsValid) + v.RegisterValidation("PhaseSelectorsValid", apivalidator.PhaseSelectorsValid) + v.RegisterValidation("CronValid", apivalidator.CronValid) + v.RegisterValidation("DurationValid", apivalidator.DurationValid) + v.RegisterValidation("ValueValid", apivalidator.ValueValid) + v.RegisterValidation("PodsValid", apivalidator.PodsValid) + v.RegisterValidation("RequiredFieldEqual", apivalidator.RequiredFieldEqualValid, true) + v.RegisterValidation("PhysicalMachineValid", apivalidator.PhysicalMachineValid) + } + + ui := uiserver.AssetsFS() + if ui != nil { + r.NoRoute(func(c *gin.Context) { + c.FileFromFS(c.Request.URL.Path, ui) + }) + } else { + r.GET("/", func(c *gin.Context) { + c.String(http.StatusOK, "Dashboard UI is not built.") + }) + } + + return r +} + +func newAPIRouter(r *gin.Engine) *gin.RouterGroup { + api := r.Group("/api") + + api.GET("/swagger/*any", swaggerserver.Handler) + + return api +} diff --git a/pkg/dashboard/apiserver/template/fx.go b/pkg/dashboard/apiserver/template/fx.go new file mode 100644 index 0000000000..5d02f88345 --- /dev/null +++ b/pkg/dashboard/apiserver/template/fx.go @@ -0,0 +1,26 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package template + +import ( + "github.com/go-logr/logr" + + config "github.com/chaos-mesh/chaos-mesh/pkg/config" +) + +func Bootstrap(conf *config.ChaosDashboardConfig, logger logr.Logger) *Service { + return &Service{conf: conf, logger: logger.WithName("template-api")} +} diff --git a/pkg/dashboard/apiserver/template/template.go b/pkg/dashboard/apiserver/template/template.go new file mode 100644 index 0000000000..04d0eb5d6c --- /dev/null +++ b/pkg/dashboard/apiserver/template/template.go @@ -0,0 +1,344 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package template + +import ( + "context" + "net/http" + "sort" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-logr/logr" + "gopkg.in/yaml.v2" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/clientpool" + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + apiservertypes "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/types" + u "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/utils" +) + +// Service defines a handler service for cluster common objects. +type Service struct { + conf *config.ChaosDashboardConfig + logger logr.Logger +} + +func NewService(conf *config.ChaosDashboardConfig, logger logr.Logger) *Service { + return &Service{conf: conf, logger: logger} +} + +func Register(r *gin.RouterGroup, s *Service) { + endpoint := r.Group("/templates") + + statusCheckEndpoint := endpoint.Group("/statuschecks") + statusCheckEndpoint.GET("", s.listStatusCheckTemplate) + statusCheckEndpoint.POST("", s.createStatusCheckTemplate) + statusCheckEndpoint.GET("/statuscheck", s.getStatusCheckTemplateDetail) + statusCheckEndpoint.PUT("/statuscheck", s.updateStatusCheckTemplate) + statusCheckEndpoint.DELETE("/statuscheck", s.deleteStatusCheckTemplate) +} + +// @Summary List status check templates. +// @Description Get status check templates from k8s cluster in real time. +// @Tags template +// @Produce json +// @Param namespace query string false "filter status check templates by namespace" +// @Param name query string false "filter status check templates by name" +// @Success 200 {array} apiservertypes.StatusCheckTemplateBase +// @Failure 400 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /templates/statuschecks [get] +func (s *Service) listStatusCheckTemplate(c *gin.Context) { + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + + ns, name := c.Query("namespace"), c.Query("name") + if ns == "" && !s.conf.ClusterScoped && s.conf.TargetNamespace != "" { + ns = s.conf.TargetNamespace + s.logger.Info("Replace query namespace", "ns", ns) + } + + configMapList := v1.ConfigMapList{} + if err = kubeCli.List(context.Background(), &configMapList, + client.InNamespace(ns), + client.MatchingLabels{ + v1alpha1.TemplateTypeLabelKey: v1alpha1.KindStatusCheck, + v1alpha1.ManagedByLabelKey: v1alpha1.ManagedByLabelValue, + }, + ); err != nil { + u.SetAPImachineryError(c, err) + return + } + + templates := make([]*apiservertypes.StatusCheckTemplateBase, 0) + for _, cm := range configMapList.Items { + templateName := v1alpha1.GetTemplateName(cm) + if templateName == "" { + // skip illegal template + continue + } + if name != "" && templateName != name { + continue + } + + templates = append(templates, &apiservertypes.StatusCheckTemplateBase{ + Namespace: cm.Namespace, + Name: templateName, + UID: string(cm.UID), + Created: cm.CreationTimestamp.Format(time.RFC3339), + Description: v1alpha1.GetTemplateDescription(cm), + }) + } + + sort.Slice(templates, func(i, j int) bool { + return templates[i].Created > templates[j].Created + }) + + c.JSON(http.StatusOK, templates) +} + +// @Summary Create a new status check template. +// @Description Pass a JSON object to create a new status check template. +// @Tags templates +// @Accept json +// @Produce json +// @Param statuscheck body apiservertypes.StatusCheckTemplate true "the status check definition" +// @Success 200 {object} apiservertypes.StatusCheckTemplate +// @Failure 400 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /templates/statuschecks [post] +func (s *Service) createStatusCheckTemplate(c *gin.Context) { + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + + var template apiservertypes.StatusCheckTemplate + if err = u.ShouldBindBodyWithJSON(c, &template); err != nil { + return + } + template.Spec.Default() + if _, err := template.Spec.Validate(); err != nil { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + + spec, err := yaml.Marshal(template.Spec) + if err != nil { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + cm := v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: template.Namespace, + Name: v1alpha1.GenerateTemplateName(template.Name), + Labels: map[string]string{ + v1alpha1.TemplateTypeLabelKey: v1alpha1.KindStatusCheck, + v1alpha1.ManagedByLabelKey: v1alpha1.ManagedByLabelValue, + }, + Annotations: map[string]string{ + v1alpha1.TemplateNameAnnotationKey: template.Name, + v1alpha1.TemplateDescriptionAnnotationKey: template.Description, + }, + }, + Data: map[string]string{v1alpha1.StatusCheckTemplateKey: string(spec)}, + } + if err = kubeCli.Create(context.Background(), &cm); err != nil { + u.SetAPImachineryError(c, err) + return + } + + c.JSON(http.StatusOK, template) +} + +// @Summary Get a status check template. +// @Description Get the status check template's detail by namespaced name. +// @Tags templates +// @Produce json +// @Param namespace query string true "the namespace of status check templates" +// @Param name query string true "the name of status check templates" +// @Success 200 {object} apiservertypes.StatusCheckTemplateDetail +// @Failure 400 {object} u.APIError +// @Failure 404 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /templates/statuschecks/statuscheck [get] +func (s *Service) getStatusCheckTemplateDetail(c *gin.Context) { + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + + ns, name := c.Query("namespace"), c.Query("name") + if ns == "" && !s.conf.ClusterScoped && s.conf.TargetNamespace != "" { + ns = s.conf.TargetNamespace + s.logger.Info("Replace query namespace", "ns", ns) + } + if name == "" { + u.SetAPIError(c, u.ErrBadRequest.New("name is required")) + return + } + + var cm v1.ConfigMap + if err = kubeCli.Get(context.Background(), + types.NamespacedName{ + Namespace: ns, + Name: v1alpha1.GenerateTemplateName(name), + }, &cm); err != nil { + u.SetAPImachineryError(c, err) + return + } + + if !v1alpha1.IsStatusCheckTemplate(cm) { + u.SetAPIError(c, u.ErrInternalServer.New("invalid status check template")) + return + } + + var spec v1alpha1.StatusCheckTemplate + if err := yaml.Unmarshal([]byte(cm.Data[v1alpha1.StatusCheckTemplateKey]), &spec); err != nil { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + detail := apiservertypes.StatusCheckTemplateDetail{ + StatusCheckTemplateBase: apiservertypes.StatusCheckTemplateBase{ + Namespace: cm.Namespace, + Name: v1alpha1.GetTemplateName(cm), + UID: string(cm.UID), + Created: cm.CreationTimestamp.Format(time.RFC3339), + Description: v1alpha1.GetTemplateDescription(cm), + }, + Spec: spec, + } + c.JSON(http.StatusOK, detail) +} + +// @Summary Update a status check template. +// @Description Update a status check template by namespaced name. +// @Tags templates +// @Produce json +// @Param request body apiservertypes.StatusCheckTemplate true "Request body" +// @Success 200 {object} apiservertypes.StatusCheckTemplate +// @Failure 400 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /templates/statuschecks/statuscheck [put] +func (s *Service) updateStatusCheckTemplate(c *gin.Context) { + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + + var template apiservertypes.StatusCheckTemplate + if err = u.ShouldBindBodyWithJSON(c, &template); err != nil { + return + } + template.Spec.Default() + if _, err := template.Spec.Validate(); err != nil { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + + var cm v1.ConfigMap + if err = kubeCli.Get(context.Background(), + types.NamespacedName{ + Namespace: template.Namespace, + Name: v1alpha1.GenerateTemplateName(template.Name), + }, &cm); err != nil { + u.SetAPImachineryError(c, err) + return + } + if !v1alpha1.IsStatusCheckTemplate(cm) { + u.SetAPIError(c, u.ErrInternalServer.New("invalid status check template")) + return + } + + spec, err := yaml.Marshal(template.Spec) + if err != nil { + u.SetAPIError(c, u.ErrInternalServer.WrapWithNoMessage(err)) + return + } + if cm.Data == nil { + cm.Data = map[string]string{v1alpha1.StatusCheckTemplateKey: string(spec)} + } else { + cm.Data[v1alpha1.StatusCheckTemplateKey] = string(spec) + } + cm.Annotations[v1alpha1.TemplateDescriptionAnnotationKey] = template.Description + + if err := kubeCli.Update(context.Background(), &cm); err != nil { + u.SetAPImachineryError(c, err) + return + } + c.JSON(http.StatusOK, template) +} + +// @Summary Delete a status check template. +// @Description Delete the status check template by namespaced name. +// @Tags templates +// @Produce json +// @Param namespace query string true "the namespace of status check templates" +// @Param name query string true "the name of status check templates" +// @Success 200 {object} u.Response +// @Failure 400 {object} u.APIError +// @Failure 404 {object} u.APIError +// @Failure 500 {object} u.APIError +// @Router /templates/statuschecks/statuscheck [delete] +func (s *Service) deleteStatusCheckTemplate(c *gin.Context) { + kubeCli, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + u.SetAPIError(c, u.ErrBadRequest.WrapWithNoMessage(err)) + return + } + + ns, name := c.Query("namespace"), c.Query("name") + if ns == "" && !s.conf.ClusterScoped && s.conf.TargetNamespace != "" { + ns = s.conf.TargetNamespace + s.logger.Info("Replace query namespace", "ns", ns) + } + if name == "" { + u.SetAPIError(c, u.ErrBadRequest.New("name is required")) + return + } + + var cm v1.ConfigMap + if err = kubeCli.Get(context.Background(), + types.NamespacedName{ + Namespace: ns, + Name: v1alpha1.GenerateTemplateName(name), + }, &cm); err != nil { + u.SetAPImachineryError(c, err) + return + } + if !v1alpha1.IsStatusCheckTemplate(cm) { + u.SetAPIError(c, u.ErrInternalServer.New("invalid status check template")) + return + } + + if err := kubeCli.Delete(context.Background(), &cm); err != nil { + u.SetAPImachineryError(c, err) + return + } + c.JSON(http.StatusOK, u.ResponseSuccess) +} diff --git a/pkg/dashboard/apiserver/types/types.go b/pkg/dashboard/apiserver/types/types.go new file mode 100644 index 0000000000..75cc510a22 --- /dev/null +++ b/pkg/dashboard/apiserver/types/types.go @@ -0,0 +1,109 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package types + +import ( + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" + "github.com/chaos-mesh/chaos-mesh/pkg/status" +) + +// Archive defines the basic information of an archive. +type Archive = core.ObjectBase + +/* +ArchiveDetail represents an archive instance. + +It inherits `Archive` and adds complete definition of an experiment. +*/ +type ArchiveDetail struct { + Archive + KubeObject core.KubeObjectDesc `json:"kube_object"` +} + +// Experiment defines the basic information of an experiment. +type Experiment struct { + core.ObjectBase + Status status.ChaosStatus `json:"status"` + FailedMessage string `json:"failed_message,omitempty"` +} + +/* +ExperimentDetail represents an experiment instance. + +It inherits `Experiment` and adds complete definition of an experiment. +*/ +type ExperimentDetail struct { + Experiment + KubeObject core.KubeObjectDesc `json:"kube_object"` +} + +// PhysicalMachine defines the basic information of a physical machine. +type PhysicalMachine struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + Address string `json:"address"` +} + +// Pod defines the basic information of a pod. +type Pod struct { + IP string `json:"ip"` + Name string `json:"name"` + Namespace string `json:"namespace"` + State string `json:"state"` +} + +// Schedule defines the basic information of a schedule. +type Schedule struct { + core.ObjectBase + Status status.ScheduleStatus `json:"status"` +} + +/* +ScheduleDetail represents an archive instance. + +It inherits `Schedule` and adds complete definition of a schedule. +*/ +type ScheduleDetail struct { + Schedule + ExperimentUIDs []string `json:"experiment_uids"` + KubeObject core.KubeObjectDesc `json:"kube_object"` +} + +type StatusCheckTemplateBase struct { + Namespace string `json:"namespace"` + Name string `json:"name"` + UID string `json:"uid"` + Description string `json:"description,omitempty"` + Created string `json:"created_at"` +} + +/* +StatusCheckTemplateDetail represents an archive instance. + +It inherits `StatusCheckTemplateBase` and adds complete definition of a Status Check template. +*/ +type StatusCheckTemplateDetail struct { + StatusCheckTemplateBase `json:",inline,omitempty"` + Spec v1alpha1.StatusCheckTemplate `json:"spec"` +} + +type StatusCheckTemplate struct { + Namespace string `json:"namespace"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + Spec v1alpha1.StatusCheckTemplate `json:"spec"` +} diff --git a/pkg/dashboard/apiserver/utils/auth.go b/pkg/dashboard/apiserver/utils/auth.go new file mode 100644 index 0000000000..07d010c3c8 --- /dev/null +++ b/pkg/dashboard/apiserver/utils/auth.go @@ -0,0 +1,88 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package utils + +import ( + "net/http" + + "github.com/gin-gonic/gin" + authorizationv1 "k8s.io/api/authorization/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/chaos-mesh/chaos-mesh/pkg/clientpool" + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/log" + "github.com/chaos-mesh/chaos-mesh/pkg/mock" +) + +func AuthMiddleware(c *gin.Context, config *config.ChaosDashboardConfig) { + if mockResult := mock.On("AuthMiddleware"); mockResult != nil { + c.Next() + + return + } + + kubeCli, err := clientpool.ExtractTokenAndGetAuthClient(c.Request.Header) + if err != nil { + SetAPIError(c, ErrBadRequest.WrapWithNoMessage(err)) + + return + } + + ns := c.Query("namespace") + + if ns == "" && !config.ClusterScoped && config.TargetNamespace != "" { + ns = config.TargetNamespace + + log.L().WithName("auth middleware").V(1).Info("Replace query namespace", "ns", ns) + } + + verb := "list" + if c.Request.Method != http.MethodGet { + // patch is used to indicate create, patch, finalizers and other write operations + verb = "patch" + } + + sar := &authorizationv1.SelfSubjectAccessReview{ + Spec: authorizationv1.SelfSubjectAccessReviewSpec{ + ResourceAttributes: &authorizationv1.ResourceAttributes{ + Namespace: ns, + Verb: verb, + Group: "chaos-mesh.org", + Resource: "*", + }, + }, + } + + result, err := kubeCli.SelfSubjectAccessReviews().Create(c.Request.Context(), sar, metav1.CreateOptions{}) + if err != nil { + SetAPImachineryError(c, ErrInternalServer.WrapWithNoMessage(err)) + + return + } + + if !result.Status.Allowed { + if len(ns) == 0 { + SetAPIError(c, ErrNoClusterPrivilege.New("can't %s resource in the cluster", verb)) + } else { + SetAPIError(c, ErrNoNamespacePrivilege.New("can't %s resource in namespace %s", verb, ns)) + } + + return + } + + c.Next() +} diff --git a/pkg/dashboard/apiserver/utils/error.go b/pkg/dashboard/apiserver/utils/error.go new file mode 100644 index 0000000000..003a069206 --- /dev/null +++ b/pkg/dashboard/apiserver/utils/error.go @@ -0,0 +1,92 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package utils + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "github.com/joomcode/errorx" + apierrors "k8s.io/apimachinery/pkg/api/errors" + + "github.com/chaos-mesh/chaos-mesh/pkg/log" +) + +var ( + ErrNS = errorx.NewNamespace("error.api") + ErrUnknown = ErrNS.NewType("unknown") // 500 + ErrBadRequest = ErrNS.NewType("bad_request") // 400 + ErrNotFound = ErrNS.NewType("resource_not_found") // 404 + ErrInternalServer = ErrNS.NewType("internal_server_error") // 500 + // Custom + ErrNoClusterPrivilege = ErrNS.NewType("no_cluster_privilege") // 401 + ErrNoNamespacePrivilege = ErrNS.NewType("no_namespace_privilege") // 401 +) + +type APIError struct { + Code int `json:"code"` + Type string `json:"type"` + Message string `json:"message"` + FullText string `json:"full_text"` +} + +func SetAPIError(c *gin.Context, err *errorx.Error) { + typeName := errorx.GetTypeName(err) + + var code int + switch typeName { + case ErrBadRequest.FullName(): + code = http.StatusBadRequest + case ErrNoClusterPrivilege.FullName(), ErrNoNamespacePrivilege.FullName(): + code = http.StatusUnauthorized + case ErrNotFound.FullName(): + code = http.StatusNotFound + case ErrUnknown.FullName(), ErrInternalServer.FullName(): + code = http.StatusInternalServerError + default: + code = http.StatusInternalServerError + } + + apiError := APIError{ + Code: code, + Type: typeName, + Message: err.Error(), + FullText: fmt.Sprintf("%+v", err), + } + + log.L().WithName("auth middleware").Error(err.Cause(), typeName) + c.AbortWithStatusJSON(code, &apiError) +} + +func SetAPImachineryError(c *gin.Context, err error) { + if apierrors.IsForbidden(err) && strings.Contains(err.Error(), "at the cluster scope") { + SetAPIError(c, ErrNoClusterPrivilege.WrapWithNoMessage(err)) + + return + } else if apierrors.IsForbidden(err) && strings.Contains(err.Error(), "in the namespace") { + SetAPIError(c, ErrNoNamespacePrivilege.WrapWithNoMessage(err)) + + return + } else if apierrors.IsNotFound(err) { + SetAPIError(c, ErrNotFound.WrapWithNoMessage(err)) + + return + } + + SetAPIError(c, ErrInternalServer.WrapWithNoMessage(err)) +} diff --git a/pkg/dashboard/apiserver/utils/gin.go b/pkg/dashboard/apiserver/utils/gin.go new file mode 100644 index 0000000000..8f767b8a45 --- /dev/null +++ b/pkg/dashboard/apiserver/utils/gin.go @@ -0,0 +1,42 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package utils + +import ( + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" +) + +// MapSliceResponse is an alias of map[string][]string. +type MapStringSliceResponse map[string][]string + +// Response defines a common status struct. +type Response struct { + Status string `json:"status"` +} + +var ( + ResponseSuccess = Response{Status: "success"} +) + +func ShouldBindBodyWithJSON(c *gin.Context, obj interface{}) (err error) { + err = c.ShouldBindBodyWith(obj, binding.JSON) + if err != nil { + SetAPIError(c, ErrBadRequest.WrapWithNoMessage(err)) + } + + return +} diff --git a/pkg/dashboard/apiserver/workflow/fx.go b/pkg/dashboard/apiserver/workflow/fx.go new file mode 100644 index 0000000000..f8ed601340 --- /dev/null +++ b/pkg/dashboard/apiserver/workflow/fx.go @@ -0,0 +1,27 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package workflow + +import ( + "github.com/go-logr/logr" + + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +func Bootstrap(conf *config.ChaosDashboardConfig, store core.WorkflowStore, logger logr.Logger) *Service { + return NewService(conf, store, logger.WithName("workflow-api")) +} diff --git a/pkg/dashboard/apiserver/workflow/workflow.go b/pkg/dashboard/apiserver/workflow/workflow.go new file mode 100644 index 0000000000..6d3df9f586 --- /dev/null +++ b/pkg/dashboard/apiserver/workflow/workflow.go @@ -0,0 +1,373 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package workflow + +import ( + "encoding/json" + "fmt" + "net/http" + "sort" + + "github.com/gin-gonic/gin" + "github.com/go-logr/logr" + apierrors "k8s.io/apimachinery/pkg/api/errors" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/clientpool" + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/curl" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/utils" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +func Register(r *gin.RouterGroup, s *Service) { + endpoint := r.Group("/workflows") + endpoint.GET("", s.listWorkflows) + endpoint.POST("", s.createWorkflow) + endpoint.GET("/:uid", s.getWorkflowDetailByUID) + endpoint.PUT("/:uid", s.updateWorkflow) + endpoint.DELETE("/:uid", s.deleteWorkflow) + endpoint.POST("/render-task/http", s.renderHTTPTask) + endpoint.POST("/parse-task/http", s.parseHTTPTask) + endpoint.POST("/validate-task/http", s.isValidRenderedHTTPTask) +} + +// Service defines a handler service for workflows. +type Service struct { + conf *config.ChaosDashboardConfig + store core.WorkflowStore + logger logr.Logger +} + +func NewService(conf *config.ChaosDashboardConfig, store core.WorkflowStore, logger logr.Logger) *Service { + return &Service{conf: conf, store: store, logger: logger} +} + +// @Summary Render a task which sends HTTP request +// @Description Render a task which sends HTTP request +// @Tags workflows +// @Produce json +// @Param request body curl.RequestForm true "Origin HTTP Request" +// @Success 200 {object} v1alpha1.Template +// @Failure 400 {object} utils.APIError +// @Failure 500 {object} utils.APIError +// @Router /workflows/render-task/http [post] +func (it *Service) renderHTTPTask(c *gin.Context) { + requestBody := curl.RequestForm{} + if err := c.ShouldBindJSON(&requestBody); err != nil { + utils.SetAPIError(c, utils.ErrBadRequest.Wrap(err, "failed to parse request body")) + return + } + result, err := curl.RenderWorkflowTaskTemplate(requestBody) + if err != nil { + utils.SetAPIError(c, utils.ErrInternalServer.Wrap(err, "failed to parse request body")) + return + } + c.JSON(http.StatusOK, result) +} + +// @Summary Validate the given template is a valid rendered HTTP Task +// @Description Validate the given template is a valid rendered HTTP Task +// @Tags workflows +// @Produce json +// @Param request body v1alpha1.Template true "Rendered Task" +// @Router /workflows/validate-task/http [post] +// @Success 200 {object} bool +// @Failure 400 {object} utils.APIError +// @Failure 500 {object} utils.APIError +func (it *Service) isValidRenderedHTTPTask(c *gin.Context) { + requestBody := v1alpha1.Template{} + if err := c.ShouldBindJSON(&requestBody); err != nil { + utils.SetAPIError(c, utils.ErrBadRequest.Wrap(err, "failed to parse request body")) + return + } + result := curl.IsValidRenderedTask(&requestBody) + c.JSON(http.StatusOK, result) +} + +// @Summary Parse the rendered task back to the original request +// @Description Parse the rendered task back to the original request +// @Tags workflows +// @Produce json +// @Param request body v1alpha1.Template true "Rendered Task" +// @Router /workflows/parse-task/http [post] +// @Success 200 {object} curl.RequestForm +// @Failure 400 {object} utils.APIError +// @Failure 500 {object} utils.APIError +func (it *Service) parseHTTPTask(c *gin.Context) { + requestBody := v1alpha1.Template{} + if err := c.ShouldBindJSON(&requestBody); err != nil { + utils.SetAPIError(c, utils.ErrBadRequest.Wrap(err, "failed to parse request body")) + return + } + result, err := curl.ParseWorkflowTaskTemplate(&requestBody) + if err != nil { + utils.SetAPIError(c, utils.ErrInternalServer.Wrap(err, "failed to parse request body")) + return + } + c.JSON(http.StatusOK, result) +} + +// @Summary List workflows from Kubernetes cluster. +// @Description List workflows from Kubernetes cluster. +// @Tags workflows +// @Produce json +// @Param namespace query string false "namespace, given empty string means list from all namespace" +// @Param status query string false "status" Enums(Initializing, Running, Errored, Finished) +// @Success 200 {array} core.WorkflowMeta +// @Router /workflows [get] +// @Failure 500 {object} utils.APIError +func (it *Service) listWorkflows(c *gin.Context) { + namespace := c.Query("namespace") + if len(namespace) == 0 && !it.conf.ClusterScoped && + len(it.conf.TargetNamespace) != 0 { + namespace = it.conf.TargetNamespace + } + + result := make([]core.WorkflowMeta, 0) + + kubeClient, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + _ = c.Error(utils.ErrBadRequest.WrapWithNoMessage(err)) + return + } + repo := core.NewKubeWorkflowRepository(kubeClient) + + if namespace != "" { + workflowFromNs, err := repo.ListByNamespace(c.Request.Context(), namespace) + if err != nil { + utils.SetAPImachineryError(c, err) + return + } + result = append(result, workflowFromNs...) + } else { + allWorkflow, err := repo.List(c.Request.Context()) + if err != nil { + utils.SetAPImachineryError(c, err) + return + } + result = append(result, allWorkflow...) + } + + // enriching with ID + for index, item := range result { + entity, err := it.store.FindByUID(c.Request.Context(), string(item.UID)) + if err != nil { + it.logger.Info("warning: workflow does not have a record in database", + "namespaced name", fmt.Sprintf("%s/%s", item.Namespace, item.Name), + "uid", item.UID, + ) + } + + if entity != nil { + result[index].ID = entity.ID + } + } + + sort.Slice(result, func(i, j int) bool { + return result[i].CreatedAt.After(result[i].CreatedAt) + }) + + c.JSON(http.StatusOK, result) +} + +// @Summary Get detailed information about the specified workflow. +// @Description Get detailed information about the specified workflow. If that object is not existed in kubernetes, it will only return ths persisted data in the database. +// @Tags workflows +// @Produce json +// @Param uid path string true "uid" +// @Router /workflows/{uid} [GET] +// @Success 200 {object} core.WorkflowDetail +// @Failure 400 {object} utils.APIError +// @Failure 500 {object} utils.APIError +func (it *Service) getWorkflowDetailByUID(c *gin.Context) { + uid := c.Param("uid") + + entity, err := it.store.FindByUID(c.Request.Context(), uid) + if err != nil { + utils.SetAPImachineryError(c, err) + return + } + + namespace := entity.Namespace + name := entity.Name + + kubeClient, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + if apierrors.IsNotFound(err) { + // if not exists in kubernetes anymore, return the persisted entity directly. + workflowDetail, err := core.WorkflowEntity2WorkflowDetail(entity) + if err != nil { + utils.SetAPImachineryError(c, err) + return + } + c.JSON(http.StatusOK, workflowDetail) + return + } + _ = c.Error(utils.ErrBadRequest.WrapWithNoMessage(err)) + return + } + + // enriching the topology and spec/status with CR in kubernetes + repo := core.NewKubeWorkflowRepository(kubeClient) + + workflowCRInKubernetes, err := repo.Get(c.Request.Context(), namespace, name) + if err != nil { + utils.SetAPImachineryError(c, err) + return + } + result, err := core.WorkflowEntity2WorkflowDetail(entity) + if err != nil { + utils.SetAPImachineryError(c, err) + return + } + result.Topology = workflowCRInKubernetes.Topology + result.KubeObject = workflowCRInKubernetes.KubeObject + + c.JSON(http.StatusOK, result) +} + +// @Summary Create a new workflow. +// @Description Create a new workflow. +// @Tags workflows +// @Produce json +// @Param request body v1alpha1.Workflow true "Request body" +// @Success 200 {object} core.WorkflowDetail +// @Failure 400 {object} utils.APIError +// @Failure 500 {object} utils.APIError +// @Router /workflows [post] +func (it *Service) createWorkflow(c *gin.Context) { + payload := v1alpha1.Workflow{} + + err := json.NewDecoder(c.Request.Body).Decode(&payload) + if err != nil { + _ = c.Error(utils.ErrInternalServer.Wrap(err, "failed to parse request body")) + return + } + + kubeClient, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + utils.SetAPImachineryError(c, err) + return + } + + repo := core.NewKubeWorkflowRepository(kubeClient) + + result, err := repo.Create(c.Request.Context(), payload) + if err != nil { + utils.SetAPImachineryError(c, err) + return + } + c.JSON(http.StatusOK, result) +} + +// @Summary Delete the specified workflow. +// @Description Delete the specified workflow. +// @Tags workflows +// @Produce json +// @Param uid path string true "uid" +// @Success 200 {object} utils.Response +// @Failure 400 {object} utils.APIError +// @Failure 404 {object} utils.APIError +// @Failure 500 {object} utils.APIError +// @Router /workflows/{uid} [delete] +func (it *Service) deleteWorkflow(c *gin.Context) { + uid := c.Param("uid") + + entity, err := it.store.FindByUID(c.Request.Context(), uid) + if err != nil { + utils.SetAPImachineryError(c, err) + return + } + + namespace := entity.Namespace + name := entity.Name + + kubeClient, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + _ = c.Error(utils.ErrBadRequest.WrapWithNoMessage(err)) + return + } + + repo := core.NewKubeWorkflowRepository(kubeClient) + + err = repo.Delete(c.Request.Context(), namespace, name) + if err != nil { + utils.SetAPImachineryError(c, err) + return + } + c.JSON(http.StatusOK, utils.ResponseSuccess) +} + +// @Summary Update a workflow. +// @Description Update a workflow. +// @Tags workflows +// @Produce json +// @Param uid path string true "uid" +// @Param request body v1alpha1.Workflow true "Request body" +// @Success 200 {object} core.WorkflowDetail +// @Failure 400 {object} utils.APIError +// @Failure 500 {object} utils.APIError +// @Router /workflows/{uid} [put] +func (it *Service) updateWorkflow(c *gin.Context) { + payload := v1alpha1.Workflow{} + + err := json.NewDecoder(c.Request.Body).Decode(&payload) + if err != nil { + utils.SetAPIError(c, utils.ErrInternalServer.Wrap(err, "failed to parse request body")) + return + } + uid := c.Param("uid") + entity, err := it.store.FindByUID(c.Request.Context(), uid) + if err != nil { + utils.SetAPImachineryError(c, err) + return + } + + namespace := entity.Namespace + name := entity.Name + + if namespace != payload.Namespace { + utils.SetAPIError(c, utils.ErrBadRequest.Wrap(err, + "namespace is not consistent, pathParameter: %s, metaInRaw: %s", + namespace, + payload.Namespace)) + return + } + if name != payload.Name { + utils.SetAPIError(c, utils.ErrBadRequest.Wrap(err, + "name is not consistent, pathParameter: %s, metaInRaw: %s", + name, + payload.Name)) + return + } + + kubeClient, err := clientpool.ExtractTokenAndGetClient(c.Request.Header) + if err != nil { + utils.SetAPImachineryError(c, err) + return + } + + repo := core.NewKubeWorkflowRepository(kubeClient) + + result, err := repo.Update(c.Request.Context(), namespace, name, payload) + if err != nil { + utils.SetAPImachineryError(c, err) + return + } + + c.JSON(http.StatusOK, result) +} diff --git a/pkg/apivalidator/base_validator.go b/pkg/dashboard/apivalidator/base_validator.go similarity index 87% rename from pkg/apivalidator/base_validator.go rename to pkg/dashboard/apivalidator/base_validator.go index e04e69d150..73461fda08 100644 --- a/pkg/apivalidator/base_validator.go +++ b/pkg/dashboard/apivalidator/base_validator.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package apivalidator @@ -39,7 +41,7 @@ func NameValid(fl validator.FieldLevel) bool { return true } -var namePattern = regexp.MustCompile("^[-.\\w]*$") +var namePattern = regexp.MustCompile(`^[-.\w]*$`) // checkName can be used to check resource names. func checkName(name string) bool { diff --git a/pkg/apivalidator/scope_validator.go b/pkg/dashboard/apivalidator/scope_validator.go similarity index 84% rename from pkg/apivalidator/scope_validator.go rename to pkg/dashboard/apivalidator/scope_validator.go index 29f73953e0..3e6205600f 100644 --- a/pkg/apivalidator/scope_validator.go +++ b/pkg/dashboard/apivalidator/scope_validator.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package apivalidator @@ -175,3 +177,29 @@ func PodsValid(fl validator.FieldLevel) bool { return true } + +// PhysicalMachineValid can be used to check whether the physicalMachine name is valid. +func PhysicalMachineValid(fl validator.FieldLevel) bool { + if fl.Field().IsNil() { + return true + } + + physicalMachines, ok := fl.Field().Interface().(map[string][]string) + if !ok { + return false + } + + for ns, ps := range physicalMachines { + if !checkName(ns) { + return false + } + + for _, p := range ps { + if !checkName(p) { + return false + } + } + } + + return true +} diff --git a/pkg/apivalidator/target_validator.go b/pkg/dashboard/apivalidator/target_validator.go similarity index 94% rename from pkg/apivalidator/target_validator.go rename to pkg/dashboard/apivalidator/target_validator.go index 3baa7c0aa1..ad8d3a36cd 100644 --- a/pkg/apivalidator/target_validator.go +++ b/pkg/dashboard/apivalidator/target_validator.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package apivalidator diff --git a/pkg/dashboard/collector/collector.go b/pkg/dashboard/collector/collector.go new file mode 100644 index 0000000000..4b1254c985 --- /dev/null +++ b/pkg/dashboard/collector/collector.go @@ -0,0 +1,208 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package collector + +import ( + "context" + "encoding/json" + + "github.com/go-logr/logr" + "github.com/jinzhu/gorm" + "github.com/pkg/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +// ChaosCollector represents a collector for Chaos Object. +type ChaosCollector struct { + client.Client + Log logr.Logger + apiType runtime.Object + archive core.ExperimentStore + event core.EventStore +} + +// Reconcile reconciles a chaos collector. +func (r *ChaosCollector) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + if r.apiType == nil { + r.Log.Error(nil, "apiType has not been initialized") + return ctrl.Result{}, nil + } + + obj, ok := r.apiType.DeepCopyObject().(v1alpha1.InnerObject) + if !ok { + r.Log.Error(nil, "it's not a stateful object") + return ctrl.Result{}, nil + } + + err := r.Get(ctx, req.NamespacedName, obj) + if apierrors.IsNotFound(err) { + if err = r.archiveExperiment(req.Namespace, req.Name); err != nil { + r.Log.Error(err, "failed to archive experiment") + } + + // If the experiment was created by schedule or workflow, + // it and its events will be deleted from database. + if err = r.deleteManagedExperiments(req.Namespace, req.Name); err != nil { + r.Log.Error(err, "delete managed experiments", "namespace", req.Namespace, "name", req.Name) + } + + return ctrl.Result{}, nil + } + + if err != nil { + r.Log.Error(err, "failed to get chaos object", "request", req.NamespacedName) + return ctrl.Result{}, nil + } + + if err := r.setUnarchivedExperiment(req, obj); err != nil { + r.Log.Error(err, "failed to archive experiment") + // ignore error here + } + + return ctrl.Result{}, nil +} + +// Setup setups collectors by Manager. +func (r *ChaosCollector) Setup(mgr ctrl.Manager, apiType client.Object) error { + r.apiType = apiType + + return ctrl.NewControllerManagedBy(mgr). + For(apiType). + Complete(r) +} + +func (r *ChaosCollector) setUnarchivedExperiment(req ctrl.Request, obj v1alpha1.InnerObject) error { + archive, err := convertInnerObjectToExperiment(obj) + if err != nil { + r.Log.Error(err, "failed to covert InnerObject") + return err + } + + find, err := r.archive.FindByUID(context.Background(), archive.UID) + if err != nil && !gorm.IsRecordNotFoundError(err) { + r.Log.Error(err, "failed to find experiment", "UID", archive.UID) + return err + } + + if find != nil { + archive.ID = find.ID + archive.CreatedAt = find.CreatedAt + archive.UpdatedAt = find.UpdatedAt + } + + if err := r.archive.Set(context.Background(), archive); err != nil { + r.Log.Error(err, "failed to update experiment", "archive", archive) + return err + } + + return nil +} + +func (r *ChaosCollector) archiveExperiment(ns, name string) error { + if err := r.archive.Archive(context.Background(), ns, name); err != nil { + r.Log.Error(err, "failed to archive experiment", "namespace", ns, "name", name) + return err + } + + return nil +} + +func (r *ChaosCollector) deleteManagedExperiments(ns, name string) error { + archives, err := r.archive.FindManagedByNamespaceName(context.Background(), ns, name) + if gorm.IsRecordNotFoundError(err) { + return nil + } + + if err != nil { + return err + } + + for _, expr := range archives { + if err = r.event.DeleteByUID(context.Background(), expr.UID); err != nil { + r.Log.Error(err, "failed to delete experiment related events") + } + + if err = r.archive.Delete(context.Background(), expr); err != nil { + r.Log.Error(err, "failed to delete managed experiment") + } + } + + return nil +} + +func convertInnerObjectToExperiment(obj v1alpha1.InnerObject) (*core.Experiment, error) { + chaosMeta, ok := obj.(metav1.Object) + if !ok { + return nil, errors.New("chaos meta information not found") + } + UID := string(chaosMeta.GetUID()) + + archive := &core.Experiment{ + ExperimentMeta: core.ExperimentMeta{ + Namespace: chaosMeta.GetNamespace(), + Name: chaosMeta.GetName(), + Kind: obj.GetObjectKind().GroupVersionKind().Kind, + UID: UID, + Archived: false, + }, + } + + switch chaos := obj.(type) { + case *v1alpha1.PodChaos: + archive.Action = string(chaos.Spec.Action) + case *v1alpha1.NetworkChaos: + archive.Action = string(chaos.Spec.Action) + case *v1alpha1.IOChaos: + archive.Action = string(chaos.Spec.Action) + case *v1alpha1.TimeChaos, *v1alpha1.KernelChaos, *v1alpha1.StressChaos, *v1alpha1.HTTPChaos: + archive.Action = "" + case *v1alpha1.DNSChaos: + archive.Action = string(chaos.Spec.Action) + case *v1alpha1.PhysicalMachineChaos: + archive.Action = string(chaos.Spec.Action) + case *v1alpha1.AWSChaos: + archive.Action = string(chaos.Spec.Action) + case *v1alpha1.GCPChaos: + archive.Action = string(chaos.Spec.Action) + case *v1alpha1.JVMChaos: + archive.Action = string(chaos.Spec.Action) + case *v1alpha1.BlockChaos: + archive.Action = string(chaos.Spec.Action) + default: + return nil, errors.New("unsupported chaos type " + archive.Kind) + } + + archive.StartTime = chaosMeta.GetCreationTimestamp().Time + if chaosMeta.GetDeletionTimestamp() != nil { + archive.FinishTime = &chaosMeta.GetDeletionTimestamp().Time + } + + data, err := json.Marshal(chaosMeta) + if err != nil { + return nil, err + } + + archive.Experiment = string(data) + + return archive, nil +} diff --git a/pkg/dashboard/collector/event_collector.go b/pkg/dashboard/collector/event_collector.go new file mode 100644 index 0000000000..8dd660d6ce --- /dev/null +++ b/pkg/dashboard/collector/event_collector.go @@ -0,0 +1,151 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package collector + +import ( + "context" + + "github.com/go-logr/logr" + v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +// EventCollector represents a collector for Event Object. +type EventCollector struct { + client.Client + Log logr.Logger + apiType runtime.Object + event core.EventStore +} + +// Reconcile reconciles a Event collector. +func (r *EventCollector) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + if r.apiType == nil { + r.Log.Error(nil, "apiType has not been initialized") + return ctrl.Result{}, nil + } + + event := &v1.Event{} + err := r.Get(ctx, req.NamespacedName, event) + if err != nil { + if !apierrors.IsNotFound(err) { + r.Log.Error(err, "unable to get event") + } + return ctrl.Result{}, nil + } + chaosKind, ok := v1alpha1.AllKinds()[event.InvolvedObject.Kind] + if ok { + chaosObject := chaosKind.SpawnObject() + + if err = r.Get(ctx, types.NamespacedName{ + Namespace: event.InvolvedObject.Namespace, + Name: event.InvolvedObject.Name, + }, chaosObject); err != nil { + return ctrl.Result{}, nil + } + } else if event.InvolvedObject.Kind == v1alpha1.KindSchedule { + if err = r.Get(ctx, types.NamespacedName{ + Namespace: event.InvolvedObject.Namespace, + Name: event.InvolvedObject.Name, + }, &v1alpha1.Schedule{}); err != nil { + return ctrl.Result{}, nil + } + } else if event.InvolvedObject.Kind == v1alpha1.KindWorkflow { + if err = r.Get(ctx, types.NamespacedName{ + Namespace: event.InvolvedObject.Namespace, + Name: event.InvolvedObject.Name, + }, &v1alpha1.Workflow{}); err != nil { + return ctrl.Result{}, nil + } + } else if event.InvolvedObject.Kind == v1alpha1.KindWorkflowNode { + if err = r.Get(ctx, types.NamespacedName{ + Namespace: event.InvolvedObject.Namespace, + Name: event.InvolvedObject.Name, + }, &v1alpha1.WorkflowNode{}); err != nil { + return ctrl.Result{}, nil + } + } else { + r.Log.Info("event collector: omitted event", "involved object name", event.InvolvedObject.Name, "involved object namespace", event.InvolvedObject.Namespace, "involved object kind", event.InvolvedObject.Kind) + return ctrl.Result{}, nil + } + + et := core.Event{ + CreatedAt: event.CreationTimestamp.Time.UTC(), + Kind: event.InvolvedObject.Kind, + Type: event.Type, + Reason: event.Reason, + Message: event.Message, + Name: event.InvolvedObject.Name, + Namespace: event.InvolvedObject.Namespace, + ObjectID: string(event.InvolvedObject.UID), + } + if err := r.event.Create(context.Background(), &et); err != nil { + r.Log.Error(err, "failed to save event", "event", et) + } + + return ctrl.Result{}, nil +} + +// Setup setups collectors by Manager. +func (r *EventCollector) Setup(mgr ctrl.Manager, apiType client.Object) error { + r.apiType = apiType + + return ctrl.NewControllerManagedBy(mgr). + For(apiType). + WithEventFilter(predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + event, ok := e.Object.(*v1.Event) + if !ok { + return false + } + flag := false + _, ok = v1alpha1.AllKinds()[event.InvolvedObject.Kind] + if ok { + flag = true + } + if event.InvolvedObject.Kind == v1alpha1.KindSchedule { + flag = true + } + if event.InvolvedObject.Kind == v1alpha1.KindWorkflow { + flag = true + } + if event.InvolvedObject.Kind == v1alpha1.KindWorkflowNode { + flag = true + } + return flag + + }, + DeleteFunc: func(e event.DeleteEvent) bool { + return false + }, + UpdateFunc: func(e event.UpdateEvent) bool { + return false + }, + GenericFunc: func(e event.GenericEvent) bool { + return false + }, + }). + Complete(r) +} diff --git a/pkg/dashboard/collector/fx.go b/pkg/dashboard/collector/fx.go new file mode 100644 index 0000000000..26ace1ff0a --- /dev/null +++ b/pkg/dashboard/collector/fx.go @@ -0,0 +1,36 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package collector + +import ( + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +func Bootstrap( + conf *config.ChaosDashboardConfig, + experimentArchive core.ExperimentStore, + scheduleArchive core.ScheduleStore, + event core.EventStore, + workflowStore core.WorkflowStore, + logger logr.Logger, +) (*Server, client.Client, client.Reader, *runtime.Scheme) { + return NewServer(conf, experimentArchive, scheduleArchive, event, workflowStore, logger.WithName("collector")) +} diff --git a/pkg/dashboard/collector/schedule_collector.go b/pkg/dashboard/collector/schedule_collector.go new file mode 100644 index 0000000000..e32e06c277 --- /dev/null +++ b/pkg/dashboard/collector/schedule_collector.go @@ -0,0 +1,154 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package collector + +import ( + "context" + "encoding/json" + + "github.com/go-logr/logr" + "github.com/jinzhu/gorm" + "github.com/pkg/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +// ScheduleCollector represents a collector for Schedule Object. +type ScheduleCollector struct { + client.Client + Log logr.Logger + apiType runtime.Object + archive core.ScheduleStore +} + +// Reconcile reconciles a Schedule collector. +func (r *ScheduleCollector) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + if r.apiType == nil { + r.Log.Error(nil, "apiType has not been initialized") + return ctrl.Result{}, nil + } + + schedule := &v1alpha1.Schedule{} + err := r.Get(ctx, req.NamespacedName, schedule) + if apierrors.IsNotFound(err) { + if err = r.archiveSchedule(req.Namespace, req.Name); err != nil { + r.Log.Error(err, "failed to archive schedule") + } + return ctrl.Result{}, nil + } + if err != nil { + r.Log.Error(err, "failed to get schedule object", "request", req.NamespacedName) + return ctrl.Result{}, nil + } + + if err := r.setUnarchivedSchedule(req, *schedule); err != nil { + r.Log.Error(err, "failed to archive schedule") + // ignore error here + } + + return ctrl.Result{}, nil +} + +// Setup setups collectors by Manager. +func (r *ScheduleCollector) Setup(mgr ctrl.Manager, apiType client.Object) error { + r.apiType = apiType + + return ctrl.NewControllerManagedBy(mgr). + For(apiType). + Complete(r) +} + +func (r *ScheduleCollector) setUnarchivedSchedule(req ctrl.Request, schedule v1alpha1.Schedule) error { + archive := &core.Schedule{ + ScheduleMeta: core.ScheduleMeta{ + Namespace: req.Namespace, + Name: req.Name, + Kind: schedule.Kind, + UID: string(schedule.UID), + Archived: false, + }, + } + + switch schedule.Spec.Type { + case v1alpha1.ScheduleTypePodChaos: + archive.Action = string(schedule.Spec.ScheduleItem.PodChaos.Action) + case v1alpha1.ScheduleTypeNetworkChaos: + archive.Action = string(schedule.Spec.ScheduleItem.NetworkChaos.Action) + case v1alpha1.ScheduleTypeIOChaos: + archive.Action = string(schedule.Spec.ScheduleItem.IOChaos.Action) + case v1alpha1.ScheduleTypeTimeChaos, v1alpha1.ScheduleTypeKernelChaos, v1alpha1.ScheduleTypeStressChaos, v1alpha1.ScheduleTypeHTTPChaos: + archive.Action = "" + case v1alpha1.ScheduleTypeDNSChaos: + archive.Action = string(schedule.Spec.ScheduleItem.DNSChaos.Action) + case v1alpha1.ScheduleTypeAWSChaos: + archive.Action = string(schedule.Spec.ScheduleItem.AWSChaos.Action) + case v1alpha1.ScheduleTypeGCPChaos: + archive.Action = string(schedule.Spec.ScheduleItem.GCPChaos.Action) + case v1alpha1.ScheduleTypeJVMChaos: + archive.Action = string(schedule.Spec.ScheduleItem.JVMChaos.Action) + case v1alpha1.ScheduleTypePhysicalMachineChaos: + archive.Action = string(schedule.Spec.ScheduleItem.PhysicalMachineChaos.Action) + default: + return errors.New("unsupported chaos type " + string(schedule.Spec.Type)) + } + + archive.StartTime = schedule.GetCreationTimestamp().Time + if schedule.GetDeletionTimestamp() != nil { + archive.FinishTime = &schedule.GetDeletionTimestamp().Time + } + + data, err := json.Marshal(schedule) + if err != nil { + r.Log.Error(err, "failed to marshal schedule", "kind", archive.Kind, + "namespace", archive.Namespace, "name", archive.Name) + return err + } + + archive.Schedule = string(data) + + find, err := r.archive.FindByUID(context.Background(), string(schedule.UID)) + if err != nil && !gorm.IsRecordNotFoundError(err) { + r.Log.Error(err, "failed to find schedule", "UID", schedule.UID) + return err + } + + if find != nil { + archive.ID = find.ID + archive.CreatedAt = find.CreatedAt + archive.UpdatedAt = find.UpdatedAt + } + + if err := r.archive.Set(context.Background(), archive); err != nil { + r.Log.Error(err, "failed to update schedule", "archive", archive) + return err + } + + return nil +} + +func (r *ScheduleCollector) archiveSchedule(ns, name string) error { + if err := r.archive.Archive(context.Background(), ns, name); err != nil { + r.Log.Error(err, "failed to archive schedule", "namespace", ns, "name", name) + return err + } + + return nil +} diff --git a/pkg/dashboard/collector/server.go b/pkg/dashboard/collector/server.go new file mode 100644 index 0000000000..c98b0c41c0 --- /dev/null +++ b/pkg/dashboard/collector/server.go @@ -0,0 +1,172 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package collector + +import ( + "context" + "net" + "os" + "strconv" + + "github.com/go-logr/logr" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/clientpool" + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +var ( + scheme = runtime.NewScheme() +) + +func init() { + _ = clientgoscheme.AddToScheme(scheme) + + _ = v1alpha1.AddToScheme(scheme) +} + +// Server defines a server to manage collectors. +type Server struct { + Manager ctrl.Manager + logger logr.Logger +} + +// NewServer returns a CollectorServer and Client. +func NewServer( + conf *config.ChaosDashboardConfig, + experimentArchive core.ExperimentStore, + scheduleArchive core.ScheduleStore, + event core.EventStore, + workflowStore core.WorkflowStore, + logger logr.Logger, +) (*Server, client.Client, client.Reader, *runtime.Scheme) { + s := &Server{logger: logger} + + // namespace scoped + options := ctrl.Options{ + Scheme: scheme, + Metrics: metricsserver.Options{ + BindAddress: net.JoinHostPort(conf.MetricHost, strconv.Itoa(conf.MetricPort)), + }, + LeaderElection: conf.EnableLeaderElection, + WebhookServer: webhook.NewServer(webhook.Options{ + Port: 9443, + }), + } + if conf.ClusterScoped { + logger.Info("Chaos controller manager is running in cluster scoped mode.") + } else { + logger.Info("Chaos controller manager is running in namespace scoped mode.", "targetNamespace", conf.TargetNamespace) + options.NewCache = func(cfg *rest.Config, opts cache.Options) (cache.Cache, error) { + opts.DefaultNamespaces = map[string]cache.Config{ + conf.TargetNamespace: {}, + } + return cache.New(cfg, opts) + } + } + + var err error + + cfg := ctrl.GetConfigOrDie() + + if conf.QPS > 0 { + cfg.QPS = conf.QPS + cfg.Burst = conf.Burst + } + + s.Manager, err = ctrl.NewManager(cfg, options) + if err != nil { + logger.Error(err, "unable to start collector") + os.Exit(1) + } + + if conf.SecurityMode { + clientpool.K8sClients, err = clientpool.NewClientPool(cfg, scheme, 100) + if err != nil { + // this should never happen + logger.Error(err, "fail to create client pool") + os.Exit(1) + } + } else { + clientpool.K8sClients, err = clientpool.NewLocalClient(cfg, scheme) + if err != nil { + logger.Error(err, "fail to create client pool") + os.Exit(1) + } + } + + for kind, chaosKind := range v1alpha1.AllKinds() { + if err = (&ChaosCollector{ + Client: s.Manager.GetClient(), + Log: logger.WithName(kind), + archive: experimentArchive, + event: event, + }).Setup(s.Manager, chaosKind.SpawnObject()); err != nil { + logger.Error(err, "unable to create collector", "collector", kind) + os.Exit(1) + } + } + + if err = (&ScheduleCollector{ + Client: s.Manager.GetClient(), + Log: logger.WithName("schedule-collector").WithName(v1alpha1.KindSchedule), + archive: scheduleArchive, + }).Setup(s.Manager, &v1alpha1.Schedule{}); err != nil { + logger.Error(err, "unable to create collector", "collector", v1alpha1.KindSchedule) + os.Exit(1) + } + + if err = (&EventCollector{ + Client: s.Manager.GetClient(), + Log: logger.WithName("event-collector").WithName("Event"), + event: event, + }).Setup(s.Manager, &v1.Event{}); err != nil { + logger.Error(err, "unable to create collector", "collector", v1alpha1.KindSchedule) + os.Exit(1) + } + + if err = (&WorkflowCollector{ + kubeClient: s.Manager.GetClient(), + Log: logger.WithName("workflow-collector").WithName(v1alpha1.KindWorkflow), + store: workflowStore, + }).Setup(s.Manager, &v1alpha1.Workflow{}); err != nil { + logger.Error(err, "unable to create collector", "collector", v1alpha1.KindWorkflow) + os.Exit(1) + } + + return s, s.Manager.GetClient(), s.Manager.GetAPIReader(), s.Manager.GetScheme() +} + +// Register starts collectors manager. +func Register(ctx context.Context, s *Server) { + go func() { + s.logger.Info("Starting collector") + if err := s.Manager.Start(ctx); err != nil { + s.logger.Error(err, "could not start collector") + os.Exit(1) + } + }() +} diff --git a/pkg/dashboard/collector/workflow_collector.go b/pkg/dashboard/collector/workflow_collector.go new file mode 100644 index 0000000000..bef1b29ab2 --- /dev/null +++ b/pkg/dashboard/collector/workflow_collector.go @@ -0,0 +1,99 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package collector + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/jinzhu/gorm" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +type WorkflowCollector struct { + kubeClient client.Client + Log logr.Logger + apiType runtime.Object + store core.WorkflowStore +} + +func (it *WorkflowCollector) Setup(mgr ctrl.Manager, apiType client.Object) error { + it.apiType = apiType + + return ctrl.NewControllerManagedBy(mgr). + For(apiType). + Complete(it) +} + +func (it *WorkflowCollector) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { + if it.apiType == nil { + it.Log.Error(nil, "apiType has not been initialized") + return ctrl.Result{}, nil + } + workflow := v1alpha1.Workflow{} + err := it.kubeClient.Get(ctx, request.NamespacedName, &workflow) + if apierrors.IsNotFound(err) { + // target + if err = it.markAsArchived(ctx, request.Namespace, request.Name); err != nil { + it.Log.Error(err, "failed to archive experiment") + } + return ctrl.Result{}, nil + } + if err != nil { + it.Log.Error(err, "failed to get workflow object", "request", request.NamespacedName) + return ctrl.Result{}, nil + } + + if err := it.persistentWorkflow(&workflow); err != nil { + it.Log.Error(err, "failed to archive workflow") + } + + return ctrl.Result{}, nil +} + +func (it *WorkflowCollector) markAsArchived(ctx context.Context, namespace, name string) error { + return it.store.MarkAsArchived(ctx, namespace, name) +} + +func (it *WorkflowCollector) persistentWorkflow(workflow *v1alpha1.Workflow) error { + newEntity, err := core.WorkflowCR2WorkflowEntity(workflow) + if err != nil { + return err + } + + existedEntity, err := it.store.FindByUID(context.Background(), string(workflow.UID)) + if err != nil && !gorm.IsRecordNotFoundError(err) { + it.Log.Error(err, "failed to find workflow", "UID", workflow.UID) + return err + } + + if existedEntity != nil { + newEntity.ID = existedEntity.ID + } + + err = it.store.Save(context.Background(), newEntity) + if err != nil { + it.Log.Error(err, "failed to update workflow", "archive", newEntity) + } + return err +} diff --git a/pkg/dashboard/core/common.go b/pkg/dashboard/core/common.go new file mode 100644 index 0000000000..fba2315726 --- /dev/null +++ b/pkg/dashboard/core/common.go @@ -0,0 +1,109 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package core + +import ( + "encoding/json" + "strings" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type ObjectBase struct { + Namespace string `json:"namespace"` + Name string `json:"name"` + Kind string `json:"kind"` + UID string `json:"uid"` + Created string `json:"created_at"` +} + +// KubeObjectDesc defines a simple kube object description which uses in apiserver. +type KubeObjectDesc struct { + metav1.TypeMeta + Meta KubeObjectMeta `json:"metadata"` + Spec interface{} `json:"spec"` +} + +// KubeObjectMetadata extracts the required fields from metav1.ObjectMeta. +type KubeObjectMeta struct { + Namespace string `json:"namespace"` + Name string `json:"name"` + Labels map[string]string `json:"labels,omitempty"` + Annotations map[string]string `json:"annotations,omitempty"` +} + +type Filter struct { + ObjectID string `json:"object_id"` + Start string `json:"start"` + End string `json:"end"` + Namespace string `json:"namespace"` + Name string `json:"name"` + Kind string `json:"kind"` + Limit string `json:"limit"` +} + +func (f *Filter) toMap() map[string]interface{} { + var fMap map[string]interface{} + + marshal, _ := json.Marshal(f) + _ = json.Unmarshal(marshal, &fMap) + + return fMap +} + +const zeroTime = "0001-01-01 00:00:00" + +func (f *Filter) ConstructQueryArgs() (string, []interface{}) { + fMap, query, args := f.toMap(), make([]string, 0), make([]interface{}, 0) + + for k, v := range fMap { + if v != "" { + if k == "start" || k == "end" || k == "limit" { + continue + } + + if len(args) > 0 { + query = append(query, "AND", k, "= ?") + } else { + query = append(query, k, "= ?") + } + + args = append(args, v) + } + } + + startEnd := "" + if f.Start != zeroTime && f.End != zeroTime { + startEnd = "created_at BETWEEN ? AND ?" + args = append(args, f.Start, f.End) + } else if f.Start != zeroTime && f.End == zeroTime { + startEnd = "created_at >= ?" + args = append(args, f.Start) + } else if f.Start == zeroTime && f.End != zeroTime { + startEnd = "created_at <= ?" + args = append(args, f.End) + } + + if startEnd != "" { + if len(query) > 0 { + query = append(query, "AND", startEnd) + } else { + query = append(query, startEnd) + } + } + + return strings.Join(query, " "), args +} diff --git a/pkg/dashboard/core/event.go b/pkg/dashboard/core/event.go new file mode 100644 index 0000000000..fa102b73da --- /dev/null +++ b/pkg/dashboard/core/event.go @@ -0,0 +1,68 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package core + +import ( + "context" + "time" +) + +// EventStore defines operations for working with events. +type EventStore interface { + // List returns an event list from the datastore. + List(context.Context) ([]*Event, error) + + // ListByUID returns an event list by the UID. + ListByUID(context.Context, string) ([]*Event, error) + + // ListByUIDs returns an event list by the UID list. + ListByUIDs(context.Context, []string) ([]*Event, error) + + // ListByExperiment returns an event list by the namespace, name, or kind. + ListByExperiment(context context.Context, namespace string, name string, kind string) ([]*Event, error) + + ListByFilter(context.Context, Filter) ([]*Event, error) + + // Find returns an event by ID. + Find(context.Context, uint) (*Event, error) + + // Create persists a new event to the datastore. + Create(context.Context, *Event) error + + // DeleteByUID deletes events by the UID. + DeleteByUID(context.Context, string) error + + // DeleteByUIDs deletes events by the UID list. + DeleteByUIDs(context.Context, []string) error + + // DeleteByTime deletes events within the specified time interval. + DeleteByTime(context.Context, string, string) error + + // DeleteByDuration selete events that exceed duration. + DeleteByDuration(context.Context, time.Duration) error +} + +type Event struct { + ID uint `gorm:"primary_key" json:"id"` + ObjectID string `gorm:"index:object_id" json:"object_id"` + CreatedAt time.Time `json:"created_at"` + Namespace string `json:"namespace"` + Name string `json:"name"` + Kind string `json:"kind"` + Type string `json:"type"` + Reason string `json:"reason"` + Message string `gorm:"type:text;size:32768" json:"message"` +} diff --git a/pkg/dashboard/core/experiment.go b/pkg/dashboard/core/experiment.go new file mode 100644 index 0000000000..eb5b17c0c8 --- /dev/null +++ b/pkg/dashboard/core/experiment.go @@ -0,0 +1,78 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package core + +import ( + "context" + "time" + + "github.com/jinzhu/gorm" +) + +// ExperimentStore defines operations for working with experiments. +type ExperimentStore interface { + // ListMeta returns experiment metadata list from the datastore. + ListMeta(ctx context.Context, kind, namespace, name string, archived bool) ([]*ExperimentMeta, error) + + // FindByUID returns an experiment by UID. + FindByUID(ctx context.Context, UID string) (*Experiment, error) + + // FindManagedByNamespaceName returns experiment list which are managed by schedule or workflow. + FindManagedByNamespaceName(ctx context.Context, namespace, name string) ([]*Experiment, error) + + // FindMetaByUID returns an experiment metadata by UID. + FindMetaByUID(context.Context, string) (*ExperimentMeta, error) + + // Set saves the experiment to datastore. + Set(context.Context, *Experiment) error + + // Archive archives experiments which "archived" field is false. + Archive(ctx context.Context, namespace, name string) error + + // Delete deletes the archive from the datastore. + Delete(context.Context, *Experiment) error + + // DeleteByFinishTime deletes archives which time difference is greater than the given time from FinishTime. + DeleteByFinishTime(context.Context, time.Duration) error + + // DeleteByUIDs deletes archives by the uid list. + DeleteByUIDs(context.Context, []string) error + + // DeleteIncompleteExperiments deletes all incomplete experiments. + // If the chaos-dashboard was restarted and the experiment is completed during the restart, + // which means the experiment would never save the finish_time. + // DeleteIncompleteExperiments can be used to delete all incomplete experiments to avoid this case. + DeleteIncompleteExperiments(context.Context) error +} + +// Experiment represents an experiment instance. Use in db. +type Experiment struct { + ExperimentMeta + Experiment string `gorm:"type:text;size:32768"` // JSON string +} + +// ExperimentMeta defines the metadata of an experiment. Use in db. +type ExperimentMeta struct { + gorm.Model + UID string `gorm:"index:uid" json:"uid"` + Kind string `json:"kind"` + Name string `json:"name"` + Namespace string `json:"namespace"` + Action string `json:"action"` + StartTime time.Time `json:"start_time"` + FinishTime *time.Time `json:"finish_time"` + Archived bool `json:"archived"` +} diff --git a/pkg/dashboard/core/schedule.go b/pkg/dashboard/core/schedule.go new file mode 100644 index 0000000000..744ac59121 --- /dev/null +++ b/pkg/dashboard/core/schedule.go @@ -0,0 +1,75 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package core + +import ( + "context" + "time" + + "github.com/jinzhu/gorm" +) + +// ScheduleStore defines operations for working with schedules. +type ScheduleStore interface { + // ListMeta returns schedule metadata list from the datastore. + ListMeta(ctx context.Context, namespace, name string, archived bool) ([]*ScheduleMeta, error) + + // FindByUID returns a schedule by UID. + FindByUID(ctx context.Context, UID string) (*Schedule, error) + + // FindMetaByUID returns a schedule metadata by UID. + FindMetaByUID(context.Context, string) (*ScheduleMeta, error) + + // Set saves the schedule to datastore. + Set(context.Context, *Schedule) error + + // Archive archives schedules which "archived" field is false. + Archive(ctx context.Context, namespace, name string) error + + // Delete deletes the archive from the datastore. + Delete(context.Context, *Schedule) error + + // DeleteByFinishTime deletes archives which time difference is greater than the given time from FinishTime. + DeleteByFinishTime(context.Context, time.Duration) error + + // DeleteByUIDs deletes archives by the uid list. + DeleteByUIDs(context.Context, []string) error + + // DeleteIncompleteSchedules deletes all incomplete schedules. + // If the chaos-dashboard was restarted and the schedule is completed during the restart, + // which means the schedule would never save the finish_time. + // DeleteIncompleteSchedules can be used to delete all incomplete schedules to avoid this case. + DeleteIncompleteSchedules(context.Context) error +} + +// Schedule represents a schedule instance. Use in db. +type Schedule struct { + ScheduleMeta + Schedule string `gorm:"type:text;size:32768"` // JSON string +} + +// ScheduleMeta defines the metadata of a schedule instance. Use in db. +type ScheduleMeta struct { + gorm.Model + UID string `gorm:"index:schedule_uid" json:"uid"` + Kind string `json:"kind"` + Name string `json:"name"` + Namespace string `json:"namespace"` + Action string `json:"action"` + StartTime time.Time `json:"start_time"` + FinishTime *time.Time `json:"finish_time"` + Archived bool `json:"archived"` +} diff --git a/pkg/dashboard/core/workflow.go b/pkg/dashboard/core/workflow.go new file mode 100644 index 0000000000..216dfddef4 --- /dev/null +++ b/pkg/dashboard/core/workflow.go @@ -0,0 +1,500 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package core + +import ( + "context" + "encoding/json" + "strings" + "time" + + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + wfcontrollers "github.com/chaos-mesh/chaos-mesh/pkg/workflow/controllers" +) + +type WorkflowRepository interface { + List(ctx context.Context) ([]WorkflowMeta, error) + ListByNamespace(ctx context.Context, namespace string) ([]WorkflowMeta, error) + Create(ctx context.Context, workflow v1alpha1.Workflow) (WorkflowDetail, error) + Get(ctx context.Context, namespace, name string) (WorkflowDetail, error) + Delete(ctx context.Context, namespace, name string) error + Update(ctx context.Context, namespace, name string, workflow v1alpha1.Workflow) (WorkflowDetail, error) +} + +type WorkflowStatus string + +const ( + WorkflowRunning WorkflowStatus = "running" + WorkflowSucceed WorkflowStatus = "finished" + WorkflowFailed WorkflowStatus = "failed" + WorkflowUnknown WorkflowStatus = "unknown" +) + +// WorkflowMeta defines the root structure of a workflow. +type WorkflowMeta struct { + ID uint `gorm:"primary_key" json:"id"` + UID string `gorm:"index:workflow_uid" json:"uid"` + Namespace string `json:"namespace"` + Name string `json:"name"` + Entry string `json:"entry"` // the entry node name + CreatedAt time.Time `json:"created_at"` + // FinishTime represents the time when the workflow was deleted from Kubernetes. + FinishTime *time.Time `json:"finish_time"` + // EndTime represents the time when the workflow completed all steps. + EndTime string `json:"end_time"` + Status WorkflowStatus `json:"status,omitempty"` + Archived bool `json:"-"` +} + +type WorkflowDetail struct { + WorkflowMeta `json:",inline"` + Topology Topology `json:"topology"` + KubeObject KubeObjectDesc `json:"kube_object,omitempty"` +} + +// Topology describes the process of a workflow. +type Topology struct { + Nodes []Node `json:"nodes"` +} + +type NodeState string + +const ( + NodeRunning NodeState = "Running" + NodeSucceed NodeState = "Succeed" + NodeFailed NodeState = "Failed" +) + +// Node defines a single step of a workflow. +type Node struct { + Name string `json:"name"` + Type NodeType `json:"type"` + State NodeState `json:"state"` + Serial []NodeNameWithTemplate `json:"serial,omitempty"` + Parallel []NodeNameWithTemplate `json:"parallel,omitempty"` + ConditionalBranches []ConditionalBranch `json:"conditional_branches,omitempty"` + Template string `json:"template"` + UID string `json:"uid"` +} + +type NodeNameWithTemplate struct { + Name string `json:"name,omitempty"` + Template string `json:"template,omitempty"` +} + +type ConditionalBranch struct { + NodeNameWithTemplate `json:",inline,omitempty"` + Expression string `json:"expression,omitempty"` +} + +// NodeType represents the type of a workflow node. +// +// There will be five types can be referred as NodeType: +// ChaosNode, SerialNode, ParallelNode, SuspendNode, TaskNode. +// +// Const definitions can be found below this type. +type NodeType string + +const ( + // ChaosNode represents a node will perform a single Chaos Experiment. + ChaosNode NodeType = "ChaosNode" + + // SerialNode represents a node that will perform continuous templates. + SerialNode NodeType = "SerialNode" + + // ParallelNode represents a node that will perform parallel templates. + ParallelNode NodeType = "ParallelNode" + + // SuspendNode represents a node that will perform wait operation. + SuspendNode NodeType = "SuspendNode" + + // TaskNode represents a node that will perform user-defined task. + TaskNode NodeType = "TaskNode" +) + +var nodeTypeTemplateTypeMapping = map[v1alpha1.TemplateType]NodeType{ + v1alpha1.TypeSerial: SerialNode, + v1alpha1.TypeParallel: ParallelNode, + v1alpha1.TypeSuspend: SuspendNode, + v1alpha1.TypeTask: TaskNode, +} + +type KubeWorkflowRepository struct { + kubeclient client.Client +} + +func NewKubeWorkflowRepository(kubeclient client.Client) *KubeWorkflowRepository { + return &KubeWorkflowRepository{kubeclient: kubeclient} +} + +func (it *KubeWorkflowRepository) Create(ctx context.Context, workflow v1alpha1.Workflow) (WorkflowDetail, error) { + err := it.kubeclient.Create(ctx, &workflow) + if err != nil { + return WorkflowDetail{}, err + } + + return it.Get(ctx, workflow.Namespace, workflow.Name) +} + +func (it *KubeWorkflowRepository) Update(ctx context.Context, namespace, name string, workflow v1alpha1.Workflow) (WorkflowDetail, error) { + current := v1alpha1.Workflow{} + + err := it.kubeclient.Get(ctx, types.NamespacedName{ + Namespace: namespace, + Name: name, + }, ¤t) + if err != nil { + return WorkflowDetail{}, err + } + workflow.ObjectMeta.ResourceVersion = current.ObjectMeta.ResourceVersion + + err = it.kubeclient.Update(ctx, &workflow) + if err != nil { + return WorkflowDetail{}, err + } + + return it.Get(ctx, workflow.Namespace, workflow.Name) +} + +func (it *KubeWorkflowRepository) ListByNamespace(ctx context.Context, namespace string) ([]WorkflowMeta, error) { + workflowList := v1alpha1.WorkflowList{} + + err := it.kubeclient.List(ctx, &workflowList, &client.ListOptions{ + Namespace: namespace, + }) + if err != nil { + return nil, err + } + + var result []WorkflowMeta + for _, item := range workflowList.Items { + result = append(result, convertWorkflow(item)) + } + + return result, nil +} + +func (it *KubeWorkflowRepository) List(ctx context.Context) ([]WorkflowMeta, error) { + return it.ListByNamespace(ctx, "") +} + +func (it *KubeWorkflowRepository) Get(ctx context.Context, namespace, name string) (WorkflowDetail, error) { + kubeWorkflow := v1alpha1.Workflow{} + + err := it.kubeclient.Get(ctx, types.NamespacedName{ + Namespace: namespace, + Name: name, + }, &kubeWorkflow) + if err != nil { + return WorkflowDetail{}, err + } + + workflowNodes := v1alpha1.WorkflowNodeList{} + // labeling workflow nodes, see pkg/workflow/controllers/new_node.go + selector, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{ + MatchLabels: map[string]string{ + v1alpha1.LabelWorkflow: kubeWorkflow.Name, + }, + }) + if err != nil { + return WorkflowDetail{}, err + } + + err = it.kubeclient.List(ctx, &workflowNodes, &client.ListOptions{ + Namespace: namespace, + LabelSelector: selector, + }) + if err != nil { + return WorkflowDetail{}, err + } + + return convertWorkflowDetail(kubeWorkflow, workflowNodes.Items) +} + +func (it *KubeWorkflowRepository) Delete(ctx context.Context, namespace, name string) error { + kubeWorkflow := v1alpha1.Workflow{} + + err := it.kubeclient.Get(ctx, types.NamespacedName{ + Namespace: namespace, + Name: name, + }, &kubeWorkflow) + if err != nil { + return err + } + + return it.kubeclient.Delete(ctx, &kubeWorkflow) +} + +func convertWorkflow(kubeWorkflow v1alpha1.Workflow) WorkflowMeta { + result := WorkflowMeta{ + Namespace: kubeWorkflow.Namespace, + Name: kubeWorkflow.Name, + Entry: kubeWorkflow.Spec.Entry, + UID: string(kubeWorkflow.UID), + } + + if kubeWorkflow.Status.StartTime != nil { + result.CreatedAt = kubeWorkflow.Status.StartTime.Time + } + + if kubeWorkflow.Status.EndTime != nil { + result.EndTime = kubeWorkflow.Status.EndTime.Format(time.RFC3339) + } + + if kubeWorkflow.GetDeletionTimestamp() != nil { + result.FinishTime = &kubeWorkflow.GetDeletionTimestamp().Time + } + + if wfcontrollers.WorkflowConditionEqualsTo(kubeWorkflow.Status, v1alpha1.WorkflowConditionAccomplished, corev1.ConditionTrue) { + result.Status = WorkflowSucceed + } else if wfcontrollers.WorkflowConditionEqualsTo(kubeWorkflow.Status, v1alpha1.WorkflowConditionScheduled, corev1.ConditionTrue) { + result.Status = WorkflowRunning + } else { + result.Status = WorkflowUnknown + } + + // TODO: status failed + + return result +} + +func convertWorkflowDetail(kubeWorkflow v1alpha1.Workflow, kubeNodes []v1alpha1.WorkflowNode) (WorkflowDetail, error) { + nodes := make([]Node, 0) + + for _, item := range kubeNodes { + node, err := convertWorkflowNode(item) + if err != nil { + return WorkflowDetail{}, nil + } + + nodes = append(nodes, node) + } + + result := WorkflowDetail{ + WorkflowMeta: convertWorkflow(kubeWorkflow), + Topology: Topology{ + Nodes: nodes, + }, + KubeObject: KubeObjectDesc{ + TypeMeta: kubeWorkflow.TypeMeta, + Meta: KubeObjectMeta{ + Name: kubeWorkflow.Name, + Namespace: kubeWorkflow.Namespace, + Labels: kubeWorkflow.Labels, + Annotations: kubeWorkflow.Annotations, + }, + Spec: kubeWorkflow.Spec, + }, + } + + return result, nil +} + +func convertWorkflowNode(kubeWorkflowNode v1alpha1.WorkflowNode) (Node, error) { + templateType, err := mappingTemplateType(kubeWorkflowNode.Spec.Type) + if err != nil { + return Node{}, err + } + + result := Node{ + Name: kubeWorkflowNode.Name, + Type: templateType, + Serial: nil, + Parallel: nil, + Template: kubeWorkflowNode.Spec.TemplateName, + UID: string(kubeWorkflowNode.UID), + } + + if kubeWorkflowNode.Spec.Type == v1alpha1.TypeSerial { + var nodes []string + for _, child := range kubeWorkflowNode.Status.FinishedChildren { + nodes = append(nodes, child.Name) + } + for _, child := range kubeWorkflowNode.Status.ActiveChildren { + nodes = append(nodes, child.Name) + } + result.Serial = composeSerialTaskAndNodes(kubeWorkflowNode.Spec.Children, nodes) + + } else if kubeWorkflowNode.Spec.Type == v1alpha1.TypeParallel { + var nodes []string + for _, child := range kubeWorkflowNode.Status.FinishedChildren { + nodes = append(nodes, child.Name) + } + for _, child := range kubeWorkflowNode.Status.ActiveChildren { + nodes = append(nodes, child.Name) + } + result.Parallel = composeParallelTaskAndNodes(kubeWorkflowNode.Spec.Children, nodes) + + } else if kubeWorkflowNode.Spec.Type == v1alpha1.TypeTask { + var nodes []string + for _, child := range kubeWorkflowNode.Status.FinishedChildren { + nodes = append(nodes, child.Name) + } + for _, child := range kubeWorkflowNode.Status.ActiveChildren { + nodes = append(nodes, child.Name) + } + result.ConditionalBranches = composeTaskConditionalBranches(kubeWorkflowNode.Spec.ConditionalBranches, nodes) + } + + if wfcontrollers.WorkflowNodeFinished(kubeWorkflowNode.Status) { + result.State = NodeSucceed + } else { + result.State = NodeRunning + } + + return result, nil +} + +// composeSerialTaskAndNodes need nodes to be ordered with its creation time +func composeSerialTaskAndNodes(children []string, nodes []string) []NodeNameWithTemplate { + var result []NodeNameWithTemplate + for _, node := range nodes { + // TODO: that reverse the generated name, maybe we could use WorkflowNode.TemplateName in the future + templateName := node[0:strings.LastIndex(node, "-")] + result = append(result, NodeNameWithTemplate{Name: node, Template: templateName}) + } + for _, task := range children[len(nodes):] { + result = append(result, NodeNameWithTemplate{Template: task}) + } + return result +} + +func composeParallelTaskAndNodes(children []string, nodes []string) []NodeNameWithTemplate { + var result []NodeNameWithTemplate + for _, task := range children { + result = append(result, NodeNameWithTemplate{ + Name: "", + Template: task, + }) + } + for _, node := range nodes { + for i, item := range result { + if len(item.Name) == 0 && strings.HasPrefix(node, item.Template) { + result[i].Name = node + break + } + } + } + return result +} + +func composeTaskConditionalBranches(conditionalBranches []v1alpha1.ConditionalBranch, nodes []string) []ConditionalBranch { + var result []ConditionalBranch + for _, item := range conditionalBranches { + nodeName := "" + for _, node := range nodes { + if strings.HasPrefix(node, item.Target) { + nodeName = node + } + } + result = append(result, + ConditionalBranch{ + NodeNameWithTemplate: NodeNameWithTemplate{ + Name: nodeName, + Template: item.Target, + }, + Expression: item.Expression, + }) + } + + return result +} + +func mappingTemplateType(templateType v1alpha1.TemplateType) (NodeType, error) { + if v1alpha1.IsChaosTemplateType(templateType) { + return ChaosNode, nil + } else if target, ok := nodeTypeTemplateTypeMapping[templateType]; ok { + return target, nil + } else { + return "", errors.Errorf("can not resolve such type called %s", templateType) + } +} + +// The WorkflowStore of workflow is not so similar with others store. +type WorkflowStore interface { + List(ctx context.Context, namespace, name string, archived bool) ([]*WorkflowEntity, error) + ListMeta(ctx context.Context, namespace, name string, archived bool) ([]*WorkflowMeta, error) + FindByID(ctx context.Context, ID uint) (*WorkflowEntity, error) + FindByUID(ctx context.Context, UID string) (*WorkflowEntity, error) + FindMetaByUID(ctx context.Context, UID string) (*WorkflowMeta, error) + Save(ctx context.Context, entity *WorkflowEntity) error + DeleteByUID(ctx context.Context, UID string) error + DeleteByUIDs(ctx context.Context, UIDs []string) error + DeleteByFinishTime(ctx context.Context, ttl time.Duration) error + MarkAsArchived(ctx context.Context, namespace, name string) error + MarkAsArchivedWithUID(ctx context.Context, UID string) error +} + +// WorkflowEntity is the gorm entity, refers to a row of data +type WorkflowEntity struct { + WorkflowMeta + Workflow string `gorm:"type:text;size:32768"` +} + +func WorkflowCR2WorkflowEntity(workflow *v1alpha1.Workflow) (*WorkflowEntity, error) { + if workflow == nil { + return nil, nil + + } + jsonContent, err := json.Marshal(workflow) + if err != nil { + return nil, err + } + + return &WorkflowEntity{ + WorkflowMeta: convertWorkflow(*workflow), + Workflow: string(jsonContent), + }, nil + +} + +func WorkflowEntity2WorkflowCR(entity *WorkflowEntity) (*v1alpha1.Workflow, error) { + if entity == nil { + return nil, nil + } + result := v1alpha1.Workflow{} + err := json.Unmarshal([]byte(entity.Workflow), &result) + if err != nil { + return nil, err + } + return &result, nil +} + +func WorkflowEntity2WorkflowDetail(entity *WorkflowEntity) (*WorkflowDetail, error) { + workflowCustomResource, err := WorkflowEntity2WorkflowCR(entity) + if err != nil { + return nil, err + } + return &WorkflowDetail{ + WorkflowMeta: entity.WorkflowMeta, + KubeObject: KubeObjectDesc{ + TypeMeta: workflowCustomResource.TypeMeta, + Meta: KubeObjectMeta{ + Name: workflowCustomResource.Name, + Namespace: workflowCustomResource.Namespace, + Labels: workflowCustomResource.Labels, + Annotations: workflowCustomResource.Annotations, + }, + Spec: workflowCustomResource.Spec, + }, + }, nil +} diff --git a/pkg/dashboard/core/workflow_test.go b/pkg/dashboard/core/workflow_test.go new file mode 100644 index 0000000000..abec813d6c --- /dev/null +++ b/pkg/dashboard/core/workflow_test.go @@ -0,0 +1,869 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package core + +import ( + "reflect" + "testing" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +func Test_convertWorkflow(t *testing.T) { + type args struct { + kubeWorkflow v1alpha1.Workflow + } + tests := []struct { + name string + args args + want WorkflowMeta + }{ + { + name: "simple workflow", + args: args{ + v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "fake-workflow-0", + }, + Spec: v1alpha1.WorkflowSpec{ + Entry: "an-entry", + }, + Status: v1alpha1.WorkflowStatus{}, + }, + }, + want: WorkflowMeta{ + Namespace: "fake-namespace", + Name: "fake-workflow-0", + Entry: "an-entry", + Status: WorkflowUnknown, + }, + }, { + name: "running workflow", + args: args{ + v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "fake-workflow-0", + }, + Spec: v1alpha1.WorkflowSpec{ + Entry: "an-entry", + }, + Status: v1alpha1.WorkflowStatus{ + Conditions: []v1alpha1.WorkflowCondition{ + { + Type: v1alpha1.WorkflowConditionScheduled, + Status: corev1.ConditionTrue, + Reason: "", + }, + }, + }, + }, + }, + want: WorkflowMeta{ + Namespace: "fake-namespace", + Name: "fake-workflow-0", + Entry: "an-entry", + Status: WorkflowRunning, + }, + }, { + name: "running workflow", + args: args{ + v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "fake-workflow-0", + }, + Spec: v1alpha1.WorkflowSpec{ + Entry: "an-entry", + }, + Status: v1alpha1.WorkflowStatus{ + Conditions: []v1alpha1.WorkflowCondition{ + { + Type: v1alpha1.WorkflowConditionAccomplished, + Status: corev1.ConditionUnknown, + Reason: "", + }, + { + Type: v1alpha1.WorkflowConditionScheduled, + Status: corev1.ConditionTrue, + Reason: "", + }, + }, + }, + }, + }, + want: WorkflowMeta{ + Namespace: "fake-namespace", + Name: "fake-workflow-0", + Entry: "an-entry", + Status: WorkflowRunning, + }, + }, { + name: "running workflow", + args: args{ + v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "fake-workflow-0", + }, + Spec: v1alpha1.WorkflowSpec{ + Entry: "an-entry", + }, + Status: v1alpha1.WorkflowStatus{ + Conditions: []v1alpha1.WorkflowCondition{ + { + Type: v1alpha1.WorkflowConditionAccomplished, + Status: corev1.ConditionFalse, + Reason: "", + }, + { + Type: v1alpha1.WorkflowConditionScheduled, + Status: corev1.ConditionTrue, + Reason: "", + }, + }, + }, + }, + }, + want: WorkflowMeta{ + Namespace: "fake-namespace", + Name: "fake-workflow-0", + Entry: "an-entry", + Status: WorkflowRunning, + }, + }, { + name: "succeed workflow", + args: args{ + v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "fake-workflow-0", + }, + Spec: v1alpha1.WorkflowSpec{ + Entry: "an-entry", + }, + Status: v1alpha1.WorkflowStatus{ + Conditions: []v1alpha1.WorkflowCondition{ + { + Type: v1alpha1.WorkflowConditionAccomplished, + Status: corev1.ConditionTrue, + Reason: "", + }, + { + Type: v1alpha1.WorkflowConditionScheduled, + Status: corev1.ConditionTrue, + Reason: "", + }, + }, + }, + }, + }, + want: WorkflowMeta{ + Namespace: "fake-namespace", + Name: "fake-workflow-0", + Entry: "an-entry", + Status: WorkflowSucceed, + }, + }, { + name: "converting UID", + args: args{ + v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "fake-workflow-0", + UID: "uid-of-workflow", + }, + Spec: v1alpha1.WorkflowSpec{ + Entry: "an-entry", + }, + Status: v1alpha1.WorkflowStatus{ + Conditions: []v1alpha1.WorkflowCondition{ + { + Type: v1alpha1.WorkflowConditionAccomplished, + Status: corev1.ConditionTrue, + Reason: "", + }, + { + Type: v1alpha1.WorkflowConditionScheduled, + Status: corev1.ConditionTrue, + Reason: "", + }, + }, + }, + }, + }, + want: WorkflowMeta{ + Namespace: "fake-namespace", + Name: "fake-workflow-0", + Entry: "an-entry", + Status: WorkflowSucceed, + UID: "uid-of-workflow", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := convertWorkflow(tt.args.kubeWorkflow); !reflect.DeepEqual(got, tt.want) { + t.Errorf("convertWorkflow() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_convertWorkflowDetail(t *testing.T) { + type args struct { + kubeWorkflow v1alpha1.Workflow + kubeNodes []v1alpha1.WorkflowNode + } + tests := []struct { + name string + args args + want WorkflowDetail + wantErr bool + }{ + { + name: "simple workflow detail with no nodes", + args: args{ + kubeWorkflow: v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "another-namespace", + Name: "another-fake-workflow", + }, + Spec: v1alpha1.WorkflowSpec{ + Entry: "another-entry", + Templates: nil, + }, + Status: v1alpha1.WorkflowStatus{}, + }, + kubeNodes: nil, + }, + want: WorkflowDetail{ + WorkflowMeta: WorkflowMeta{ + Namespace: "another-namespace", + Name: "another-fake-workflow", + Entry: "another-entry", + Status: WorkflowUnknown, + }, + Topology: Topology{ + Nodes: []Node{}, + }, + KubeObject: KubeObjectDesc{ + Meta: KubeObjectMeta{ + Name: "another-fake-workflow", + Namespace: "another-namespace", + }, + Spec: v1alpha1.WorkflowSpec{ + Entry: "another-entry", + }, + }, + }, + }, + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := convertWorkflowDetail(tt.args.kubeWorkflow, tt.args.kubeNodes) + if (err != nil) != tt.wantErr { + t.Errorf("convertWorkflowDetail() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("convertWorkflowDetail() got = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_convertWorkflowNode(t *testing.T) { + type args struct { + kubeWorkflowNode v1alpha1.WorkflowNode + } + tests := []struct { + name string + args args + want Node + wantErr bool + }{ + { + name: "simple node", + args: args{kubeWorkflowNode: v1alpha1.WorkflowNode{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "fake-node-0", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + WorkflowName: "fake-workflow-0", + TemplateName: "fake-template-0", + Type: v1alpha1.TypeJVMChaos, + }, + Status: v1alpha1.WorkflowNodeStatus{}, + }}, + want: Node{ + Name: "fake-node-0", + Type: ChaosNode, + Serial: nil, + Parallel: nil, + Template: "fake-template-0", + State: NodeRunning, + }, + }, { + name: "serial node", + args: args{ + kubeWorkflowNode: v1alpha1.WorkflowNode{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "fake-serial-node-0", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + TemplateName: "fake-serial-node", + WorkflowName: "fake-workflow-0", + Type: v1alpha1.TypeSerial, + Children: []string{"child-0", "child-1"}, + }, + Status: v1alpha1.WorkflowNodeStatus{}, + }, + }, + want: Node{ + Name: "fake-serial-node-0", + Type: SerialNode, + Serial: []NodeNameWithTemplate{ + {Name: "", Template: "child-0"}, + {Name: "", Template: "child-1"}, + }, + Parallel: nil, + Template: "fake-serial-node", + State: NodeRunning, + }, + }, + { + name: "parallel node", + args: args{ + kubeWorkflowNode: v1alpha1.WorkflowNode{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "parallel-node-0", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + TemplateName: "parallel-node", + WorkflowName: "another-fake-workflow", + Type: v1alpha1.TypeParallel, + Children: []string{"child-1", "child-0"}, + }, + Status: v1alpha1.WorkflowNodeStatus{}, + }, + }, + want: Node{ + Name: "parallel-node-0", + Type: ParallelNode, + Serial: nil, + Parallel: []NodeNameWithTemplate{ + {Name: "", Template: "child-1"}, + {Name: "", Template: "child-0"}, + }, + Template: "parallel-node", + State: NodeRunning, + }, + }, + { + name: "some chaos", + args: args{ + kubeWorkflowNode: v1alpha1.WorkflowNode{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "io-chaos-0", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + TemplateName: "io-chaos", + WorkflowName: "another-workflow-0", + Type: v1alpha1.TypeIOChaos, + EmbedChaos: &v1alpha1.EmbedChaos{ + IOChaos: &v1alpha1.IOChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Mode: v1alpha1.OneMode, + }, + }, + Action: "delay", + Delay: "100ms", + Path: "/fake/path", + Percent: 100, + VolumePath: "/fake/path", + }, + }, + }, + Status: v1alpha1.WorkflowNodeStatus{}, + }, + }, + want: Node{ + Name: "io-chaos-0", + Type: ChaosNode, + Serial: nil, + Parallel: nil, + Template: "io-chaos", + State: NodeRunning, + }, + }, + { + name: "accomplished node", + args: args{ + kubeWorkflowNode: v1alpha1.WorkflowNode{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "the-entry-0", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + TemplateName: "the-entry", + WorkflowName: "fake-workflow-0", + Type: v1alpha1.TypeSerial, + Children: []string{"unimportant-task-0"}, + }, + Status: v1alpha1.WorkflowNodeStatus{ + Conditions: []v1alpha1.WorkflowNodeCondition{ + { + Type: v1alpha1.ConditionAccomplished, + Status: corev1.ConditionTrue, + Reason: "unit test mocked true", + }, + }, + }, + }, + }, + want: Node{ + Name: "the-entry-0", + Type: SerialNode, + State: NodeSucceed, + Serial: []NodeNameWithTemplate{ + {Name: "", Template: "unimportant-task-0"}, + }, + Parallel: nil, + Template: "the-entry", + }, + }, + { + name: "deadline exceed node", + args: args{kubeWorkflowNode: v1alpha1.WorkflowNode{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "deadline-exceed-node-0", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + TemplateName: "deadline-exceed-node", + WorkflowName: "some-workflow", + Type: v1alpha1.TypePodChaos, + }, + Status: v1alpha1.WorkflowNodeStatus{ + Conditions: []v1alpha1.WorkflowNodeCondition{ + { + Type: v1alpha1.ConditionDeadlineExceed, + Status: corev1.ConditionTrue, + Reason: "unit test mocked true", + }, + }, + }, + }}, + want: Node{ + Name: "deadline-exceed-node-0", + Type: ChaosNode, + State: NodeSucceed, + Serial: nil, + Parallel: nil, + Template: "deadline-exceed-node", + }, + }, + { + name: "appending uid", + args: args{ + kubeWorkflowNode: v1alpha1.WorkflowNode{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "the-entry-0", + UID: "uid-of-workflow-node", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + TemplateName: "the-entry", + WorkflowName: "fake-workflow-0", + Type: v1alpha1.TypeSerial, + Children: []string{"unimportant-task-0"}, + }, + Status: v1alpha1.WorkflowNodeStatus{ + Conditions: []v1alpha1.WorkflowNodeCondition{ + { + Type: v1alpha1.ConditionAccomplished, + Status: corev1.ConditionTrue, + Reason: "unit test mocked true", + }, + }, + }, + }, + }, + want: Node{ + Name: "the-entry-0", + Type: SerialNode, + State: NodeSucceed, + Serial: []NodeNameWithTemplate{ + {Name: "", Template: "unimportant-task-0"}, + }, + Parallel: nil, + Template: "the-entry", + UID: "uid-of-workflow-node", + }, + }, + { + name: "task node", + args: args{ + kubeWorkflowNode: v1alpha1.WorkflowNode{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mocking-task-node-0", + Namespace: "mocked-namespace", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + TemplateName: "mocking-task-node", + WorkflowName: "fake-workflow-0", + Type: v1alpha1.TypeTask, + ConditionalBranches: []v1alpha1.ConditionalBranch{ + { + Target: "one-node", + Expression: "exitCode == 0", + }, + { + Target: "another-node", + Expression: "exitCode != 0", + }, + }, + }, + Status: v1alpha1.WorkflowNodeStatus{ + ConditionalBranchesStatus: &v1alpha1.ConditionalBranchesStatus{ + Branches: []v1alpha1.ConditionalBranchStatus{ + { + Target: "one-node", + EvaluationResult: corev1.ConditionFalse, + }, + { + Target: "another-node", + EvaluationResult: corev1.ConditionTrue, + }, + }, + Context: nil, + }, + ActiveChildren: []corev1.LocalObjectReference{ + { + Name: "another-node-0", + }, + }, + }, + }, + }, + want: Node{ + Name: "mocking-task-node-0", + Type: TaskNode, + State: NodeRunning, + ConditionalBranches: []ConditionalBranch{ + { + NodeNameWithTemplate: NodeNameWithTemplate{ + Template: "one-node", + Name: "", + }, + Expression: "exitCode == 0", + }, + { + NodeNameWithTemplate: NodeNameWithTemplate{ + Template: "another-node", + Name: "another-node-0", + }, + Expression: "exitCode != 0", + }, + }, + Template: "mocking-task-node", + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := convertWorkflowNode(tt.args.kubeWorkflowNode) + if (err != nil) != tt.wantErr { + t.Errorf("convertWorkflowNode() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("convertWorkflowNode() got = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_composeTaskAndNodes(t *testing.T) { + type args struct { + children []string + nodes []string + } + tests := []struct { + name string + args args + want []NodeNameWithTemplate + }{ + { + name: "ordered with serial", + args: args{ + children: []string{"node-0", "node-1", "node-0", "node-2", "node-3"}, + nodes: []string{"node-0-instance", "node-1-instance", "node-0-another_instance"}, + }, + want: []NodeNameWithTemplate{ + { + Name: "node-0-instance", + Template: "node-0", + }, { + Name: "node-1-instance", + Template: "node-1", + }, { + Name: "node-0-another_instance", + Template: "node-0", + }, { + Name: "", + Template: "node-2", + }, { + Name: "", + Template: "node-3", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := composeSerialTaskAndNodes(tt.args.children, tt.args.nodes); !reflect.DeepEqual(got, tt.want) { + t.Errorf("composeSerialTaskAndNodes() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_composeParallelTaskAndNodes(t *testing.T) { + type args struct { + children []string + nodes []string + } + tests := []struct { + name string + args args + want []NodeNameWithTemplate + }{ + { + name: "parallel", + args: args{ + children: []string{"node-a", "node-b", "node-a", "node-c", "node-d"}, + nodes: []string{"node-a-instance", "node-a-another_instance", "node-d-instance"}, + }, + want: []NodeNameWithTemplate{ + { + Name: "node-a-instance", + Template: "node-a", + }, { + Name: "", + Template: "node-b", + }, { + Name: "node-a-another_instance", + Template: "node-a", + }, { + Name: "", + Template: "node-c", + }, { + Name: "node-d-instance", + Template: "node-d", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := composeParallelTaskAndNodes(tt.args.children, tt.args.nodes); !reflect.DeepEqual(got, tt.want) { + t.Errorf("composeParallelTaskAndNodes() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_composeTaskConditionalBranches(t *testing.T) { + type args struct { + conditionalBranches []v1alpha1.ConditionalBranch + nodes []string + } + tests := []struct { + name string + args args + want []ConditionalBranch + }{ + { + name: "task node all of the branch is selected", + args: args{ + conditionalBranches: []v1alpha1.ConditionalBranch{ + { + Target: "template-a", + Expression: "a: whatever valid or not", + }, + { + Target: "template-b", + Expression: "b: whatever valid or not", + }, + { + Target: "template-c", + Expression: "c: whatever valid or not", + }, + }, + nodes: []string{ + "template-a-0", + "template-b-0", + "template-c-0", + }, + }, + want: []ConditionalBranch{ + { + NodeNameWithTemplate: NodeNameWithTemplate{ + Name: "template-a-0", + Template: "template-a", + }, + Expression: "a: whatever valid or not", + }, + { + NodeNameWithTemplate: NodeNameWithTemplate{ + Name: "template-b-0", + Template: "template-b", + }, + Expression: "b: whatever valid or not", + }, + { + NodeNameWithTemplate: NodeNameWithTemplate{ + Name: "template-c-0", + Template: "template-c", + }, + Expression: "c: whatever valid or not", + }, + }, + }, + { + name: "none of the branch is selected", + args: args{ + conditionalBranches: []v1alpha1.ConditionalBranch{ + { + Target: "template-a", + Expression: "a: whatever valid or not", + }, + { + Target: "template-b", + Expression: "b: whatever valid or not", + }, + { + Target: "template-c", + Expression: "c: whatever valid or not", + }, + }, + nodes: []string{}, + }, + want: []ConditionalBranch{ + { + NodeNameWithTemplate: NodeNameWithTemplate{ + Name: "", + Template: "template-a", + }, + Expression: "a: whatever valid or not", + }, + { + NodeNameWithTemplate: NodeNameWithTemplate{ + Name: "", + Template: "template-b", + }, + Expression: "b: whatever valid or not", + }, + { + NodeNameWithTemplate: NodeNameWithTemplate{ + Name: "", + Template: "template-c", + }, + Expression: "c: whatever valid or not", + }, + }, + }, + { + name: "part of the branch is selected", + args: args{ + conditionalBranches: []v1alpha1.ConditionalBranch{ + { + Target: "template-a", + Expression: "a: whatever valid or not", + }, + { + Target: "template-b", + Expression: "b: whatever valid or not", + }, + { + Target: "template-c", + Expression: "c: whatever valid or not", + }, + }, + nodes: []string{ + "template-a-0", + }, + }, + want: []ConditionalBranch{ + { + NodeNameWithTemplate: NodeNameWithTemplate{ + Name: "template-a-0", + Template: "template-a", + }, + Expression: "a: whatever valid or not", + }, + { + NodeNameWithTemplate: NodeNameWithTemplate{ + Name: "", + Template: "template-b", + }, + Expression: "b: whatever valid or not", + }, + { + NodeNameWithTemplate: NodeNameWithTemplate{ + Name: "", + Template: "template-c", + }, + Expression: "c: whatever valid or not", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := composeTaskConditionalBranches(tt.args.conditionalBranches, tt.args.nodes); !reflect.DeepEqual(got, tt.want) { + t.Errorf("composeTaskConditionalBranches() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/dashboard/store/event/event.go b/pkg/dashboard/store/event/event.go new file mode 100644 index 0000000000..3ec2b0f313 --- /dev/null +++ b/pkg/dashboard/store/event/event.go @@ -0,0 +1,126 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package event + +import ( + "context" + "strconv" + "time" + + "github.com/jinzhu/gorm" + + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +func NewStore(db *gorm.DB) core.EventStore { + db.AutoMigrate(&core.Event{}) + + return &eventStore{db} +} + +type eventStore struct { + db *gorm.DB +} + +func (e *eventStore) List(_ context.Context) ([]*core.Event, error) { + var events []*core.Event + + if err := e.db.Find(&events).Error; err != nil { + return nil, err + } + + return events, nil +} + +func (e *eventStore) ListBy(_ context.Context, by string, args ...interface{}) ([]*core.Event, error) { + var events []*core.Event + + if err := e.db.Where(by, args...).Find(&events).Error; err != nil { + return nil, err + } + + return events, nil +} + +func (e *eventStore) ListByUID(c context.Context, uid string) ([]*core.Event, error) { + return e.ListBy(c, "object_id = ?", uid) +} + +func (e *eventStore) ListByUIDs(c context.Context, uids []string) ([]*core.Event, error) { + return e.ListBy(c, "object_id IN (?)", uids) +} + +func (e *eventStore) ListByExperiment(c context.Context, namespace string, name string, kind string) ([]*core.Event, error) { + return e.ListBy(c, "namespace = ? AND name = ? AND kind = ?", namespace, name, kind) +} + +func (e *eventStore) ListByFilter(_ context.Context, filter core.Filter) ([]*core.Event, error) { + var ( + events []*core.Event + limit int + err error + ) + + query, args := filter.ConstructQueryArgs() + statement := e.db.Where(query, args...).Order("id desc") + + if filter.Limit != "" { + limit, err = strconv.Atoi(filter.Limit) + if err != nil { + return nil, err + } + + statement = statement.Limit(limit) + } + + if err := statement.Find(&events).Error; err != nil { + return nil, err + } + + return events, nil +} + +func (e *eventStore) Find(_ context.Context, id uint) (*core.Event, error) { + event := new(core.Event) + + if err := e.db.First(event, id).Error; err != nil { + return nil, err + } + + return event, nil +} + +func (e *eventStore) Create(_ context.Context, event *core.Event) error { + return e.db.Create(event).Error +} + +func (e *eventStore) DeleteByUID(_ context.Context, uid string) error { + return e.db.Where("object_id = ?", uid).Delete(&core.Event{}).Error +} + +func (e *eventStore) DeleteByUIDs(_ context.Context, uids []string) error { + return e.db.Where("object_id IN (?)", uids).Delete(&core.Event{}).Error +} + +func (e *eventStore) DeleteByTime(_ context.Context, start string, end string) error { + return e.db.Where("created_at BETWEEN ? AND ?", start, end).Delete(&core.Event{}).Error +} + +func (e *eventStore) DeleteByDuration(_ context.Context, duration time.Duration) error { + now := time.Now().UTC().Add(-duration).Format("2006-01-02 15:04:05") + + return e.db.Where("created_at <= ?", now).Delete(&core.Event{}).Error +} diff --git a/pkg/dashboard/store/event/event_test.go b/pkg/dashboard/store/event/event_test.go new file mode 100644 index 0000000000..f872e89557 --- /dev/null +++ b/pkg/dashboard/store/event/event_test.go @@ -0,0 +1,174 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package event + +import ( + "context" + "database/sql" + "testing" + "time" + + sqlmock "github.com/DATA-DOG/go-sqlmock" + "github.com/jinzhu/gorm" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +func TestEvent(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Event Suite") +} + +func genRows() *sqlmock.Rows { + return sqlmock.NewRows( + []string{"id", "object_id", "created_at", "namespace", "name", "kind", "type", "reason", "message"}, + ) +} + +func addRow(rows *sqlmock.Rows, event *core.Event) { + rows.AddRow(event.ID, event.ObjectID, event.CreatedAt, event.Namespace, event.Name, + event.Kind, event.Type, event.Reason, event.Message) +} + +var _ = Describe("Event", func() { + var ( + err error + db *sql.DB + mock sqlmock.Sqlmock + es *eventStore + event0 *core.Event + event1 *core.Event + ) + + BeforeEach(func() { + db, mock, err = sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + Expect(err).ShouldNot(HaveOccurred()) + + gdb, err := gorm.Open("sqlite3", db) + Expect(err).ShouldNot(HaveOccurred()) + + es = &eventStore{db: gdb} + + now := time.Now() + event0 = &core.Event{ + ID: 0, + ObjectID: "UID0", + CreatedAt: now, + Namespace: "default", + Name: "event0", + Kind: "PodChaos", + Type: "type", + Reason: "reason", + Message: "message", + } + event1 = &core.Event{ + ID: 1, + ObjectID: "UID1", + CreatedAt: now.Add(time.Hour * 24), + Namespace: "chaos-mesh", + Name: "event1", + Kind: "NetworkChaos", + Type: "type", + Reason: "reason", + Message: "message", + } + }) + + AfterEach(func() { + Expect(mock.ExpectationsWereMet()).ShouldNot(HaveOccurred()) + }) + + Context("List", func() { + It("event0 should be found", func() { + rows := genRows() + addRow(rows, event0) + + mock.ExpectQuery("SELECT * FROM \"events\"").WillReturnRows(rows) + + events, err := es.List(context.TODO()) + Expect(err).ShouldNot(HaveOccurred()) + Expect(events[0]).Should(Equal(event0)) + }) + }) + + Context("ListByUID", func() { + sql := "SELECT * FROM \"events\" WHERE (object_id = ?)" + + It("event0 should be found", func() { + rows := genRows() + addRow(rows, event0) + + mock.ExpectQuery(sql).WithArgs(event0.ObjectID).WillReturnRows(rows) + + events, err := es.ListByUID(context.TODO(), "UID0") + Expect(err).ShouldNot(HaveOccurred()) + Expect(events[0]).Should(Equal(event0)) + }) + + It("event0 shoud not be found", func() { + rows := genRows() + addRow(rows, event0) + mock.ExpectQuery(sql).WithArgs(event1.ObjectID).WillReturnRows(sqlmock.NewRows(nil)) + + events, err := es.ListByUID(context.TODO(), "UID1") + Expect(err).ShouldNot(HaveOccurred()) + Expect(len(events)).Should(Equal(0)) + }) + }) + + Context("ListByExperiment", func() { + sql := "SELECT * FROM \"events\" WHERE (namespace = ? AND name = ? AND kind = ?)" + + It("event0 should be found", func() { + rows := genRows() + addRow(rows, event0) + + mock.ExpectQuery(sql).WithArgs(event0.Namespace, event0.Name, event0.Kind).WillReturnRows(rows) + + events, err := es.ListByExperiment(context.TODO(), "default", "event0", "PodChaos") + Expect(err).ShouldNot(HaveOccurred()) + Expect(events[0]).Should(Equal(event0)) + }) + + It("event1 should be found", func() { + rows := genRows() + addRow(rows, event1) + + mock.ExpectQuery(sql).WithArgs(event1.Namespace, event1.Name, event1.Kind).WillReturnRows(rows) + + events, err := es.ListByExperiment(context.TODO(), "chaos-mesh", "event1", "NetworkChaos") + Expect(err).ShouldNot(HaveOccurred()) + Expect(events[0]).Should(Equal(event1)) + }) + }) + + Context("Find", func() { + sql := "SELECT * FROM \"events\" WHERE (\"events\".\"id\" = 0) ORDER BY \"events\".\"id\" ASC LIMIT 1" + + It("event0 should be found", func() { + rows := genRows() + addRow(rows, event0) + + mock.ExpectQuery(sql).WillReturnRows(rows) + + event, err := es.Find(context.TODO(), 0) + Expect(err).ShouldNot(HaveOccurred()) + Expect(event).Should(Equal(event0)) + }) + }) +}) diff --git a/pkg/dashboard/store/experiment/experiment.go b/pkg/dashboard/store/experiment/experiment.go new file mode 100644 index 0000000000..8a5ad0790f --- /dev/null +++ b/pkg/dashboard/store/experiment/experiment.go @@ -0,0 +1,205 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package experiment + +import ( + "context" + "time" + + "github.com/jinzhu/gorm" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +var log = ctrl.Log.WithName("store/experiment") + +// NewStore returns a new ExperimentStore. +func NewStore(db *gorm.DB) core.ExperimentStore { + db.AutoMigrate(&core.Experiment{}) + + return &experimentStore{db} +} + +// DeleteIncompleteExperiments call core.ExperimentStore.DeleteIncompleteExperiments to deletes all incomplete experiments. +func DeleteIncompleteExperiments(es core.ExperimentStore, _ core.EventStore) { + if err := es.DeleteIncompleteExperiments(context.Background()); err != nil && !gorm.IsRecordNotFoundError(err) { + log.Error(err, "failed to delete all incomplete experiments") + } +} + +type experimentStore struct { + db *gorm.DB +} + +// ListMeta implements the core.ExperimentStore.ListMeta method. +func (e *experimentStore) ListMeta(_ context.Context, kind, namespace, name string, archived bool) ([]*core.ExperimentMeta, error) { + db := e.db.Table("experiments") + experiments := make([]*core.ExperimentMeta, 0) + query, args := constructQueryArgs(kind, namespace, name, "") + + if err := db.Where(query, args).Where("archived = ?", archived).Find(&experiments).Error; err != nil && !gorm.IsRecordNotFoundError(err) { + return nil, err + } + + return experiments, nil +} + +// FindByUID implements the core.ExperimentStore.FindByUID method. +func (e *experimentStore) FindByUID(_ context.Context, uid string) (*core.Experiment, error) { + experiment := new(core.Experiment) + + if err := e.db.Where("uid = ?", uid).First(experiment).Error; err != nil { + return nil, err + } + + return experiment, nil +} + +// FindMetaByUID implements the core.ExperimentStore.FindMetaByUID method. +func (e *experimentStore) FindMetaByUID(_ context.Context, uid string) (*core.ExperimentMeta, error) { + db := e.db.Table("experiments") + experiment := new(core.ExperimentMeta) + + if err := db.Where("uid = ?", uid).First(experiment).Error; err != nil { + return nil, err + } + + return experiment, nil +} + +// FindManagedByNamespaceName implements the core.ExperimentStore.FindManagedByNamespaceName method. +func (e *experimentStore) FindManagedByNamespaceName(_ context.Context, namespace, name string) ([]*core.Experiment, error) { + experiments := make([]*core.Experiment, 0) + if err := e.db.Model(core.Experiment{}). + Find(&experiments, "namespace = ? AND name = ? AND archived = ?", namespace, name, true).Error; err != nil { + return nil, err + } + + managedExperiments := make([]*core.Experiment, 0) + for _, expr := range experiments { + meta := &unstructured.Unstructured{} + if err := meta.UnmarshalJSON([]byte(expr.Experiment)); err != nil { + return nil, err + } + + if meta.GetLabels()[v1alpha1.LabelManagedBy] != "" { + managedExperiments = append(managedExperiments, expr) + } + } + + if len(managedExperiments) == 0 { + return nil, gorm.ErrRecordNotFound + } + + return managedExperiments, nil +} + +// Set implements the core.ExperimentStore.Set method. +func (e *experimentStore) Set(_ context.Context, experiment *core.Experiment) error { + return e.db.Model(core.Experiment{}).Save(experiment).Error +} + +// Archive implements the core.ExperimentStore.Archive method. +func (e *experimentStore) Archive(_ context.Context, namespace, name string) error { + if err := e.db.Model(core.Experiment{}). + Where("namespace = ? AND name = ? AND archived = ?", namespace, name, false). + Updates(map[string]interface{}{"archived": true, "finish_time": time.Now()}).Error; err != nil && !gorm.IsRecordNotFoundError(err) { + return err + } + + return nil +} + +// Delete deletes the experiment from the datastore. +func (e *experimentStore) Delete(_ context.Context, exp *core.Experiment) error { + err := e.db.Table("experiments").Unscoped().Delete(*exp).Error + return err +} + +// DeleteByFinishTime deletes experiments whose time difference is greater than the given time from FinishTime. +func (e *experimentStore) DeleteByFinishTime(_ context.Context, ttl time.Duration) error { + experiments, err := e.ListMeta(context.Background(), "", "", "", true) + if err != nil { + return err + } + + nowTime := time.Now() + for _, exp := range experiments { + if exp.FinishTime == nil { + log.Error(nil, "finish time is nil when deleting archived experiment records, skip it", "experiment", exp) + continue + } + if exp.FinishTime.Add(ttl).Before(nowTime) { + if err := e.db.Table("experiments").Unscoped().Delete(*exp).Error; err != nil { + return err + } + } + } + + return nil +} + +// DeleteByUIDs deletes archives by the uid list. +func (e *experimentStore) DeleteByUIDs(_ context.Context, uids []string) error { + return e.db.Table("experiments").Where("uid IN (?)", uids).Unscoped().Delete(core.Experiment{}).Error +} + +// DeleteIncompleteExperiments implements the core.ExperimentStore.DeleteIncompleteExperiments method. +func (e *experimentStore) DeleteIncompleteExperiments(_ context.Context) error { + return e.db.Where("finish_time IS NULL").Unscoped().Delete(core.Experiment{}).Error +} + +func constructQueryArgs(kind, ns, name, uid string) (string, []string) { + query := "" + args := make([]string, 0) + + if kind != "" { + query += "kind = ?" + args = append(args, kind) + } + + if ns != "" { + if len(args) > 0 { + query += " AND namespace = ?" + } else { + query += "namespace = ?" + } + args = append(args, ns) + } + + if name != "" { + if len(args) > 0 { + query += " AND name = ?" + } else { + query += "name = ?" + } + args = append(args, name) + } + + if uid != "" { + if len(args) > 0 { + query += " AND uid = ?" + } else { + query += "uid = ?" + } + args = append(args, uid) + } + + return query, args +} diff --git a/pkg/store/experiment/experiment_test.go b/pkg/dashboard/store/experiment/experiment_test.go similarity index 95% rename from pkg/store/experiment/experiment_test.go rename to pkg/dashboard/store/experiment/experiment_test.go index 291a380337..150b3cd49d 100644 --- a/pkg/store/experiment/experiment_test.go +++ b/pkg/dashboard/store/experiment/experiment_test.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package experiment diff --git a/pkg/dashboard/store/fx.go b/pkg/dashboard/store/fx.go new file mode 100644 index 0000000000..8221c9b009 --- /dev/null +++ b/pkg/dashboard/store/fx.go @@ -0,0 +1,28 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package store + +import ( + "github.com/go-logr/logr" + "github.com/jinzhu/gorm" + "go.uber.org/fx" + + config "github.com/chaos-mesh/chaos-mesh/pkg/config" +) + +func Bootstrap(lc fx.Lifecycle, conf *config.ChaosDashboardConfig, logger logr.Logger) (*gorm.DB, error) { + return NewDBStore(lc, conf, logger.WithName("dashboard-store")) +} diff --git a/pkg/dashboard/store/metrics/metrics.go b/pkg/dashboard/store/metrics/metrics.go new file mode 100644 index 0000000000..9f4b4f37f1 --- /dev/null +++ b/pkg/dashboard/store/metrics/metrics.go @@ -0,0 +1,159 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package metrics + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/prometheus/client_golang/prometheus" + "go.uber.org/fx" + + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +const chaosDashboardSubsystem = "chaos_dashboard" + +// Collector implements prometheus.Collector interface +type Collector struct { + log logr.Logger + experimentStore core.ExperimentStore + scheduleStore core.ScheduleStore + workflowStore core.WorkflowStore + + archivedExperiments *prometheus.GaugeVec + archivedSchedules *prometheus.GaugeVec + archivedWorkflows *prometheus.GaugeVec +} + +// NewCollector initializes metrics and collector +func NewCollector(log logr.Logger, experimentStore core.ExperimentStore, scheduleStore core.ScheduleStore, workflowStore core.WorkflowStore) *Collector { + return &Collector{ + log: log, + experimentStore: experimentStore, + scheduleStore: scheduleStore, + workflowStore: workflowStore, + archivedExperiments: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Subsystem: chaosDashboardSubsystem, + Name: "archived_experiments", + Help: "Total number of archived chaos experiments", + }, []string{"namespace", "type"}), + archivedSchedules: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Subsystem: chaosDashboardSubsystem, + Name: "archived_schedules", + Help: "Total number of archived chaos schedules", + }, []string{"namespace"}), + archivedWorkflows: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Subsystem: chaosDashboardSubsystem, + Name: "archived_workflows", + Help: "Total number of archived chaos workflows", + }, []string{"namespace"}), + } +} + +// Describe implements the prometheus.Collector interface. +func (collector *Collector) Describe(ch chan<- *prometheus.Desc) { + collector.archivedExperiments.Describe(ch) + collector.archivedSchedules.Describe(ch) + collector.archivedWorkflows.Describe(ch) +} + +// Collect implements the prometheus.Collector interface. +func (collector *Collector) Collect(ch chan<- prometheus.Metric) { + collector.collectArchivedExperiments() + collector.collectArchivedSchedules() + collector.collectArchivedWorkflows() + collector.archivedExperiments.Collect(ch) + collector.archivedSchedules.Collect(ch) + collector.archivedWorkflows.Collect(ch) +} + +func (collector *Collector) collectArchivedExperiments() { + collector.archivedExperiments.Reset() + + metas, err := collector.experimentStore.ListMeta(context.TODO(), "", "", "", true) + if err != nil { + collector.log.Error(err, "fail to list all archived chaos experiments") + return + } + + countByNamespaceAndKind := map[string]map[string]int{} + for _, meta := range metas { + if _, ok := countByNamespaceAndKind[meta.Namespace]; !ok { + countByNamespaceAndKind[meta.Namespace] = map[string]int{} + } + + countByNamespaceAndKind[meta.Namespace][meta.Kind]++ + } + + for namespace, countByKind := range countByNamespaceAndKind { + for kind, count := range countByKind { + collector.archivedExperiments.WithLabelValues(namespace, kind).Set(float64(count)) + } + } +} + +func (collector *Collector) collectArchivedSchedules() { + collector.archivedSchedules.Reset() + + metas, err := collector.scheduleStore.ListMeta(context.TODO(), "", "", true) + if err != nil { + collector.log.Error(err, "fail to list all archived schedules") + return + } + + countByNamespace := map[string]int{} + for _, meta := range metas { + countByNamespace[meta.Namespace]++ + } + + for namespace, count := range countByNamespace { + collector.archivedSchedules.WithLabelValues(namespace).Set(float64(count)) + } +} + +func (collector *Collector) collectArchivedWorkflows() { + collector.archivedWorkflows.Reset() + + metas, err := collector.workflowStore.ListMeta(context.TODO(), "", "", true) + if err != nil { + collector.log.Error(err, "fail to list all archived workflows") + return + } + + countByNamespace := map[string]int{} + for _, meta := range metas { + countByNamespace[meta.Namespace]++ + } + + for namespace, count := range countByNamespace { + collector.archivedWorkflows.WithLabelValues(namespace).Set(float64(count)) + } +} + +type Params struct { + fx.In + Log logr.Logger + Registry *prometheus.Registry + ExperimentStore core.ExperimentStore + ScheduleStore core.ScheduleStore + WorkflowStore core.WorkflowStore +} + +func Register(params Params) { + collector := NewCollector(params.Log, params.ExperimentStore, params.ScheduleStore, params.WorkflowStore) + params.Registry.MustRegister(collector) +} diff --git a/pkg/dashboard/store/schedule/schedule.go b/pkg/dashboard/store/schedule/schedule.go new file mode 100644 index 0000000000..dc7fb91899 --- /dev/null +++ b/pkg/dashboard/store/schedule/schedule.go @@ -0,0 +1,176 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package schedule + +import ( + "context" + "time" + + "github.com/jinzhu/gorm" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +var log = ctrl.Log.WithName("store/schedule") + +// NewStore returns a new ScheduleStore. +func NewStore(db *gorm.DB) core.ScheduleStore { + db.AutoMigrate(&core.Schedule{}) + + return &ScheduleStore{db} +} + +// DeleteIncompleteSchedules call core.ScheduleStore.DeleteIncompleteSchedules to deletes all incomplete schedules. +func DeleteIncompleteSchedules(es core.ScheduleStore, _ core.EventStore) { + if err := es.DeleteIncompleteSchedules(context.Background()); err != nil && !gorm.IsRecordNotFoundError(err) { + log.Error(err, "failed to delete all incomplete schedules") + } +} + +type ScheduleStore struct { + db *gorm.DB +} + +// ListMeta implements the core.ScheduleStore.ListMeta method. +func (e *ScheduleStore) ListMeta(_ context.Context, namespace, name string, archived bool) ([]*core.ScheduleMeta, error) { + db := e.db.Table("schedules") + sches := make([]*core.ScheduleMeta, 0) + query, args := constructQueryArgs("", namespace, name, "") + + if err := db.Where(query, args).Where("archived = ?", archived).Find(&sches).Error; err != nil && !gorm.IsRecordNotFoundError(err) { + return nil, err + } + + return sches, nil +} + +// FindByUID implements the core.ScheduleStore.FindByUID method. +func (e *ScheduleStore) FindByUID(_ context.Context, uid string) (*core.Schedule, error) { + sch := new(core.Schedule) + + if err := e.db.Where("uid = ?", uid).First(sch).Error; err != nil { + return nil, err + } + + return sch, nil +} + +// FindMetaByUID implements the core.ScheduleStore.FindMetaByUID method. +func (e *ScheduleStore) FindMetaByUID(_ context.Context, uid string) (*core.ScheduleMeta, error) { + db := e.db.Table("schedules") + sch := new(core.ScheduleMeta) + + if err := db.Where("uid = ?", uid).First(sch).Error; err != nil { + return nil, err + } + + return sch, nil +} + +// Set implements the core.ScheduleStore.Set method. +func (e *ScheduleStore) Set(_ context.Context, schedule *core.Schedule) error { + return e.db.Model(core.Schedule{}).Save(schedule).Error +} + +// Archive implements the core.ScheduleStore.Archive method. +func (e *ScheduleStore) Archive(_ context.Context, ns, name string) error { + if err := e.db.Model(core.Schedule{}). + Where("namespace = ? AND name = ? AND archived = ?", ns, name, false). + Updates(map[string]interface{}{"archived": true, "finish_time": time.Now()}).Error; err != nil && !gorm.IsRecordNotFoundError(err) { + return err + } + + return nil +} + +// Delete deletes the experiment from the datastore. +func (e *ScheduleStore) Delete(_ context.Context, exp *core.Schedule) error { + err := e.db.Table("schedules").Unscoped().Delete(*exp).Error + return err +} + +// DeleteByFinishTime deletes schedules whose time difference is greater than the given time from FinishTime. +func (e *ScheduleStore) DeleteByFinishTime(_ context.Context, ttl time.Duration) error { + sches, err := e.ListMeta(context.Background(), "", "", true) + if err != nil { + return err + } + + nowTime := time.Now() + for _, sch := range sches { + if sch.FinishTime == nil { + log.Error(nil, "finish time is nil when deleting archived schedule records, skip it", "schedule", sch) + continue + } + if sch.FinishTime.Add(ttl).Before(nowTime) { + if err := e.db.Table("schedules").Unscoped().Delete(*sch).Error; err != nil { + return err + } + } + } + + return nil +} + +// DeleteByUIDs deletes schedules by the uid list. +func (e *ScheduleStore) DeleteByUIDs(_ context.Context, uids []string) error { + return e.db.Table("schedules").Where("uid IN (?)", uids).Unscoped().Delete(core.Schedule{}).Error +} + +// DeleteIncompleteSchedules implements the core.ScheduleStore.DeleteIncompleteSchedules method. +func (e *ScheduleStore) DeleteIncompleteSchedules(_ context.Context) error { + return e.db.Where("finish_time IS NULL").Unscoped().Delete(core.Schedule{}).Error +} + +func constructQueryArgs(kind, ns, name, uid string) (string, []string) { + query := "" + args := make([]string, 0) + + if kind != "" { + query += "kind = ?" + args = append(args, kind) + } + + if ns != "" { + if len(args) > 0 { + query += " AND namespace = ?" + } else { + query += "namespace = ?" + } + args = append(args, ns) + } + + if name != "" { + if len(args) > 0 { + query += " AND name = ?" + } else { + query += "name = ?" + } + args = append(args, name) + } + + if uid != "" { + if len(args) > 0 { + query += " AND uid = ?" + } else { + query += "uid = ?" + } + args = append(args, uid) + } + + return query, args +} diff --git a/pkg/dashboard/store/store.go b/pkg/dashboard/store/store.go new file mode 100644 index 0000000000..aa3196a2f1 --- /dev/null +++ b/pkg/dashboard/store/store.go @@ -0,0 +1,78 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package store + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/jinzhu/gorm" + "go.uber.org/fx" + controllermetrics "sigs.k8s.io/controller-runtime/pkg/metrics" + + config "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/store/event" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/store/experiment" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/store/metrics" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/store/schedule" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/store/workflow" +) + +var ( + // Module includes the providers provided by store. + Module = fx.Options( + fx.Provide( + experiment.NewStore, + event.NewStore, + schedule.NewStore, + workflow.NewStore, + ), + fx.Supply(controllermetrics.Registry), + fx.Invoke(metrics.Register), + fx.Invoke(experiment.DeleteIncompleteExperiments), + fx.Invoke(schedule.DeleteIncompleteSchedules), + ) + sqliteDriver = "sqlite3" +) + +// NewDBStore returns a new gorm.DB +func NewDBStore(lc fx.Lifecycle, conf *config.ChaosDashboardConfig, logger logr.Logger) (*gorm.DB, error) { + ds := conf.Database.Datasource + + // fix error `database is locked`, refer to https://github.com/mattn/go-sqlite3/blob/master/README.md#faq + if conf.Database.Driver == sqliteDriver { + ds += "?cache=shared" + } + + gormDB, err := gorm.Open(conf.Database.Driver, ds) + if err != nil { + logger.Error(err, "Failed to open DB: ", "driver => ", conf.Database.Driver) + return nil, err + } + + // fix error `database is locked`, refer to https://github.com/mattn/go-sqlite3/blob/master/README.md#faq + if conf.Database.Driver == sqliteDriver { + gormDB.DB().SetMaxOpenConns(1) + } + + lc.Append(fx.Hook{ + OnStop: func(context.Context) error { + return gormDB.Close() + }, + }) + + return gormDB, nil +} diff --git a/pkg/dashboard/store/workflow/workflow.go b/pkg/dashboard/store/workflow/workflow.go new file mode 100644 index 0000000000..dda8fb96f1 --- /dev/null +++ b/pkg/dashboard/store/workflow/workflow.go @@ -0,0 +1,184 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package workflow + +import ( + "context" + "time" + + "github.com/jinzhu/gorm" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +var log = ctrl.Log.WithName("store/workflow") + +type WorkflowStore struct { + db *gorm.DB +} + +func NewStore(db *gorm.DB) core.WorkflowStore { + db.AutoMigrate(&core.WorkflowEntity{}) + + return &WorkflowStore{db} +} + +func (it *WorkflowStore) List(ctx context.Context, namespace, name string, archived bool) ([]*core.WorkflowEntity, error) { + var entities []core.WorkflowEntity + query, args := constructQueryArgs(namespace, name, "") + + err := it.db.Where(query, args).Where("archived = ?", archived).Find(&entities).Error + if err != nil && !gorm.IsRecordNotFoundError(err) { + return nil, err + } + + var result []*core.WorkflowEntity + for _, item := range entities { + item := item + result = append(result, &item) + } + return result, nil +} + +func (it *WorkflowStore) ListMeta(ctx context.Context, namespace, name string, archived bool) ([]*core.WorkflowMeta, error) { + entities, err := it.List(ctx, namespace, name, archived) + if err != nil { + return nil, err + } + var result []*core.WorkflowMeta + for _, item := range entities { + item := item + result = append(result, &item.WorkflowMeta) + } + return result, nil +} + +func (it *WorkflowStore) FindByID(ctx context.Context, id uint) (*core.WorkflowEntity, error) { + result := new(core.WorkflowEntity) + if err := it.db.Where( + "id = ?", id). + First(result).Error; err != nil { + return nil, err + } + + return result, nil +} + +func (it *WorkflowStore) FindByUID(ctx context.Context, uid string) (*core.WorkflowEntity, error) { + result := new(core.WorkflowEntity) + if err := it.db.Where( + "uid = ?", uid). + First(result).Error; err != nil { + return nil, err + } + + return result, nil +} + +func (it *WorkflowStore) FindMetaByUID(ctx context.Context, UID string) (*core.WorkflowMeta, error) { + entity, err := it.FindByUID(ctx, UID) + if err != nil { + return nil, err + } + return &entity.WorkflowMeta, nil +} + +func (it *WorkflowStore) Save(ctx context.Context, entity *core.WorkflowEntity) error { + return it.db.Model(core.WorkflowEntity{}).Save(entity).Error +} + +func (it *WorkflowStore) DeleteByUID(ctx context.Context, uid string) error { + return it.db.Where("uid = ?", uid).Unscoped(). + Delete(core.WorkflowEntity{}).Error +} + +func (it *WorkflowStore) DeleteByUIDs(ctx context.Context, uids []string) error { + return it.db.Where("uid IN (?)", uids).Unscoped().Delete(core.WorkflowEntity{}).Error +} + +func (it *WorkflowStore) DeleteByFinishTime(ctx context.Context, ttl time.Duration) error { + workflows, err := it.ListMeta(context.Background(), "", "", true) + if err != nil { + return err + } + + nowTime := time.Now() + for _, wfl := range workflows { + if wfl.FinishTime == nil { + log.Error(nil, "workflow finish time is nil when deleting archived workflow records, skip it", "workflow", wfl) + continue + } + if wfl.FinishTime.Add(ttl).Before(nowTime) { + if err := it.db.Where("uid = ?", wfl.UID).Unscoped().Delete(*it).Error; err != nil { + return err + } + } + } + + return nil +} + +func (it *WorkflowStore) MarkAsArchived(ctx context.Context, namespace, name string) error { + if err := it.db.Model(core.WorkflowEntity{}). + Where("namespace = ? AND name = ? AND archived = ?", namespace, name, false). + Updates(map[string]interface{}{"archived": true, "finish_time": time.Now().Format(time.RFC3339)}).Error; err != nil && !gorm.IsRecordNotFoundError(err) { + return err + } + return nil +} + +func (it *WorkflowStore) MarkAsArchivedWithUID(ctx context.Context, uid string) error { + if err := it.db.Model(core.WorkflowEntity{}). + Where("uid = ? AND archived = ?", uid, false). + Updates(map[string]interface{}{"archived": true, "end_time": time.Now().Format(time.RFC3339)}).Error; err != nil && !gorm.IsRecordNotFoundError(err) { + return err + } + return nil +} +func constructQueryArgs(ns, name, uid string) (string, []string) { + query := "" + args := make([]string, 0) + + if ns != "" { + if len(args) > 0 { + query += " AND namespace = ?" + } else { + query += "namespace = ?" + } + args = append(args, ns) + } + + if name != "" { + if len(args) > 0 { + query += " AND name = ?" + } else { + query += "name = ?" + } + args = append(args, name) + } + + if uid != "" { + if len(args) > 0 { + query += " AND uid = ?" + } else { + query += "uid = ?" + } + args = append(args, uid) + } + + return query, args +} diff --git a/pkg/dashboard/swaggerdocs/docs.go b/pkg/dashboard/swaggerdocs/docs.go new file mode 100644 index 0000000000..6faa23d7fb --- /dev/null +++ b/pkg/dashboard/swaggerdocs/docs.go @@ -0,0 +1,7959 @@ +// Package swaggerdocs GENERATED BY SWAG; DO NOT EDIT +// This file was generated by swaggo/swag +package swaggerdocs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": { + "name": "GitHub Issues", + "url": "https://github.com/chaos-mesh/chaos-mesh/issues" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/archives": { + "get": { + "description": "Get archived chaos experiments.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Get archived chaos experiments.", + "parameters": [ + { + "type": "string", + "description": "namespace", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "name", + "name": "name", + "in": "query" + }, + { + "enum": [ + "PodChaos", + "IOChaos", + "NetworkChaos", + "TimeChaos", + "KernelChaos", + "StressChaos" + ], + "type": "string", + "description": "kind", + "name": "kind", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.Archive" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the specified archived experiment.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Delete the specified archived experiment.", + "parameters": [ + { + "type": "string", + "description": "uids", + "name": "uids", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/archives/schedules": { + "get": { + "description": "Get archived schedule experiments.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Get archived schedule experiments.", + "parameters": [ + { + "type": "string", + "description": "namespace", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "name", + "name": "name", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.Archive" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the specified archived schedule.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Delete the specified archived schedule.", + "parameters": [ + { + "type": "string", + "description": "uids", + "name": "uids", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/archives/schedules/{uid}": { + "get": { + "description": "Get the detail of an archived schedule experiment.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Get the detail of an archived schedule experiment.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ArchiveDetail" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the specified archived schedule.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Delete the specified archived schedule.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/archives/workflows": { + "get": { + "description": "Get archived workflow.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Get archived workflow.", + "parameters": [ + { + "type": "string", + "description": "namespace", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "name", + "name": "name", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.Archive" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the specified archived workflows.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Delete the specified archived workflows.", + "parameters": [ + { + "type": "string", + "description": "uids", + "name": "uids", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/archives/workflows/{uid}": { + "get": { + "description": "Get the detail of an archived workflow.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Get the detail of an archived workflow.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ArchiveDetail" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the specified archived workflow.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Delete the specified archived workflow.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/archives/{uid}": { + "get": { + "description": "Get the archived chaos experiment's detail by uid.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Get an archived chaos experiment.", + "parameters": [ + { + "type": "string", + "description": "the archive uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ArchiveDetail" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the specified archived experiment.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Delete the specified archived experiment.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/annotations": { + "get": { + "description": "Get the annotations of the pods in the specified namespace from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get the annotations of the pods in the specified namespace from Kubernetes cluster.", + "parameters": [ + { + "type": "string", + "description": "The pod's namespace list, split by ,", + "name": "podNamespaceList", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.MapStringSliceResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/chaos-available-namespaces": { + "get": { + "description": "Get all namespaces which could inject chaos(explosion scope) from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get all namespaces which could inject chaos(explosion scope) from Kubernetes cluster.", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/config": { + "get": { + "description": "Get the config of Dashboard.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get the config of Dashboard.", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/config.ChaosDashboardConfig" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/kinds": { + "get": { + "description": "Get all chaos kinds from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get all chaos kinds from Kubernetes cluster.", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/labels": { + "get": { + "description": "Get the labels of the pods in the specified namespace from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get the labels of the pods in the specified namespace from Kubernetes cluster.", + "parameters": [ + { + "type": "string", + "description": "The pod's namespace list, split by ,", + "name": "podNamespaceList", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.MapStringSliceResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/namespaces": { + "get": { + "description": "Get all from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get all namespaces from Kubernetes cluster.", + "deprecated": true, + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/physicalmachine-annotations": { + "get": { + "description": "Get the annotations of the physicalMachines in the specified namespace from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get the annotations of the physicalMachines in the specified namespace from Kubernetes cluster.", + "parameters": [ + { + "type": "string", + "description": "The physicalMachine's namespace list, split by ,", + "name": "physicalMachineNamespaceList", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.MapStringSliceResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/physicalmachine-labels": { + "get": { + "description": "Get the labels of the physicalMachines in the specified namespace from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get the labels of the physicalMachines in the specified namespace from Kubernetes cluster.", + "parameters": [ + { + "type": "string", + "description": "The physicalMachine's namespace list, split by ,", + "name": "physicalMachineNamespaceList", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.MapStringSliceResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/physicalmachines": { + "post": { + "description": "Get physicalMachines from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get physicalMachines from Kubernetes cluster.", + "parameters": [ + { + "description": "Request body", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1.PhysicalMachineSelectorSpec" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.PhysicalMachine" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/pods": { + "post": { + "description": "Get pods from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get pods from Kubernetes cluster.", + "parameters": [ + { + "description": "Request body", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.Pod" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/rbac-config": { + "get": { + "description": "Get the rbac config according to the user's choice.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get the rbac config according to the user's choice.", + "parameters": [ + { + "type": "string", + "description": "The namespace of RBAC", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "The role of RBAC", + "name": "role", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/events": { + "get": { + "description": "Get events from db.", + "produces": [ + "application/json" + ], + "tags": [ + "events" + ], + "summary": "list events.", + "parameters": [ + { + "type": "string", + "description": "The create time of events", + "name": "created_at", + "in": "query" + }, + { + "type": "string", + "description": "The name of the object", + "name": "name", + "in": "query" + }, + { + "type": "string", + "description": "The namespace of the object", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "The UID of the object", + "name": "object_id", + "in": "query" + }, + { + "enum": [ + "PodChaos", + "IOChaos", + "NetworkChaos", + "TimeChaos", + "KernelChaos", + "StressChaos", + "AWSChaos", + "GCPChaos", + "DNSChaos", + "Schedule" + ], + "type": "string", + "description": "kind", + "name": "kind", + "in": "query" + }, + { + "type": "number", + "description": "The max length of events list", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/core.Event" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/events/workflow/{uid}": { + "get": { + "description": "list all events for Workflow and related WorkflowNode.", + "produces": [ + "application/json" + ], + "tags": [ + "events" + ], + "summary": "cascadeFetchEventsForWorkflow list all events for Workflow and related WorkflowNode.", + "parameters": [ + { + "type": "string", + "description": "The UID of the Workflow", + "name": "uid", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "The namespace of the object", + "name": "namespace", + "in": "query" + }, + { + "type": "number", + "description": "The max length of events list", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/core.Event" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/events/{id}": { + "get": { + "description": "Get the event from db by ID.", + "produces": [ + "application/json" + ], + "tags": [ + "events" + ], + "summary": "Get an event.", + "parameters": [ + { + "type": "integer", + "description": "The event ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/core.Event" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/experiments": { + "get": { + "description": "Get chaos experiments from k8s clusters in real time.", + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "List chaos experiments.", + "parameters": [ + { + "type": "string", + "description": "filter exps by namespace", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "filter exps by name", + "name": "name", + "in": "query" + }, + { + "enum": [ + "PodChaos", + "NetworkChaos", + "IOChaos", + "StressChaos", + "KernelChaos", + "TimeChaos", + "DNSChaos", + "AWSChaos", + "GCPChaos", + "JVMChaos", + "HTTPChaos" + ], + "type": "string", + "description": "filter exps by kind", + "name": "kind", + "in": "query" + }, + { + "enum": [ + "Injecting", + "Running", + "Finished", + "Paused" + ], + "type": "string", + "description": "filter exps by status", + "name": "status", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.Experiment" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "post": { + "description": "Pass a JSON object to create a new chaos experiment. The schema for JSON is the same as the YAML schema for the Kubernetes object.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "Create a new chaos experiment.", + "parameters": [ + { + "description": "the chaos definition", + "name": "chaos", + "in": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Batch delete chaos experiments by uids.", + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "Batch delete chaos experiments.", + "parameters": [ + { + "type": "string", + "description": "the experiment uids, split with comma. Example: ?uids=uid1,uid2", + "name": "uids", + "in": "query", + "required": true + }, + { + "enum": [ + "true", + "false" + ], + "type": "string", + "description": "force", + "name": "force", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/experiments/pause/{uid}": { + "put": { + "description": "Pause a chaos experiment.", + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "Pause a chaos experiment.", + "parameters": [ + { + "type": "string", + "description": "the experiment uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/experiments/start/{uid}": { + "put": { + "description": "Start a chaos experiment.", + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "Start a chaos experiment.", + "parameters": [ + { + "type": "string", + "description": "the experiment uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/experiments/state": { + "get": { + "description": "Get the status of all experiments.", + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "Get the status of all experiments.", + "parameters": [ + { + "type": "string", + "description": "namespace", + "name": "namespace", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/status.AllChaosStatus" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/experiments/{uid}": { + "get": { + "description": "Get the chaos experiment's detail by uid.", + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "Get a chaos experiment.", + "parameters": [ + { + "type": "string", + "description": "the experiment uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ExperimentDetail" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the chaos experiment by uid.", + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "Delete a chaos experiment.", + "parameters": [ + { + "type": "string", + "description": "the experiment uid", + "name": "uid", + "in": "path", + "required": true + }, + { + "enum": [ + "true", + "false" + ], + "type": "string", + "description": "force", + "name": "force", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/schedules": { + "get": { + "description": "Get chaos schedules from k8s cluster in real time.", + "produces": [ + "application/json" + ], + "tags": [ + "schedules" + ], + "summary": "List chaos schedules.", + "parameters": [ + { + "type": "string", + "description": "filter schedules by namespace", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "filter schedules by name", + "name": "name", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.Schedule" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "post": { + "description": "Pass a JSON object to create a new schedule. The schema for JSON is the same as the YAML schema for the Kubernetes object.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "schedules" + ], + "summary": "Create a new schedule.", + "parameters": [ + { + "description": "the schedule definition", + "name": "schedule", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1.Schedule" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1alpha1.Schedule" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Batch delete schedules by uids.", + "produces": [ + "application/json" + ], + "tags": [ + "schedules" + ], + "summary": "Batch delete schedules.", + "parameters": [ + { + "type": "string", + "description": "the schedule uids, split with comma. Example: ?uids=uid1,uid2", + "name": "uids", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/schedules/pause/{uid}": { + "put": { + "description": "Pause a schedule.", + "produces": [ + "application/json" + ], + "tags": [ + "schedules" + ], + "summary": "Pause a schedule.", + "parameters": [ + { + "type": "string", + "description": "the schedule uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/schedules/start/{uid}": { + "put": { + "description": "Start a schedule.", + "produces": [ + "application/json" + ], + "tags": [ + "schedules" + ], + "summary": "Start a schedule.", + "parameters": [ + { + "type": "string", + "description": "the schedule uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/schedules/{uid}": { + "get": { + "description": "Get the schedule's detail by uid.", + "produces": [ + "application/json" + ], + "tags": [ + "schedules" + ], + "summary": "Get a schedule.", + "parameters": [ + { + "type": "string", + "description": "the schedule uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ScheduleDetail" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the schedule by uid.", + "produces": [ + "application/json" + ], + "tags": [ + "schedules" + ], + "summary": "Delete a schedule.", + "parameters": [ + { + "type": "string", + "description": "the schedule uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/templates/statuschecks": { + "get": { + "description": "Get status check templates from k8s cluster in real time.", + "produces": [ + "application/json" + ], + "tags": [ + "template" + ], + "summary": "List status check templates.", + "parameters": [ + { + "type": "string", + "description": "filter status check templates by namespace", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "filter status check templates by name", + "name": "name", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.StatusCheckTemplateBase" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "post": { + "description": "Pass a JSON object to create a new status check template.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "templates" + ], + "summary": "Create a new status check template.", + "parameters": [ + { + "description": "the status check definition", + "name": "statuscheck", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.StatusCheckTemplate" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.StatusCheckTemplate" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/templates/statuschecks/statuscheck": { + "get": { + "description": "Get the status check template's detail by namespaced name.", + "produces": [ + "application/json" + ], + "tags": [ + "templates" + ], + "summary": "Get a status check template.", + "parameters": [ + { + "type": "string", + "description": "the namespace of status check templates", + "name": "namespace", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "the name of status check templates", + "name": "name", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.StatusCheckTemplateDetail" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "put": { + "description": "Update a status check template by namespaced name.", + "produces": [ + "application/json" + ], + "tags": [ + "templates" + ], + "summary": "Update a status check template.", + "parameters": [ + { + "description": "Request body", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.StatusCheckTemplate" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.StatusCheckTemplate" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the status check template by namespaced name.", + "produces": [ + "application/json" + ], + "tags": [ + "templates" + ], + "summary": "Delete a status check template.", + "parameters": [ + { + "type": "string", + "description": "the namespace of status check templates", + "name": "namespace", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "the name of status check templates", + "name": "name", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/workflows": { + "get": { + "description": "List workflows from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "List workflows from Kubernetes cluster.", + "parameters": [ + { + "type": "string", + "description": "namespace, given empty string means list from all namespace", + "name": "namespace", + "in": "query" + }, + { + "enum": [ + "Initializing", + "Running", + "Errored", + "Finished" + ], + "type": "string", + "description": "status", + "name": "status", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/core.WorkflowMeta" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "post": { + "description": "Create a new workflow.", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "Create a new workflow.", + "parameters": [ + { + "description": "Request body", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1.Workflow" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/core.WorkflowDetail" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/workflows/parse-task/http": { + "post": { + "description": "Parse the rendered task back to the original request", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "Parse the rendered task back to the original request", + "parameters": [ + { + "description": "Rendered Task", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1.Template" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/curl.RequestForm" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/workflows/render-task/http": { + "post": { + "description": "Render a task which sends HTTP request", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "Render a task which sends HTTP request", + "parameters": [ + { + "description": "Origin HTTP Request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/curl.RequestForm" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1alpha1.Template" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/workflows/validate-task/http": { + "post": { + "description": "Validate the given template is a valid rendered HTTP Task", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "Validate the given template is a valid rendered HTTP Task", + "parameters": [ + { + "description": "Rendered Task", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1.Template" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "boolean" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/workflows/{uid}": { + "get": { + "description": "Get detailed information about the specified workflow. If that object is not existed in kubernetes, it will only return ths persisted data in the database.", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "Get detailed information about the specified workflow.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/core.WorkflowDetail" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "put": { + "description": "Update a workflow.", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "Update a workflow.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + }, + { + "description": "Request body", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1.Workflow" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/core.WorkflowDetail" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the specified workflow.", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "Delete the specified workflow.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + } + }, + "definitions": { + "config.ChaosDashboardConfig": { + "type": "object", + "properties": { + "cluster_mode": { + "description": "ClusterScoped means control Chaos Object in cluster level(all namespace).", + "type": "boolean", + "default": true + }, + "dns_server_create": { + "description": "After v2.5, the DNS server is created by default.", + "type": "boolean", + "default": true + }, + "enableFilterNamespace": { + "description": "EnableFilterNamespace will filter namespace with annotation. Only the pods/containers in namespace\nannotated with ` + "`" + `chaos-mesh.org/inject=enabled` + "`" + ` will be injected.", + "type": "boolean", + "default": false + }, + "gcp_security_mode": { + "description": "GcpSecurityMode will use the gcloud authentication to login to GKE user", + "type": "boolean", + "default": false + }, + "listen_host": { + "type": "string", + "default": "0.0.0.0" + }, + "listen_port": { + "type": "integer", + "default": 2333 + }, + "root_path": { + "type": "string", + "default": "http://localhost:2333" + }, + "security_mode": { + "description": "SecurityMode will use the token login by the user if set to true", + "type": "boolean", + "default": true + }, + "target_namespace": { + "description": "TargetNamespace is the target namespace to injecting chaos.\nIt only works with ClusterScoped is false.", + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "core.ConditionalBranch": { + "type": "object", + "properties": { + "expression": { + "type": "string" + }, + "name": { + "type": "string" + }, + "template": { + "type": "string" + } + } + }, + "core.Event": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "kind": { + "type": "string" + }, + "message": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "object_id": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "core.KubeObjectDesc": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/core.KubeObjectMeta" + }, + "spec": {} + } + }, + "core.KubeObjectMeta": { + "type": "object", + "properties": { + "annotations": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + } + } + }, + "core.Node": { + "type": "object", + "properties": { + "conditional_branches": { + "type": "array", + "items": { + "$ref": "#/definitions/core.ConditionalBranch" + } + }, + "name": { + "type": "string" + }, + "parallel": { + "type": "array", + "items": { + "$ref": "#/definitions/core.NodeNameWithTemplate" + } + }, + "serial": { + "type": "array", + "items": { + "$ref": "#/definitions/core.NodeNameWithTemplate" + } + }, + "state": { + "type": "string" + }, + "template": { + "type": "string" + }, + "type": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "core.NodeNameWithTemplate": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "template": { + "type": "string" + } + } + }, + "core.Topology": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "$ref": "#/definitions/core.Node" + } + } + } + }, + "core.WorkflowDetail": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "end_time": { + "description": "EndTime represents the time when the workflow completed all steps.", + "type": "string" + }, + "entry": { + "description": "the entry node name", + "type": "string" + }, + "finish_time": { + "description": "FinishTime represents the time when the workflow was deleted from Kubernetes.", + "type": "string" + }, + "id": { + "type": "integer" + }, + "kube_object": { + "$ref": "#/definitions/core.KubeObjectDesc" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "status": { + "type": "string" + }, + "topology": { + "$ref": "#/definitions/core.Topology" + }, + "uid": { + "type": "string" + } + } + }, + "core.WorkflowMeta": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "end_time": { + "description": "EndTime represents the time when the workflow completed all steps.", + "type": "string" + }, + "entry": { + "description": "the entry node name", + "type": "string" + }, + "finish_time": { + "description": "FinishTime represents the time when the workflow was deleted from Kubernetes.", + "type": "string" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "status": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "curl.Header": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "curl.RequestForm": { + "type": "object", + "properties": { + "body": { + "type": "string" + }, + "followLocation": { + "type": "boolean" + }, + "header": { + "$ref": "#/definitions/curl.Header" + }, + "jsonContent": { + "type": "boolean" + }, + "method": { + "type": "string" + }, + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "http.Header": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "intstr.IntOrString": { + "type": "object", + "properties": { + "intVal": { + "type": "integer" + }, + "strVal": { + "type": "string" + }, + "type": { + "type": "integer" + } + } + }, + "resource.Quantity": { + "type": "object", + "properties": { + "Format": { + "type": "string" + } + } + }, + "status.AllChaosStatus": { + "type": "object", + "properties": { + "deleting": { + "type": "integer" + }, + "finished": { + "type": "integer" + }, + "injecting": { + "type": "integer" + }, + "paused": { + "type": "integer" + }, + "running": { + "type": "integer" + } + } + }, + "types.Archive": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "types.ArchiveDetail": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "kube_object": { + "$ref": "#/definitions/core.KubeObjectDesc" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "types.Experiment": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "failed_message": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "status": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "types.ExperimentDetail": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "failed_message": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "kube_object": { + "$ref": "#/definitions/core.KubeObjectDesc" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "status": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "types.PhysicalMachine": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + } + } + }, + "types.Pod": { + "type": "object", + "properties": { + "ip": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "state": { + "type": "string" + } + } + }, + "types.Schedule": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "status": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "types.ScheduleDetail": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "experiment_uids": { + "type": "array", + "items": { + "type": "string" + } + }, + "kind": { + "type": "string" + }, + "kube_object": { + "$ref": "#/definitions/core.KubeObjectDesc" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "status": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "types.StatusCheckTemplate": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "spec": { + "$ref": "#/definitions/v1alpha1.StatusCheckTemplate" + } + } + }, + "types.StatusCheckTemplateBase": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "types.StatusCheckTemplateDetail": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "spec": { + "$ref": "#/definitions/v1alpha1.StatusCheckTemplate" + }, + "uid": { + "type": "string" + } + } + }, + "utils.APIError": { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "full_text": { + "type": "string" + }, + "message": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "utils.MapStringSliceResponse": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "utils.Response": { + "type": "object", + "properties": { + "status": { + "type": "string" + } + } + }, + "v1.AWSElasticBlockStoreVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "partition": { + "description": "partition is the partition in the volume that you want to mount.\nIf omitted, the default is to mount by volume name.\nExamples: For volume /dev/sda1, you specify the partition as \"1\".\nSimilarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty).\n+optional", + "type": "integer" + }, + "readOnly": { + "description": "readOnly value true will force the readOnly setting in VolumeMounts.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\n+optional", + "type": "boolean" + }, + "volumeID": { + "description": "volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume).\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", + "type": "string" + } + } + }, + "v1.AzureDiskVolumeSource": { + "type": "object", + "properties": { + "cachingMode": { + "description": "cachingMode is the Host Caching mode: None, Read Only, Read Write.\n+optional", + "type": "string" + }, + "diskName": { + "description": "diskName is the Name of the data disk in the blob storage", + "type": "string" + }, + "diskURI": { + "description": "diskURI is the URI of data disk in the blob storage", + "type": "string" + }, + "fsType": { + "description": "fsType is Filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional", + "type": "string" + }, + "kind": { + "description": "kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared", + "type": "string" + }, + "readOnly": { + "description": "readOnly Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + } + } + }, + "v1.AzureFileVolumeSource": { + "type": "object", + "properties": { + "readOnly": { + "description": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "secretName": { + "description": "secretName is the name of secret that contains Azure Storage Account Name and Key", + "type": "string" + }, + "shareName": { + "description": "shareName is the azure share Name", + "type": "string" + } + } + }, + "v1.CSIVolumeSource": { + "type": "object", + "properties": { + "driver": { + "description": "driver is the name of the CSI driver that handles this volume.\nConsult with your admin for the correct name as registered in the cluster.", + "type": "string" + }, + "fsType": { + "description": "fsType to mount. Ex. \"ext4\", \"xfs\", \"ntfs\".\nIf not provided, the empty value is passed to the associated CSI driver\nwhich will determine the default filesystem to apply.\n+optional", + "type": "string" + }, + "nodePublishSecretRef": { + "description": "nodePublishSecretRef is a reference to the secret object containing\nsensitive information to pass to the CSI driver to complete the CSI\nNodePublishVolume and NodeUnpublishVolume calls.\nThis field is optional, and may be empty if no secret is required. If the\nsecret object contains more than one secret, all secret references are passed.\n+optional", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "readOnly": { + "description": "readOnly specifies a read-only configuration for the volume.\nDefaults to false (read/write).\n+optional", + "type": "boolean" + }, + "volumeAttributes": { + "description": "volumeAttributes stores driver-specific properties that are passed to the CSI\ndriver. Consult your driver's documentation for supported values.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "v1.Capabilities": { + "type": "object", + "properties": { + "add": { + "description": "Added capabilities\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "drop": { + "description": "Removed capabilities\n+optional", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "v1.CephFSVolumeSource": { + "type": "object", + "properties": { + "monitors": { + "description": "monitors is Required: Monitors is a collection of Ceph monitors\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", + "type": "array", + "items": { + "type": "string" + } + }, + "path": { + "description": "path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly is Optional: Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional", + "type": "boolean" + }, + "secretFile": { + "description": "secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional", + "type": "string" + }, + "secretRef": { + "description": "secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty.\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "user": { + "description": "user is optional: User is the rados user name, default is admin\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional", + "type": "string" + } + } + }, + "v1.CinderVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef is optional: points to a secret object containing parameters used to connect\nto OpenStack.\n+optional", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "volumeID": { + "description": "volumeID used to identify the volume in cinder.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md", + "type": "string" + } + } + }, + "v1.ConfigMapEnvSource": { + "type": "object", + "properties": { + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + }, + "optional": { + "description": "Specify whether the ConfigMap must be defined\n+optional", + "type": "boolean" + } + } + }, + "v1.ConfigMapKeySelector": { + "type": "object", + "properties": { + "key": { + "description": "The key to select.", + "type": "string" + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + }, + "optional": { + "description": "Specify whether the ConfigMap or its key must be defined\n+optional", + "type": "boolean" + } + } + }, + "v1.ConfigMapProjection": { + "type": "object", + "properties": { + "items": { + "description": "items if unspecified, each key-value pair in the Data field of the referenced\nConfigMap will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the ConfigMap,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.KeyToPath" + } + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + }, + "optional": { + "description": "optional specify whether the ConfigMap or its keys must be defined\n+optional", + "type": "boolean" + } + } + }, + "v1.ConfigMapVolumeSource": { + "type": "object", + "properties": { + "defaultMode": { + "description": "defaultMode is optional: mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nDefaults to 0644.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "items": { + "description": "items if unspecified, each key-value pair in the Data field of the referenced\nConfigMap will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the ConfigMap,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.KeyToPath" + } + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + }, + "optional": { + "description": "optional specify whether the ConfigMap or its keys must be defined\n+optional", + "type": "boolean" + } + } + }, + "v1.Container": { + "type": "object", + "properties": { + "args": { + "description": "Arguments to the entrypoint.\nThe container image's CMD is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "command": { + "description": "Entrypoint array. Not executed within a shell.\nThe container image's ENTRYPOINT is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "env": { + "description": "List of environment variables to set in the container.\nCannot be updated.\n+optional\n+patchMergeKey=name\n+patchStrategy=merge", + "type": "array", + "items": { + "$ref": "#/definitions/v1.EnvVar" + } + }, + "envFrom": { + "description": "List of sources to populate environment variables in the container.\nThe keys defined within a source must be a C_IDENTIFIER. All invalid keys\nwill be reported as an event when the container is starting. When a key exists in multiple\nsources, the value associated with the last source will take precedence.\nValues defined by an Env with a duplicate key will take precedence.\nCannot be updated.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.EnvFromSource" + } + }, + "image": { + "description": "Container image name.\nMore info: https://kubernetes.io/docs/concepts/containers/images\nThis field is optional to allow higher level config management to default or override\ncontainer images in workload controllers like Deployments and StatefulSets.\n+optional", + "type": "string" + }, + "imagePullPolicy": { + "description": "Image pull policy.\nOne of Always, Never, IfNotPresent.\nDefaults to Always if :latest tag is specified, or IfNotPresent otherwise.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/containers/images#updating-images\n+optional", + "type": "string" + }, + "lifecycle": { + "description": "Actions that the management system should take in response to container lifecycle events.\nCannot be updated.\n+optional", + "$ref": "#/definitions/v1.Lifecycle" + }, + "livenessProbe": { + "description": "Periodic probe of container liveness.\nContainer will be restarted if the probe fails.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "$ref": "#/definitions/v1.Probe" + }, + "name": { + "description": "Name of the container specified as a DNS_LABEL.\nEach container in a pod must have a unique name (DNS_LABEL).\nCannot be updated.", + "type": "string" + }, + "ports": { + "description": "List of ports to expose from the container. Not specifying a port here\nDOES NOT prevent that port from being exposed. Any port which is\nlistening on the default \"0.0.0.0\" address inside a container will be\naccessible from the network.\nModifying this array with strategic merge patch may corrupt the data.\nFor more information See https://github.com/kubernetes/kubernetes/issues/108255.\nCannot be updated.\n+optional\n+patchMergeKey=containerPort\n+patchStrategy=merge\n+listType=map\n+listMapKey=containerPort\n+listMapKey=protocol", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ContainerPort" + } + }, + "readinessProbe": { + "description": "Periodic probe of container service readiness.\nContainer will be removed from service endpoints if the probe fails.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "$ref": "#/definitions/v1.Probe" + }, + "resizePolicy": { + "description": "Resources resize policy for the container.\n+featureGate=InPlacePodVerticalScaling\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ContainerResizePolicy" + } + }, + "resources": { + "description": "Compute Resources required by this container.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\n+optional", + "$ref": "#/definitions/v1.ResourceRequirements" + }, + "restartPolicy": { + "description": "RestartPolicy defines the restart behavior of individual containers in a pod.\nThis field may only be set for init containers, and the only allowed value is \"Always\".\nFor non-init containers or when this field is not specified,\nthe restart behavior is defined by the Pod's restart policy and the container type.\nSetting the RestartPolicy as \"Always\" for the init container will have the following effect:\nthis init container will be continually restarted on\nexit until all regular containers have terminated. Once all regular\ncontainers have completed, all init containers with restartPolicy \"Always\"\nwill be shut down. This lifecycle differs from normal init containers and\nis often referred to as a \"sidecar\" container. Although this init\ncontainer still starts in the init container sequence, it does not wait\nfor the container to complete before proceeding to the next init\ncontainer. Instead, the next init container starts immediately after this\ninit container is started, or after any startupProbe has successfully\ncompleted.\n+featureGate=SidecarContainers\n+optional", + "type": "string" + }, + "securityContext": { + "description": "SecurityContext defines the security options the container should be run with.\nIf set, the fields of SecurityContext override the equivalent fields of PodSecurityContext.\nMore info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/\n+optional", + "$ref": "#/definitions/v1.SecurityContext" + }, + "startupProbe": { + "description": "StartupProbe indicates that the Pod has successfully initialized.\nIf specified, no other probes are executed until this completes successfully.\nIf this probe fails, the Pod will be restarted, just as if the livenessProbe failed.\nThis can be used to provide different probe parameters at the beginning of a Pod's lifecycle,\nwhen it might take a long time to load data or warm a cache, than during steady-state operation.\nThis cannot be updated.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "$ref": "#/definitions/v1.Probe" + }, + "stdin": { + "description": "Whether this container should allocate a buffer for stdin in the container runtime. If this\nis not set, reads from stdin in the container will always result in EOF.\nDefault is false.\n+optional", + "type": "boolean" + }, + "stdinOnce": { + "description": "Whether the container runtime should close the stdin channel after it has been opened by\na single attach. When stdin is true the stdin stream will remain open across multiple attach\nsessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the\nfirst client attaches to stdin, and then remains open and accepts data until the client disconnects,\nat which time stdin is closed and remains closed until the container is restarted. If this\nflag is false, a container processes that reads from stdin will never receive an EOF.\nDefault is false\n+optional", + "type": "boolean" + }, + "terminationMessagePath": { + "description": "Optional: Path at which the file to which the container's termination message\nwill be written is mounted into the container's filesystem.\nMessage written is intended to be brief final status, such as an assertion failure message.\nWill be truncated by the node if greater than 4096 bytes. The total message length across\nall containers will be limited to 12kb.\nDefaults to /dev/termination-log.\nCannot be updated.\n+optional", + "type": "string" + }, + "terminationMessagePolicy": { + "description": "Indicate how the termination message should be populated. File will use the contents of\nterminationMessagePath to populate the container status message on both success and failure.\nFallbackToLogsOnError will use the last chunk of container log output if the termination\nmessage file is empty and the container exited with an error.\nThe log output is limited to 2048 bytes or 80 lines, whichever is smaller.\nDefaults to File.\nCannot be updated.\n+optional", + "type": "string" + }, + "tty": { + "description": "Whether this container should allocate a TTY for itself, also requires 'stdin' to be true.\nDefault is false.\n+optional", + "type": "boolean" + }, + "volumeDevices": { + "description": "volumeDevices is the list of block devices to be used by the container.\n+patchMergeKey=devicePath\n+patchStrategy=merge\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.VolumeDevice" + } + }, + "volumeMounts": { + "description": "Pod volumes to mount into the container's filesystem.\nCannot be updated.\n+optional\n+patchMergeKey=mountPath\n+patchStrategy=merge", + "type": "array", + "items": { + "$ref": "#/definitions/v1.VolumeMount" + } + }, + "workingDir": { + "description": "Container's working directory.\nIf not specified, the container runtime's default will be used, which\nmight be configured in the container image.\nCannot be updated.\n+optional", + "type": "string" + } + } + }, + "v1.ContainerPort": { + "type": "object", + "properties": { + "containerPort": { + "description": "Number of port to expose on the pod's IP address.\nThis must be a valid port number, 0 \u003c x \u003c 65536.", + "type": "integer" + }, + "hostIP": { + "description": "What host IP to bind the external port to.\n+optional", + "type": "string" + }, + "hostPort": { + "description": "Number of port to expose on the host.\nIf specified, this must be a valid port number, 0 \u003c x \u003c 65536.\nIf HostNetwork is specified, this must match ContainerPort.\nMost containers do not need this.\n+optional", + "type": "integer" + }, + "name": { + "description": "If specified, this must be an IANA_SVC_NAME and unique within the pod. Each\nnamed port in a pod must have a unique name. Name for the port that can be\nreferred to by services.\n+optional", + "type": "string" + }, + "protocol": { + "description": "Protocol for port. Must be UDP, TCP, or SCTP.\nDefaults to \"TCP\".\n+optional\n+default=\"TCP\"", + "type": "string" + } + } + }, + "v1.ContainerResizePolicy": { + "type": "object", + "properties": { + "resourceName": { + "description": "Name of the resource to which this resource resize policy applies.\nSupported values: cpu, memory.", + "type": "string" + }, + "restartPolicy": { + "description": "Restart policy to apply when specified resource is resized.\nIf not specified, it defaults to NotRequired.", + "type": "string" + } + } + }, + "v1.DownwardAPIProjection": { + "type": "object", + "properties": { + "items": { + "description": "Items is a list of DownwardAPIVolume file\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.DownwardAPIVolumeFile" + } + } + } + }, + "v1.DownwardAPIVolumeFile": { + "type": "object", + "properties": { + "fieldRef": { + "description": "Required: Selects a field of the pod: only annotations, labels, name and namespace are supported.\n+optional", + "$ref": "#/definitions/v1.ObjectFieldSelector" + }, + "mode": { + "description": "Optional: mode bits used to set permissions on this file, must be an octal value\nbetween 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nIf not specified, the volume defaultMode will be used.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "path": { + "description": "Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..'", + "type": "string" + }, + "resourceFieldRef": { + "description": "Selects a resource of the container: only resources limits and requests\n(limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.\n+optional", + "$ref": "#/definitions/v1.ResourceFieldSelector" + } + } + }, + "v1.DownwardAPIVolumeSource": { + "type": "object", + "properties": { + "defaultMode": { + "description": "Optional: mode bits to use on created files by default. Must be a\nOptional: mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nDefaults to 0644.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "items": { + "description": "Items is a list of downward API volume file\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.DownwardAPIVolumeFile" + } + } + } + }, + "v1.EmptyDirVolumeSource": { + "type": "object", + "properties": { + "medium": { + "description": "medium represents what type of storage medium should back this directory.\nThe default is \"\" which means to use the node's default medium.\nMust be an empty string (default) or Memory.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir\n+optional", + "type": "string" + }, + "sizeLimit": { + "description": "sizeLimit is the total amount of local storage required for this EmptyDir volume.\nThe size limit is also applicable for memory medium.\nThe maximum usage on memory medium EmptyDir would be the minimum value between\nthe SizeLimit specified here and the sum of memory limits of all containers in a pod.\nThe default is nil which means that the limit is undefined.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir\n+optional", + "$ref": "#/definitions/resource.Quantity" + } + } + }, + "v1.EnvFromSource": { + "type": "object", + "properties": { + "configMapRef": { + "description": "The ConfigMap to select from\n+optional", + "$ref": "#/definitions/v1.ConfigMapEnvSource" + }, + "prefix": { + "description": "An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.\n+optional", + "type": "string" + }, + "secretRef": { + "description": "The Secret to select from\n+optional", + "$ref": "#/definitions/v1.SecretEnvSource" + } + } + }, + "v1.EnvVar": { + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable. Must be a C_IDENTIFIER.", + "type": "string" + }, + "value": { + "description": "Variable references $(VAR_NAME) are expanded\nusing the previously defined environment variables in the container and\nany service environment variables. If a variable cannot be resolved,\nthe reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e.\n\"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\".\nEscaped references will never be expanded, regardless of whether the variable\nexists or not.\nDefaults to \"\".\n+optional", + "type": "string" + }, + "valueFrom": { + "description": "Source for the environment variable's value. Cannot be used if value is not empty.\n+optional", + "$ref": "#/definitions/v1.EnvVarSource" + } + } + }, + "v1.EnvVarSource": { + "type": "object", + "properties": { + "configMapKeyRef": { + "description": "Selects a key of a ConfigMap.\n+optional", + "$ref": "#/definitions/v1.ConfigMapKeySelector" + }, + "fieldRef": { + "description": "Selects a field of the pod: supports metadata.name, metadata.namespace, ` + "`" + `metadata.labels['\u003cKEY\u003e']` + "`" + `, ` + "`" + `metadata.annotations['\u003cKEY\u003e']` + "`" + `,\nspec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.\n+optional", + "$ref": "#/definitions/v1.ObjectFieldSelector" + }, + "resourceFieldRef": { + "description": "Selects a resource of the container: only resources limits and requests\n(limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.\n+optional", + "$ref": "#/definitions/v1.ResourceFieldSelector" + }, + "secretKeyRef": { + "description": "Selects a key of a secret in the pod's namespace\n+optional", + "$ref": "#/definitions/v1.SecretKeySelector" + } + } + }, + "v1.EphemeralVolumeSource": { + "type": "object", + "properties": { + "volumeClaimTemplate": { + "description": "Will be used to create a stand-alone PVC to provision the volume.\nThe pod in which this EphemeralVolumeSource is embedded will be the\nowner of the PVC, i.e. the PVC will be deleted together with the\npod. The name of the PVC will be ` + "`" + `\u003cpod name\u003e-\u003cvolume name\u003e` + "`" + ` where\n` + "`" + `\u003cvolume name\u003e` + "`" + ` is the name from the ` + "`" + `PodSpec.Volumes` + "`" + ` array\nentry. Pod validation will reject the pod if the concatenated name\nis not valid for a PVC (for example, too long).\n\nAn existing PVC with that name that is not owned by the pod\nwill *not* be used for the pod to avoid using an unrelated\nvolume by mistake. Starting the pod is then blocked until\nthe unrelated PVC is removed. If such a pre-created PVC is\nmeant to be used by the pod, the PVC has to updated with an\nowner reference to the pod once the pod exists. Normally\nthis should not be necessary, but it may be useful when\nmanually reconstructing a broken cluster.\n\nThis field is read-only and no changes will be made by Kubernetes\nto the PVC after it has been created.\n\nRequired, must not be nil.", + "$ref": "#/definitions/v1.PersistentVolumeClaimTemplate" + } + } + }, + "v1.ExecAction": { + "type": "object", + "properties": { + "command": { + "description": "Command is the command line to execute inside the container, the working directory for the\ncommand is root ('/') in the container's filesystem. The command is simply exec'd, it is\nnot run inside a shell, so traditional shell instructions ('|', etc) won't work. To use\na shell, you need to explicitly call out to that shell.\nExit status of 0 is treated as live/healthy and non-zero is unhealthy.\n+optional", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "v1.FCVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "lun": { + "description": "lun is Optional: FC target lun number\n+optional", + "type": "integer" + }, + "readOnly": { + "description": "readOnly is Optional: Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "targetWWNs": { + "description": "targetWWNs is Optional: FC target worldwide names (WWNs)\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "wwids": { + "description": "wwids Optional: FC volume world wide identifiers (wwids)\nEither wwids or combination of targetWWNs and lun must be set, but not both simultaneously.\n+optional", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "v1.FieldsV1": { + "type": "object" + }, + "v1.FlexVolumeSource": { + "type": "object", + "properties": { + "driver": { + "description": "driver is the name of the driver to use for this volume.", + "type": "string" + }, + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". The default filesystem depends on FlexVolume script.\n+optional", + "type": "string" + }, + "options": { + "description": "options is Optional: this field holds extra command options if any.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "readOnly": { + "description": "readOnly is Optional: defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef is Optional: secretRef is reference to the secret object containing\nsensitive information to pass to the plugin scripts. This may be\nempty if no secret object is specified. If the secret object\ncontains more than one secret, all secrets are passed to the plugin\nscripts.\n+optional", + "$ref": "#/definitions/v1.LocalObjectReference" + } + } + }, + "v1.FlockerVolumeSource": { + "type": "object", + "properties": { + "datasetName": { + "description": "datasetName is Name of the dataset stored as metadata -\u003e name on the dataset for Flocker\nshould be considered as deprecated\n+optional", + "type": "string" + }, + "datasetUUID": { + "description": "datasetUUID is the UUID of the dataset. This is unique identifier of a Flocker dataset\n+optional", + "type": "string" + } + } + }, + "v1.GCEPersistentDiskVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "partition": { + "description": "partition is the partition in the volume that you want to mount.\nIf omitted, the default is to mount by volume name.\nExamples: For volume /dev/sda1, you specify the partition as \"1\".\nSimilarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty).\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional", + "type": "integer" + }, + "pdName": { + "description": "pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional", + "type": "boolean" + } + } + }, + "v1.GRPCAction": { + "type": "object", + "properties": { + "port": { + "description": "Port number of the gRPC service. Number must be in the range 1 to 65535.", + "type": "integer" + }, + "service": { + "description": "Service is the name of the service to place in the gRPC HealthCheckRequest\n(see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).\n\nIf this is not specified, the default behavior is defined by gRPC.\n+optional\n+default=\"\"", + "type": "string" + } + } + }, + "v1.GitRepoVolumeSource": { + "type": "object", + "properties": { + "directory": { + "description": "directory is the target directory name.\nMust not contain or start with '..'. If '.' is supplied, the volume directory will be the\ngit repository. Otherwise, if specified, the volume will contain the git repository in\nthe subdirectory with the given name.\n+optional", + "type": "string" + }, + "repository": { + "description": "repository is the URL", + "type": "string" + }, + "revision": { + "description": "revision is the commit hash for the specified revision.\n+optional", + "type": "string" + } + } + }, + "v1.GlusterfsVolumeSource": { + "type": "object", + "properties": { + "endpoints": { + "description": "endpoints is the endpoint name that details Glusterfs topology.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", + "type": "string" + }, + "path": { + "description": "path is the Glusterfs volume path.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the Glusterfs volume to be mounted with read-only permissions.\nDefaults to false.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod\n+optional", + "type": "boolean" + } + } + }, + "v1.HTTPGetAction": { + "type": "object", + "properties": { + "host": { + "description": "Host name to connect to, defaults to the pod IP. You probably want to set\n\"Host\" in httpHeaders instead.\n+optional", + "type": "string" + }, + "httpHeaders": { + "description": "Custom headers to set in the request. HTTP allows repeated headers.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.HTTPHeader" + } + }, + "path": { + "description": "Path to access on the HTTP server.\n+optional", + "type": "string" + }, + "port": { + "description": "Name or number of the port to access on the container.\nNumber must be in the range 1 to 65535.\nName must be an IANA_SVC_NAME.", + "$ref": "#/definitions/intstr.IntOrString" + }, + "scheme": { + "description": "Scheme to use for connecting to the host.\nDefaults to HTTP.\n+optional", + "type": "string" + } + } + }, + "v1.HTTPHeader": { + "type": "object", + "properties": { + "name": { + "description": "The header field name.\nThis will be canonicalized upon output, so case-variant names will be understood as the same header.", + "type": "string" + }, + "value": { + "description": "The header field value", + "type": "string" + } + } + }, + "v1.HostPathVolumeSource": { + "type": "object", + "properties": { + "path": { + "description": "path of the directory on the host.\nIf the path is a symlink, it will follow the link to the real path.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", + "type": "string" + }, + "type": { + "description": "type for HostPath Volume\nDefaults to \"\"\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath\n+optional", + "type": "string" + } + } + }, + "v1.ISCSIVolumeSource": { + "type": "object", + "properties": { + "chapAuthDiscovery": { + "description": "chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication\n+optional", + "type": "boolean" + }, + "chapAuthSession": { + "description": "chapAuthSession defines whether support iSCSI Session CHAP authentication\n+optional", + "type": "boolean" + }, + "fsType": { + "description": "fsType is the filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "initiatorName": { + "description": "initiatorName is the custom iSCSI Initiator Name.\nIf initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface\n\u003ctarget portal\u003e:\u003cvolume name\u003e will be created for the connection.\n+optional", + "type": "string" + }, + "iqn": { + "description": "iqn is the target iSCSI Qualified Name.", + "type": "string" + }, + "iscsiInterface": { + "description": "iscsiInterface is the interface Name that uses an iSCSI transport.\nDefaults to 'default' (tcp).\n+optional", + "type": "string" + }, + "lun": { + "description": "lun represents iSCSI Target Lun number.", + "type": "integer" + }, + "portals": { + "description": "portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port\nis other than default (typically TCP ports 860 and 3260).\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "readOnly": { + "description": "readOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef is the CHAP Secret for iSCSI target and initiator authentication\n+optional", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "targetPortal": { + "description": "targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port\nis other than default (typically TCP ports 860 and 3260).", + "type": "string" + } + } + }, + "v1.KeyToPath": { + "type": "object", + "properties": { + "key": { + "description": "key is the key to project.", + "type": "string" + }, + "mode": { + "description": "mode is Optional: mode bits used to set permissions on this file.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nIf not specified, the volume defaultMode will be used.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "path": { + "description": "path is the relative path of the file to map the key to.\nMay not be an absolute path.\nMay not contain the path element '..'.\nMay not start with the string '..'.", + "type": "string" + } + } + }, + "v1.LabelSelector": { + "type": "object", + "properties": { + "matchExpressions": { + "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.LabelSelectorRequirement" + } + }, + "matchLabels": { + "description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels\nmap is equivalent to an element of matchExpressions, whose key field is \"key\", the\noperator is \"In\", and the values array contains only \"value\". The requirements are ANDed.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "v1.LabelSelectorRequirement": { + "type": "object", + "properties": { + "key": { + "description": "key is the label key that the selector applies to.", + "type": "string" + }, + "operator": { + "description": "operator represents a key's relationship to a set of values.\nValid operators are In, NotIn, Exists and DoesNotExist.", + "type": "string" + }, + "values": { + "description": "values is an array of string values. If the operator is In or NotIn,\nthe values array must be non-empty. If the operator is Exists or DoesNotExist,\nthe values array must be empty. This array is replaced during a strategic\nmerge patch.\n+optional", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "v1.Lifecycle": { + "type": "object", + "properties": { + "postStart": { + "description": "PostStart is called immediately after a container is created. If the handler fails,\nthe container is terminated and restarted according to its restart policy.\nOther management of the container blocks until the hook completes.\nMore info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks\n+optional", + "$ref": "#/definitions/v1.LifecycleHandler" + }, + "preStop": { + "description": "PreStop is called immediately before a container is terminated due to an\nAPI request or management event such as liveness/startup probe failure,\npreemption, resource contention, etc. The handler is not called if the\ncontainer crashes or exits. The Pod's termination grace period countdown begins before the\nPreStop hook is executed. Regardless of the outcome of the handler, the\ncontainer will eventually terminate within the Pod's termination grace\nperiod (unless delayed by finalizers). Other management of the container blocks until the hook completes\nor until the termination grace period is reached.\nMore info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks\n+optional", + "$ref": "#/definitions/v1.LifecycleHandler" + } + } + }, + "v1.LifecycleHandler": { + "type": "object", + "properties": { + "exec": { + "description": "Exec specifies the action to take.\n+optional", + "$ref": "#/definitions/v1.ExecAction" + }, + "httpGet": { + "description": "HTTPGet specifies the http request to perform.\n+optional", + "$ref": "#/definitions/v1.HTTPGetAction" + }, + "tcpSocket": { + "description": "Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept\nfor the backward compatibility. There are no validation of this field and\nlifecycle hooks will fail in runtime when tcp handler is specified.\n+optional", + "$ref": "#/definitions/v1.TCPSocketAction" + } + } + }, + "v1.LocalObjectReference": { + "type": "object", + "properties": { + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + } + } + }, + "v1.ManagedFieldsEntry": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the version of this resource that this field set\napplies to. The format is \"group/version\" just like the top-level\nAPIVersion field. It is necessary to track the version of a field\nset because it cannot be automatically converted.", + "type": "string" + }, + "fieldsType": { + "description": "FieldsType is the discriminator for the different fields format and version.\nThere is currently only one possible value: \"FieldsV1\"", + "type": "string" + }, + "fieldsV1": { + "description": "FieldsV1 holds the first JSON version format as described in the \"FieldsV1\" type.\n+optional", + "$ref": "#/definitions/v1.FieldsV1" + }, + "manager": { + "description": "Manager is an identifier of the workflow managing these fields.", + "type": "string" + }, + "operation": { + "description": "Operation is the type of operation which lead to this ManagedFieldsEntry being created.\nThe only valid values for this field are 'Apply' and 'Update'.", + "type": "string" + }, + "subresource": { + "description": "Subresource is the name of the subresource used to update that object, or\nempty string if the object was updated through the main resource. The\nvalue of this field is used to distinguish between managers, even if they\nshare the same name. For example, a status update will be distinct from a\nregular update using the same manager name.\nNote that the APIVersion field is not related to the Subresource field and\nit always corresponds to the version of the main resource.", + "type": "string" + }, + "time": { + "description": "Time is the timestamp of when the ManagedFields entry was added. The\ntimestamp will also be updated if a field is added, the manager\nchanges any of the owned fields value or removes a field. The\ntimestamp does not update when a field is removed from the entry\nbecause another manager took it over.\n+optional", + "type": "string" + } + } + }, + "v1.NFSVolumeSource": { + "type": "object", + "properties": { + "path": { + "description": "path that is exported by the NFS server.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the NFS export to be mounted with read-only permissions.\nDefaults to false.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs\n+optional", + "type": "boolean" + }, + "server": { + "description": "server is the hostname or IP address of the NFS server.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", + "type": "string" + } + } + }, + "v1.ObjectFieldSelector": { + "type": "object", + "properties": { + "apiVersion": { + "description": "Version of the schema the FieldPath is written in terms of, defaults to \"v1\".\n+optional", + "type": "string" + }, + "fieldPath": { + "description": "Path of the field to select in the specified API version.", + "type": "string" + } + } + }, + "v1.ObjectReference": { + "type": "object", + "properties": { + "apiVersion": { + "description": "API version of the referent.\n+optional", + "type": "string" + }, + "fieldPath": { + "description": "If referring to a piece of an object instead of an entire object, this string\nshould contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2].\nFor example, if the object reference is to a container within a pod, this would take on a value like:\n\"spec.containers{name}\" (where \"name\" refers to the name of the container that triggered\nthe event) or if no container name is specified \"spec.containers[2]\" (container with\nindex 2 in this pod). This syntax is chosen only to have some well-defined way of\nreferencing a part of an object.\nTODO: this design is not final and this field is subject to change in the future.\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind of the referent.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\n+optional", + "type": "string" + }, + "namespace": { + "description": "Namespace of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/\n+optional", + "type": "string" + }, + "resourceVersion": { + "description": "Specific resourceVersion to which this reference is made, if any.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency\n+optional", + "type": "string" + }, + "uid": { + "description": "UID of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids\n+optional", + "type": "string" + } + } + }, + "v1.OwnerReference": { + "type": "object", + "properties": { + "apiVersion": { + "description": "API version of the referent.", + "type": "string" + }, + "blockOwnerDeletion": { + "description": "If true, AND if the owner has the \"foregroundDeletion\" finalizer, then\nthe owner cannot be deleted from the key-value store until this\nreference is removed.\nSee https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion\nfor how the garbage collector interacts with this field and enforces the foreground deletion.\nDefaults to false.\nTo set this field, a user needs \"delete\" permission of the owner,\notherwise 422 (Unprocessable Entity) will be returned.\n+optional", + "type": "boolean" + }, + "controller": { + "description": "If true, this reference points to the managing controller.\n+optional", + "type": "boolean" + }, + "kind": { + "description": "Kind of the referent.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names", + "type": "string" + }, + "uid": { + "description": "UID of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids", + "type": "string" + } + } + }, + "v1.PersistentVolumeClaimSpec": { + "type": "object", + "properties": { + "accessModes": { + "description": "accessModes contains the desired access modes the volume should have.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "dataSource": { + "description": "dataSource field can be used to specify either:\n* An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)\n* An existing PVC (PersistentVolumeClaim)\nIf the provisioner or an external controller can support the specified data source,\nit will create a new volume based on the contents of the specified data source.\nWhen the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef,\nand dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified.\nIf the namespace is specified, then dataSourceRef will not be copied to dataSource.\n+optional", + "$ref": "#/definitions/v1.TypedLocalObjectReference" + }, + "dataSourceRef": { + "description": "dataSourceRef specifies the object from which to populate the volume with data, if a non-empty\nvolume is desired. This may be any object from a non-empty API group (non\ncore object) or a PersistentVolumeClaim object.\nWhen this field is specified, volume binding will only succeed if the type of\nthe specified object matches some installed volume populator or dynamic\nprovisioner.\nThis field will replace the functionality of the dataSource field and as such\nif both fields are non-empty, they must have the same value. For backwards\ncompatibility, when namespace isn't specified in dataSourceRef,\nboth fields (dataSource and dataSourceRef) will be set to the same\nvalue automatically if one of them is empty and the other is non-empty.\nWhen namespace is specified in dataSourceRef,\ndataSource isn't set to the same value and must be empty.\nThere are three important differences between dataSource and dataSourceRef:\n* While dataSource only allows two specific types of objects, dataSourceRef\n allows any non-core object, as well as PersistentVolumeClaim objects.\n* While dataSource ignores disallowed values (dropping them), dataSourceRef\n preserves all values, and generates an error if a disallowed value is\n specified.\n* While dataSource only allows local objects, dataSourceRef allows objects\n in any namespaces.\n(Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled.\n(Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled.\n+optional", + "$ref": "#/definitions/v1.TypedObjectReference" + }, + "resources": { + "description": "resources represents the minimum resources the volume should have.\nIf RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements\nthat are lower than previous value but must still be higher than capacity recorded in the\nstatus field of the claim.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources\n+optional", + "$ref": "#/definitions/v1.ResourceRequirements" + }, + "selector": { + "description": "selector is a label query over volumes to consider for binding.\n+optional", + "$ref": "#/definitions/v1.LabelSelector" + }, + "storageClassName": { + "description": "storageClassName is the name of the StorageClass required by the claim.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1\n+optional", + "type": "string" + }, + "volumeMode": { + "description": "volumeMode defines what type of volume is required by the claim.\nValue of Filesystem is implied when not included in claim spec.\n+optional", + "type": "string" + }, + "volumeName": { + "description": "volumeName is the binding reference to the PersistentVolume backing this claim.\n+optional", + "type": "string" + } + } + }, + "v1.PersistentVolumeClaimTemplate": { + "type": "object", + "properties": { + "annotations": { + "description": "Annotations is an unstructured key value map stored with a resource that may be\nset by external tools to store and retrieve arbitrary metadata. They are not\nqueryable and should be preserved when modifying objects.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "creationTimestamp": { + "description": "CreationTimestamp is a timestamp representing the server time when this object was\ncreated. It is not guaranteed to be set in happens-before order across separate operations.\nClients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system.\nRead-only.\nNull for lists.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "type": "string" + }, + "deletionGracePeriodSeconds": { + "description": "Number of seconds allowed for this object to gracefully terminate before\nit will be removed from the system. Only set when deletionTimestamp is also set.\nMay only be shortened.\nRead-only.\n+optional", + "type": "integer" + }, + "deletionTimestamp": { + "description": "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This\nfield is set by the server when a graceful deletion is requested by the user, and is not\ndirectly settable by a client. The resource is expected to be deleted (no longer visible\nfrom resource lists, and not reachable by name) after the time in this field, once the\nfinalizers list is empty. As long as the finalizers list contains items, deletion is blocked.\nOnce the deletionTimestamp is set, this value may not be unset or be set further into the\nfuture, although it may be shortened or the resource may be deleted prior to this time.\nFor example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react\nby sending a graceful termination signal to the containers in the pod. After that 30 seconds,\nthe Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,\nremove the pod from the API. In the presence of network partitions, this object may still\nexist after this timestamp, until an administrator or automated process can determine the\nresource is fully terminated.\nIf not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested.\nRead-only.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "type": "string" + }, + "finalizers": { + "description": "Must be empty before the object is deleted from the registry. Each entry\nis an identifier for the responsible component that will remove the entry\nfrom the list. If the deletionTimestamp of the object is non-nil, entries\nin this list can only be removed.\nFinalizers may be processed and removed in any order. Order is NOT enforced\nbecause it introduces significant risk of stuck finalizers.\nfinalizers is a shared field, any actor with permission can reorder it.\nIf the finalizer list is processed in order, then this can lead to a situation\nin which the component responsible for the first finalizer in the list is\nwaiting for a signal (field value, external system, or other) produced by a\ncomponent responsible for a finalizer later in the list, resulting in a deadlock.\nWithout enforced ordering finalizers are free to order amongst themselves and\nare not vulnerable to ordering changes in the list.\n+optional\n+patchStrategy=merge", + "type": "array", + "items": { + "type": "string" + } + }, + "generateName": { + "description": "GenerateName is an optional prefix, used by the server, to generate a unique\nname ONLY IF the Name field has not been provided.\nIf this field is used, the name returned to the client will be different\nthan the name passed. This value will also be combined with a unique suffix.\nThe provided value has the same validation rules as the Name field,\nand may be truncated by the length of the suffix required to make the value\nunique on the server.\n\nIf this field is specified and the generated name exists, the server will return a 409.\n\nApplied only if Name is not specified.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency\n+optional", + "type": "string" + }, + "generation": { + "description": "A sequence number representing a specific generation of the desired state.\nPopulated by the system. Read-only.\n+optional", + "type": "integer" + }, + "labels": { + "description": "Map of string keys and values that can be used to organize and categorize\n(scope and select) objects. May match selectors of replication controllers\nand services.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "managedFields": { + "description": "ManagedFields maps workflow-id and version to the set of fields\nthat are managed by that workflow. This is mostly for internal\nhousekeeping, and users typically shouldn't need to set or\nunderstand this field. A workflow can be the user's name, a\ncontroller's name, or the name of a specific apply path like\n\"ci-cd\". The set of fields is always in the version that the\nworkflow used when modifying the object.\n\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ManagedFieldsEntry" + } + }, + "name": { + "description": "Name must be unique within a namespace. Is required when creating resources, although\nsome resources may allow a client to request the generation of an appropriate name\nautomatically. Name is primarily intended for creation idempotence and configuration\ndefinition.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names\n+optional", + "type": "string" + }, + "namespace": { + "description": "Namespace defines the space within which each name must be unique. An empty namespace is\nequivalent to the \"default\" namespace, but \"default\" is the canonical representation.\nNot all objects are required to be scoped to a namespace - the value of this field for\nthose objects will be empty.\n\nMust be a DNS_LABEL.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces\n+optional", + "type": "string" + }, + "ownerReferences": { + "description": "List of objects depended by this object. If ALL objects in the list have\nbeen deleted, this object will be garbage collected. If this object is managed by a controller,\nthen an entry in this list will point to this controller, with the controller field set to true.\nThere cannot be more than one managing controller.\n+optional\n+patchMergeKey=uid\n+patchStrategy=merge", + "type": "array", + "items": { + "$ref": "#/definitions/v1.OwnerReference" + } + }, + "resourceVersion": { + "description": "An opaque value that represents the internal version of this object that can\nbe used by clients to determine when objects have changed. May be used for optimistic\nconcurrency, change detection, and the watch operation on a resource or set of resources.\nClients must treat these values as opaque and passed unmodified back to the server.\nThey may only be valid for a particular resource or set of resources.\n\nPopulated by the system.\nRead-only.\nValue must be treated as opaque by clients and .\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency\n+optional", + "type": "string" + }, + "selfLink": { + "description": "Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.\n+optional", + "type": "string" + }, + "spec": { + "description": "The specification for the PersistentVolumeClaim. The entire content is\ncopied unchanged into the PVC that gets created from this\ntemplate. The same fields as in a PersistentVolumeClaim\nare also valid here.", + "$ref": "#/definitions/v1.PersistentVolumeClaimSpec" + }, + "uid": { + "description": "UID is the unique in time and space value for this object. It is typically generated by\nthe server on successful creation of a resource and is not allowed to change on PUT\noperations.\n\nPopulated by the system.\nRead-only.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids\n+optional", + "type": "string" + } + } + }, + "v1.PersistentVolumeClaimVolumeSource": { + "type": "object", + "properties": { + "claimName": { + "description": "claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", + "type": "string" + }, + "readOnly": { + "description": "readOnly Will force the ReadOnly setting in VolumeMounts.\nDefault false.\n+optional", + "type": "boolean" + } + } + }, + "v1.PhotonPersistentDiskVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", + "type": "string" + }, + "pdID": { + "description": "pdID is the ID that identifies Photon Controller persistent disk", + "type": "string" + } + } + }, + "v1.PortworxVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fSType represents the filesystem type to mount\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\". Implicitly inferred to be \"ext4\" if unspecified.", + "type": "string" + }, + "readOnly": { + "description": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "volumeID": { + "description": "volumeID uniquely identifies a Portworx volume", + "type": "string" + } + } + }, + "v1.Probe": { + "type": "object", + "properties": { + "exec": { + "description": "Exec specifies the action to take.\n+optional", + "$ref": "#/definitions/v1.ExecAction" + }, + "failureThreshold": { + "description": "Minimum consecutive failures for the probe to be considered failed after having succeeded.\nDefaults to 3. Minimum value is 1.\n+optional", + "type": "integer" + }, + "grpc": { + "description": "GRPC specifies an action involving a GRPC port.\n+optional", + "$ref": "#/definitions/v1.GRPCAction" + }, + "httpGet": { + "description": "HTTPGet specifies the http request to perform.\n+optional", + "$ref": "#/definitions/v1.HTTPGetAction" + }, + "initialDelaySeconds": { + "description": "Number of seconds after the container has started before liveness probes are initiated.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "type": "integer" + }, + "periodSeconds": { + "description": "How often (in seconds) to perform the probe.\nDefault to 10 seconds. Minimum value is 1.\n+optional", + "type": "integer" + }, + "successThreshold": { + "description": "Minimum consecutive successes for the probe to be considered successful after having failed.\nDefaults to 1. Must be 1 for liveness and startup. Minimum value is 1.\n+optional", + "type": "integer" + }, + "tcpSocket": { + "description": "TCPSocket specifies an action involving a TCP port.\n+optional", + "$ref": "#/definitions/v1.TCPSocketAction" + }, + "terminationGracePeriodSeconds": { + "description": "Optional duration in seconds the pod needs to terminate gracefully upon probe failure.\nThe grace period is the duration in seconds after the processes running in the pod are sent\na termination signal and the time when the processes are forcibly halted with a kill signal.\nSet this value longer than the expected cleanup time for your process.\nIf this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this\nvalue overrides the value provided by the pod spec.\nValue must be non-negative integer. The value zero indicates stop immediately via\nthe kill signal (no opportunity to shut down).\nThis is a beta field and requires enabling ProbeTerminationGracePeriod feature gate.\nMinimum value is 1. spec.terminationGracePeriodSeconds is used if unset.\n+optional", + "type": "integer" + }, + "timeoutSeconds": { + "description": "Number of seconds after which the probe times out.\nDefaults to 1 second. Minimum value is 1.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "type": "integer" + } + } + }, + "v1.ProjectedVolumeSource": { + "type": "object", + "properties": { + "defaultMode": { + "description": "defaultMode are the mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "sources": { + "description": "sources is the list of volume projections\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.VolumeProjection" + } + } + } + }, + "v1.QuobyteVolumeSource": { + "type": "object", + "properties": { + "group": { + "description": "group to map volume access to\nDefault is no group\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the Quobyte volume to be mounted with read-only permissions.\nDefaults to false.\n+optional", + "type": "boolean" + }, + "registry": { + "description": "registry represents a single or multiple Quobyte Registry services\nspecified as a string as host:port pair (multiple entries are separated with commas)\nwhich acts as the central registry for volumes", + "type": "string" + }, + "tenant": { + "description": "tenant owning the given Quobyte volume in the Backend\nUsed with dynamically provisioned Quobyte volumes, value is set by the plugin\n+optional", + "type": "string" + }, + "user": { + "description": "user to map volume access to\nDefaults to serivceaccount user\n+optional", + "type": "string" + }, + "volume": { + "description": "volume is a string that references an already created Quobyte volume by name.", + "type": "string" + } + } + }, + "v1.RBDVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#rbd\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "image": { + "description": "image is the rados image name.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + "type": "string" + }, + "keyring": { + "description": "keyring is the path to key ring for RBDUser.\nDefault is /etc/ceph/keyring.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional", + "type": "string" + }, + "monitors": { + "description": "monitors is a collection of Ceph monitors.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + "type": "array", + "items": { + "type": "string" + } + }, + "pool": { + "description": "pool is the rados pool name.\nDefault is rbd.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef is name of the authentication secret for RBDUser. If provided\noverrides keyring.\nDefault is nil.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "user": { + "description": "user is the rados user name.\nDefault is admin.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional", + "type": "string" + } + } + }, + "v1.ResourceClaim": { + "type": "object", + "properties": { + "name": { + "description": "Name must match the name of one entry in pod.spec.resourceClaims of\nthe Pod where this field is used. It makes that resource available\ninside a container.", + "type": "string" + } + } + }, + "v1.ResourceFieldSelector": { + "type": "object", + "properties": { + "containerName": { + "description": "Container name: required for volumes, optional for env vars\n+optional", + "type": "string" + }, + "divisor": { + "description": "Specifies the output format of the exposed resources, defaults to \"1\"\n+optional", + "$ref": "#/definitions/resource.Quantity" + }, + "resource": { + "description": "Required: resource to select", + "type": "string" + } + } + }, + "v1.ResourceList": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/resource.Quantity" + } + }, + "v1.ResourceRequirements": { + "type": "object", + "properties": { + "claims": { + "description": "Claims lists the names of resources, defined in spec.resourceClaims,\nthat are used by this container.\n\nThis is an alpha field and requires enabling the\nDynamicResourceAllocation feature gate.\n\nThis field is immutable. It can only be set for containers.\n\n+listType=map\n+listMapKey=name\n+featureGate=DynamicResourceAllocation\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ResourceClaim" + } + }, + "limits": { + "description": "Limits describes the maximum amount of compute resources allowed.\nMore info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\n+optional", + "$ref": "#/definitions/v1.ResourceList" + }, + "requests": { + "description": "Requests describes the minimum amount of compute resources required.\nIf Requests is omitted for a container, it defaults to Limits if that is explicitly specified,\notherwise to an implementation-defined value. Requests cannot exceed Limits.\nMore info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\n+optional", + "$ref": "#/definitions/v1.ResourceList" + } + } + }, + "v1.SELinuxOptions": { + "type": "object", + "properties": { + "level": { + "description": "Level is SELinux level label that applies to the container.\n+optional", + "type": "string" + }, + "role": { + "description": "Role is a SELinux role label that applies to the container.\n+optional", + "type": "string" + }, + "type": { + "description": "Type is a SELinux type label that applies to the container.\n+optional", + "type": "string" + }, + "user": { + "description": "User is a SELinux user label that applies to the container.\n+optional", + "type": "string" + } + } + }, + "v1.ScaleIOVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\".\nDefault is \"xfs\".\n+optional", + "type": "string" + }, + "gateway": { + "description": "gateway is the host address of the ScaleIO API Gateway.", + "type": "string" + }, + "protectionDomain": { + "description": "protectionDomain is the name of the ScaleIO Protection Domain for the configured storage.\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef references to the secret for ScaleIO user and other\nsensitive information. If this is not provided, Login operation will fail.", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "sslEnabled": { + "description": "sslEnabled Flag enable/disable SSL communication with Gateway, default false\n+optional", + "type": "boolean" + }, + "storageMode": { + "description": "storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned.\nDefault is ThinProvisioned.\n+optional", + "type": "string" + }, + "storagePool": { + "description": "storagePool is the ScaleIO Storage Pool associated with the protection domain.\n+optional", + "type": "string" + }, + "system": { + "description": "system is the name of the storage system as configured in ScaleIO.", + "type": "string" + }, + "volumeName": { + "description": "volumeName is the name of a volume already created in the ScaleIO system\nthat is associated with this volume source.", + "type": "string" + } + } + }, + "v1.SeccompProfile": { + "type": "object", + "properties": { + "localhostProfile": { + "description": "localhostProfile indicates a profile defined in a file on the node should be used.\nThe profile must be preconfigured on the node to work.\nMust be a descending path, relative to the kubelet's configured seccomp profile location.\nMust be set if type is \"Localhost\". Must NOT be set for any other type.\n+optional", + "type": "string" + }, + "type": { + "description": "type indicates which kind of seccomp profile will be applied.\nValid options are:\n\nLocalhost - a profile defined in a file on the node should be used.\nRuntimeDefault - the container runtime default profile should be used.\nUnconfined - no profile should be applied.\n+unionDiscriminator", + "type": "string" + } + } + }, + "v1.SecretEnvSource": { + "type": "object", + "properties": { + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + }, + "optional": { + "description": "Specify whether the Secret must be defined\n+optional", + "type": "boolean" + } + } + }, + "v1.SecretKeySelector": { + "type": "object", + "properties": { + "key": { + "description": "The key of the secret to select from. Must be a valid secret key.", + "type": "string" + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + }, + "optional": { + "description": "Specify whether the Secret or its key must be defined\n+optional", + "type": "boolean" + } + } + }, + "v1.SecretProjection": { + "type": "object", + "properties": { + "items": { + "description": "items if unspecified, each key-value pair in the Data field of the referenced\nSecret will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the Secret,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.KeyToPath" + } + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + }, + "optional": { + "description": "optional field specify whether the Secret or its key must be defined\n+optional", + "type": "boolean" + } + } + }, + "v1.SecretVolumeSource": { + "type": "object", + "properties": { + "defaultMode": { + "description": "defaultMode is Optional: mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values\nfor mode bits. Defaults to 0644.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "items": { + "description": "items If unspecified, each key-value pair in the Data field of the referenced\nSecret will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the Secret,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.KeyToPath" + } + }, + "optional": { + "description": "optional field specify whether the Secret or its keys must be defined\n+optional", + "type": "boolean" + }, + "secretName": { + "description": "secretName is the name of the secret in the pod's namespace to use.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#secret\n+optional", + "type": "string" + } + } + }, + "v1.SecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "description": "AllowPrivilegeEscalation controls whether a process can gain more\nprivileges than its parent process. This bool directly controls if\nthe no_new_privs flag will be set on the container process.\nAllowPrivilegeEscalation is true always when the container is:\n1) run as Privileged\n2) has CAP_SYS_ADMIN\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "boolean" + }, + "capabilities": { + "description": "The capabilities to add/drop when running containers.\nDefaults to the default set of capabilities granted by the container runtime.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "$ref": "#/definitions/v1.Capabilities" + }, + "privileged": { + "description": "Run container in privileged mode.\nProcesses in privileged containers are essentially equivalent to root on the host.\nDefaults to false.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "boolean" + }, + "procMount": { + "description": "procMount denotes the type of proc mount to use for the containers.\nThe default is DefaultProcMount which uses the container runtime defaults for\nreadonly paths and masked paths.\nThis requires the ProcMountType feature flag to be enabled.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "string" + }, + "readOnlyRootFilesystem": { + "description": "Whether this container has a read-only root filesystem.\nDefault is false.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "boolean" + }, + "runAsGroup": { + "description": "The GID to run the entrypoint of the container process.\nUses runtime default if unset.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "integer" + }, + "runAsNonRoot": { + "description": "Indicates that the container must run as a non-root user.\nIf true, the Kubelet will validate the image at runtime to ensure that it\ndoes not run as UID 0 (root) and fail to start the container if it does.\nIf unset or false, no such validation will be performed.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\n+optional", + "type": "boolean" + }, + "runAsUser": { + "description": "The UID to run the entrypoint of the container process.\nDefaults to user specified in image metadata if unspecified.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "integer" + }, + "seLinuxOptions": { + "description": "The SELinux context to be applied to the container.\nIf unspecified, the container runtime will allocate a random SELinux context for each\ncontainer. May also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "$ref": "#/definitions/v1.SELinuxOptions" + }, + "seccompProfile": { + "description": "The seccomp options to use by this container. If seccomp options are\nprovided at both the pod \u0026 container level, the container options\noverride the pod options.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "$ref": "#/definitions/v1.SeccompProfile" + }, + "windowsOptions": { + "description": "The Windows specific settings applied to all containers.\nIf unspecified, the options from the PodSecurityContext will be used.\nIf set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is linux.\n+optional", + "$ref": "#/definitions/v1.WindowsSecurityContextOptions" + } + } + }, + "v1.ServiceAccountTokenProjection": { + "type": "object", + "properties": { + "audience": { + "description": "audience is the intended audience of the token. A recipient of a token\nmust identify itself with an identifier specified in the audience of the\ntoken, and otherwise should reject the token. The audience defaults to the\nidentifier of the apiserver.\n+optional", + "type": "string" + }, + "expirationSeconds": { + "description": "expirationSeconds is the requested duration of validity of the service\naccount token. As the token approaches expiration, the kubelet volume\nplugin will proactively rotate the service account token. The kubelet will\nstart trying to rotate the token if the token is older than 80 percent of\nits time to live or if the token is older than 24 hours.Defaults to 1 hour\nand must be at least 10 minutes.\n+optional", + "type": "integer" + }, + "path": { + "description": "path is the path relative to the mount point of the file to project the\ntoken into.", + "type": "string" + } + } + }, + "v1.StorageOSVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef specifies the secret to use for obtaining the StorageOS API\ncredentials. If not specified, default values will be attempted.\n+optional", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "volumeName": { + "description": "volumeName is the human-readable name of the StorageOS volume. Volume\nnames are only unique within a namespace.", + "type": "string" + }, + "volumeNamespace": { + "description": "volumeNamespace specifies the scope of the volume within StorageOS. If no\nnamespace is specified then the Pod's namespace will be used. This allows the\nKubernetes name scoping to be mirrored within StorageOS for tighter integration.\nSet VolumeName to any name to override the default behaviour.\nSet to \"default\" if you are not using namespaces within StorageOS.\nNamespaces that do not pre-exist within StorageOS will be created.\n+optional", + "type": "string" + } + } + }, + "v1.TCPSocketAction": { + "type": "object", + "properties": { + "host": { + "description": "Optional: Host name to connect to, defaults to the pod IP.\n+optional", + "type": "string" + }, + "port": { + "description": "Number or name of the port to access on the container.\nNumber must be in the range 1 to 65535.\nName must be an IANA_SVC_NAME.", + "$ref": "#/definitions/intstr.IntOrString" + } + } + }, + "v1.TypedLocalObjectReference": { + "type": "object", + "properties": { + "apiGroup": { + "description": "APIGroup is the group for the resource being referenced.\nIf APIGroup is not specified, the specified Kind must be in the core API group.\nFor any other third-party types, APIGroup is required.\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is the type of resource being referenced", + "type": "string" + }, + "name": { + "description": "Name is the name of resource being referenced", + "type": "string" + } + } + }, + "v1.TypedObjectReference": { + "type": "object", + "properties": { + "apiGroup": { + "description": "APIGroup is the group for the resource being referenced.\nIf APIGroup is not specified, the specified Kind must be in the core API group.\nFor any other third-party types, APIGroup is required.\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is the type of resource being referenced", + "type": "string" + }, + "name": { + "description": "Name is the name of resource being referenced", + "type": "string" + }, + "namespace": { + "description": "Namespace is the namespace of resource being referenced\nNote that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details.\n(Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled.\n+featureGate=CrossNamespaceVolumeDataSource\n+optional", + "type": "string" + } + } + }, + "v1.Volume": { + "type": "object", + "properties": { + "awsElasticBlockStore": { + "description": "awsElasticBlockStore represents an AWS Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\n+optional", + "$ref": "#/definitions/v1.AWSElasticBlockStoreVolumeSource" + }, + "azureDisk": { + "description": "azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.\n+optional", + "$ref": "#/definitions/v1.AzureDiskVolumeSource" + }, + "azureFile": { + "description": "azureFile represents an Azure File Service mount on the host and bind mount to the pod.\n+optional", + "$ref": "#/definitions/v1.AzureFileVolumeSource" + }, + "cephfs": { + "description": "cephFS represents a Ceph FS mount on the host that shares a pod's lifetime\n+optional", + "$ref": "#/definitions/v1.CephFSVolumeSource" + }, + "cinder": { + "description": "cinder represents a cinder volume attached and mounted on kubelets host machine.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional", + "$ref": "#/definitions/v1.CinderVolumeSource" + }, + "configMap": { + "description": "configMap represents a configMap that should populate this volume\n+optional", + "$ref": "#/definitions/v1.ConfigMapVolumeSource" + }, + "csi": { + "description": "csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature).\n+optional", + "$ref": "#/definitions/v1.CSIVolumeSource" + }, + "downwardAPI": { + "description": "downwardAPI represents downward API about the pod that should populate this volume\n+optional", + "$ref": "#/definitions/v1.DownwardAPIVolumeSource" + }, + "emptyDir": { + "description": "emptyDir represents a temporary directory that shares a pod's lifetime.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir\n+optional", + "$ref": "#/definitions/v1.EmptyDirVolumeSource" + }, + "ephemeral": { + "description": "ephemeral represents a volume that is handled by a cluster storage driver.\nThe volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts,\nand deleted when the pod is removed.\n\nUse this if:\na) the volume is only needed while the pod runs,\nb) features of normal volumes like restoring from snapshot or capacity\n tracking are needed,\nc) the storage driver is specified through a storage class, and\nd) the storage driver supports dynamic volume provisioning through\n a PersistentVolumeClaim (see EphemeralVolumeSource for more\n information on the connection between this volume type\n and PersistentVolumeClaim).\n\nUse PersistentVolumeClaim or one of the vendor-specific\nAPIs for volumes that persist for longer than the lifecycle\nof an individual pod.\n\nUse CSI for light-weight local ephemeral volumes if the CSI driver is meant to\nbe used that way - see the documentation of the driver for\nmore information.\n\nA pod can use both types of ephemeral volumes and\npersistent volumes at the same time.\n\n+optional", + "$ref": "#/definitions/v1.EphemeralVolumeSource" + }, + "fc": { + "description": "fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.\n+optional", + "$ref": "#/definitions/v1.FCVolumeSource" + }, + "flexVolume": { + "description": "flexVolume represents a generic volume resource that is\nprovisioned/attached using an exec based plugin.\n+optional", + "$ref": "#/definitions/v1.FlexVolumeSource" + }, + "flocker": { + "description": "flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running\n+optional", + "$ref": "#/definitions/v1.FlockerVolumeSource" + }, + "gcePersistentDisk": { + "description": "gcePersistentDisk represents a GCE Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional", + "$ref": "#/definitions/v1.GCEPersistentDiskVolumeSource" + }, + "gitRepo": { + "description": "gitRepo represents a git repository at a particular revision.\nDEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an\nEmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir\ninto the Pod's container.\n+optional", + "$ref": "#/definitions/v1.GitRepoVolumeSource" + }, + "glusterfs": { + "description": "glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md\n+optional", + "$ref": "#/definitions/v1.GlusterfsVolumeSource" + }, + "hostPath": { + "description": "hostPath represents a pre-existing file or directory on the host\nmachine that is directly exposed to the container. This is generally\nused for system agents or other privileged things that are allowed\nto see the host machine. Most containers will NOT need this.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath\n---\nTODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not\nmount host directories as read/write.\n+optional", + "$ref": "#/definitions/v1.HostPathVolumeSource" + }, + "iscsi": { + "description": "iscsi represents an ISCSI Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nMore info: https://examples.k8s.io/volumes/iscsi/README.md\n+optional", + "$ref": "#/definitions/v1.ISCSIVolumeSource" + }, + "name": { + "description": "name of the volume.\nMust be a DNS_LABEL and unique within the pod.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", + "type": "string" + }, + "nfs": { + "description": "nfs represents an NFS mount on the host that shares a pod's lifetime\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs\n+optional", + "$ref": "#/definitions/v1.NFSVolumeSource" + }, + "persistentVolumeClaim": { + "description": "persistentVolumeClaimVolumeSource represents a reference to a\nPersistentVolumeClaim in the same namespace.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims\n+optional", + "$ref": "#/definitions/v1.PersistentVolumeClaimVolumeSource" + }, + "photonPersistentDisk": { + "description": "photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine", + "$ref": "#/definitions/v1.PhotonPersistentDiskVolumeSource" + }, + "portworxVolume": { + "description": "portworxVolume represents a portworx volume attached and mounted on kubelets host machine\n+optional", + "$ref": "#/definitions/v1.PortworxVolumeSource" + }, + "projected": { + "description": "projected items for all in one resources secrets, configmaps, and downward API", + "$ref": "#/definitions/v1.ProjectedVolumeSource" + }, + "quobyte": { + "description": "quobyte represents a Quobyte mount on the host that shares a pod's lifetime\n+optional", + "$ref": "#/definitions/v1.QuobyteVolumeSource" + }, + "rbd": { + "description": "rbd represents a Rados Block Device mount on the host that shares a pod's lifetime.\nMore info: https://examples.k8s.io/volumes/rbd/README.md\n+optional", + "$ref": "#/definitions/v1.RBDVolumeSource" + }, + "scaleIO": { + "description": "scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.\n+optional", + "$ref": "#/definitions/v1.ScaleIOVolumeSource" + }, + "secret": { + "description": "secret represents a secret that should populate this volume.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#secret\n+optional", + "$ref": "#/definitions/v1.SecretVolumeSource" + }, + "storageos": { + "description": "storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.\n+optional", + "$ref": "#/definitions/v1.StorageOSVolumeSource" + }, + "vsphereVolume": { + "description": "vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine\n+optional", + "$ref": "#/definitions/v1.VsphereVirtualDiskVolumeSource" + } + } + }, + "v1.VolumeDevice": { + "type": "object", + "properties": { + "devicePath": { + "description": "devicePath is the path inside of the container that the device will be mapped to.", + "type": "string" + }, + "name": { + "description": "name must match the name of a persistentVolumeClaim in the pod", + "type": "string" + } + } + }, + "v1.VolumeMount": { + "type": "object", + "properties": { + "mountPath": { + "description": "Path within the container at which the volume should be mounted. Must\nnot contain ':'.", + "type": "string" + }, + "mountPropagation": { + "description": "mountPropagation determines how mounts are propagated from the host\nto container and the other way around.\nWhen not set, MountPropagationNone is used.\nThis field is beta in 1.10.\n+optional", + "type": "string" + }, + "name": { + "description": "This must match the Name of a Volume.", + "type": "string" + }, + "readOnly": { + "description": "Mounted read-only if true, read-write otherwise (false or unspecified).\nDefaults to false.\n+optional", + "type": "boolean" + }, + "subPath": { + "description": "Path within the volume from which the container's volume should be mounted.\nDefaults to \"\" (volume's root).\n+optional", + "type": "string" + }, + "subPathExpr": { + "description": "Expanded path within the volume from which the container's volume should be mounted.\nBehaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment.\nDefaults to \"\" (volume's root).\nSubPathExpr and SubPath are mutually exclusive.\n+optional", + "type": "string" + } + } + }, + "v1.VolumeProjection": { + "type": "object", + "properties": { + "configMap": { + "description": "configMap information about the configMap data to project\n+optional", + "$ref": "#/definitions/v1.ConfigMapProjection" + }, + "downwardAPI": { + "description": "downwardAPI information about the downwardAPI data to project\n+optional", + "$ref": "#/definitions/v1.DownwardAPIProjection" + }, + "secret": { + "description": "secret information about the secret data to project\n+optional", + "$ref": "#/definitions/v1.SecretProjection" + }, + "serviceAccountToken": { + "description": "serviceAccountToken is information about the serviceAccountToken data to project\n+optional", + "$ref": "#/definitions/v1.ServiceAccountTokenProjection" + } + } + }, + "v1.VsphereVirtualDiskVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional", + "type": "string" + }, + "storagePolicyID": { + "description": "storagePolicyID is the storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName.\n+optional", + "type": "string" + }, + "storagePolicyName": { + "description": "storagePolicyName is the storage Policy Based Management (SPBM) profile name.\n+optional", + "type": "string" + }, + "volumePath": { + "description": "volumePath is the path that identifies vSphere volume vmdk", + "type": "string" + } + } + }, + "v1.WindowsSecurityContextOptions": { + "type": "object", + "properties": { + "gmsaCredentialSpec": { + "description": "GMSACredentialSpec is where the GMSA admission webhook\n(https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the\nGMSA credential spec named by the GMSACredentialSpecName field.\n+optional", + "type": "string" + }, + "gmsaCredentialSpecName": { + "description": "GMSACredentialSpecName is the name of the GMSA credential spec to use.\n+optional", + "type": "string" + }, + "hostProcess": { + "description": "HostProcess determines if a container should be run as a 'Host Process' container.\nAll of a Pod's containers must have the same effective HostProcess value\n(it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).\nIn addition, if HostProcess is true then HostNetwork must also be set to true.\n+optional", + "type": "boolean" + }, + "runAsUserName": { + "description": "The UserName in Windows to run the entrypoint of the container process.\nDefaults to the user specified in image metadata if unspecified.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\n+optional", + "type": "string" + } + } + }, + "v1alpha1.AWSChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific aws chaos action.\nSupported action: ec2-stop / ec2-restart / detach-volume\nDefault action: ec2-stop\n+kubebuilder:validation:Enum=ec2-stop;ec2-restart;detach-volume", + "type": "string" + }, + "awsRegion": { + "description": "AWSRegion defines the region of aws.", + "type": "string" + }, + "deviceName": { + "description": "DeviceName indicates the name of the device.\nNeeded in detach-volume.\n+ui:form:when=action=='detach-volume'\n+optional", + "type": "string" + }, + "duration": { + "description": "Duration represents the duration of the chaos action.\n+optional", + "type": "string" + }, + "ec2Instance": { + "description": "Ec2Instance indicates the ID of the ec2 instance.", + "type": "string" + }, + "endpoint": { + "description": "Endpoint indicates the endpoint of the aws server. Just used it in test now.\n+ui:form:ignore\n+optional", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "secretName": { + "description": "SecretName defines the name of kubernetes secret.\n+optional", + "type": "string" + }, + "volumeID": { + "description": "EbsVolume indicates the ID of the EBS volume.\nNeeded in detach-volume.\n+ui:form:when=action=='detach-volume'\n+optional", + "type": "string" + } + } + }, + "v1alpha1.AttrOverrideSpec": { + "type": "object", + "properties": { + "atime": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.Timespec" + }, + "blocks": { + "description": "+optional", + "type": "integer" + }, + "ctime": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.Timespec" + }, + "gid": { + "description": "+optional", + "type": "integer" + }, + "ino": { + "description": "+optional", + "type": "integer" + }, + "kind": { + "description": "+optional", + "type": "string" + }, + "mtime": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.Timespec" + }, + "nlink": { + "description": "+optional", + "type": "integer" + }, + "perm": { + "description": "+optional", + "type": "integer" + }, + "rdev": { + "description": "+optional", + "type": "integer" + }, + "size": { + "description": "+optional", + "type": "integer" + }, + "uid": { + "description": "+optional", + "type": "integer" + } + } + }, + "v1alpha1.AzureChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific azure chaos action.\nSupported action: vm-stop / vm-restart / disk-detach\nDefault action: vm-stop\n+kubebuilder:validation:Enum=vm-stop;vm-restart;disk-detach", + "type": "string" + }, + "diskName": { + "description": "DiskName indicates the name of the disk.\nNeeded in disk-detach.\n+optional", + "type": "string" + }, + "duration": { + "description": "Duration represents the duration of the chaos action.\n+optional", + "type": "string" + }, + "lun": { + "description": "LUN indicates the Logical Unit Number of the data disk.\nNeeded in disk-detach.\n+optional", + "type": "integer" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "resourceGroupName": { + "description": "ResourceGroupName defines the name of ResourceGroup", + "type": "string" + }, + "secretName": { + "description": "SecretName defines the name of kubernetes secret. It is used for Azure credentials.\n+optional", + "type": "string" + }, + "subscriptionID": { + "description": "SubscriptionID defines the id of Azure subscription.", + "type": "string" + }, + "vmName": { + "description": "VMName defines the name of Virtual Machine", + "type": "string" + } + } + }, + "v1alpha1.BandwidthSpec": { + "type": "object", + "properties": { + "buffer": { + "description": "Buffer is the maximum amount of bytes that tokens can be available for instantaneously.\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "limit": { + "description": "Limit is the number of bytes that can be queued waiting for tokens to become available.\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "minburst": { + "description": "Minburst specifies the size of the peakrate bucket. For perfect\naccuracy, should be set to the MTU of the interface. If a\npeakrate is needed, but some burstiness is acceptable, this\nsize can be raised. A 3000 byte minburst allows around 3mbit/s\nof peakrate, given 1000 byte packets.\n+optional\n+kubebuilder:validation:Minimum=0", + "type": "integer" + }, + "peakrate": { + "description": "Peakrate is the maximum depletion rate of the bucket.\nThe peakrate does not need to be set, it is only necessary\nif perfect millisecond timescale shaping is required.\n+optional\n+kubebuilder:validation:Minimum=0", + "type": "integer" + }, + "rate": { + "description": "Rate is the speed knob. Allows bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means bytes per second.", + "type": "string" + } + } + }, + "v1alpha1.BlockChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific block chaos action.\nSupported action: delay\n+kubebuilder:validation:Enum=delay", + "type": "string" + }, + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "delay": { + "description": "Delay defines the delay distribution.\n+optional", + "$ref": "#/definitions/v1alpha1.BlockDelaySpec" + }, + "duration": { + "description": "Duration represents the duration of the chaos action.\n+optional", + "type": "string" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "value": { + "description": "Value is required when the mode is set to ` + "`" + `FixedMode` + "`" + ` / ` + "`" + `FixedPercentMode` + "`" + ` / ` + "`" + `RandomMaxPercentMode` + "`" + `.\nIf ` + "`" + `FixedMode` + "`" + `, provide an integer of pods to do chaos action.\nIf ` + "`" + `FixedPercentMode` + "`" + `, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF ` + "`" + `RandomMaxPercentMode` + "`" + `, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + }, + "volumeName": { + "type": "string" + } + } + }, + "v1alpha1.BlockDelaySpec": { + "type": "object", + "properties": { + "correlation": { + "description": "+optional", + "type": "string", + "default": "0" + }, + "jitter": { + "description": "+optional", + "type": "string", + "default": "0ms" + }, + "latency": { + "description": "Latency defines the latency of every io request.", + "type": "string" + } + } + }, + "v1alpha1.CPUStressor": { + "type": "object", + "properties": { + "load": { + "description": "Load specifies P percent loading per CPU worker. 0 is effectively a sleep (no load) and 100\nis full loading.\n+kubebuilder:validation:Minimum=0\n+kubebuilder:validation:Maximum=100\n+optional", + "type": "integer" + }, + "options": { + "description": "extend stress-ng options\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "workers": { + "description": "Workers specifies N workers to apply the stressor.\nMaximum 8192 workers can run by stress-ng\n+kubebuilder:validation:Maximum=8192", + "type": "integer" + } + } + }, + "v1alpha1.ChaosOnlyScheduleSpec": { + "type": "object", + "properties": { + "awsChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.AWSChaosSpec" + }, + "azureChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.AzureChaosSpec" + }, + "blockChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.BlockChaosSpec" + }, + "concurrencyPolicy": { + "description": "+optional\n+kubebuilder:validation:Enum=Forbid;Allow", + "type": "string" + }, + "dnsChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.DNSChaosSpec" + }, + "gcpChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.GCPChaosSpec" + }, + "historyLimit": { + "description": "+optional\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "httpChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.HTTPChaosSpec" + }, + "ioChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.IOChaosSpec" + }, + "jvmChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.JVMChaosSpec" + }, + "kernelChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.KernelChaosSpec" + }, + "networkChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.NetworkChaosSpec" + }, + "physicalmachineChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.PhysicalMachineChaosSpec" + }, + "podChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.PodChaosSpec" + }, + "schedule": { + "type": "string" + }, + "startingDeadlineSeconds": { + "description": "+optional\n+nullable\n+kubebuilder:validation:Minimum=0", + "type": "integer" + }, + "stressChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.StressChaosSpec" + }, + "timeChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.TimeChaosSpec" + }, + "type": { + "type": "string" + } + } + }, + "v1alpha1.ClockSpec": { + "type": "object", + "properties": { + "clock-ids-slice": { + "description": "the identifier of the particular clock on which to act.\nMore clock description in linux kernel can be found in man page of clock_getres, clock_gettime, clock_settime.\nMuti clock ids should be split with \",\"", + "type": "string" + }, + "pid": { + "description": "the pid of target program.", + "type": "integer" + }, + "time-offset": { + "description": "specifies the length of time offset.", + "type": "string" + } + } + }, + "v1alpha1.ConditionalBranch": { + "type": "object", + "properties": { + "expression": { + "description": "Expression is the expression for this conditional branch, expected type of result is boolean. If expression is empty, this branch will always be selected/the template will be spawned.\n+optional", + "type": "string" + }, + "target": { + "description": "Target is the name of other template, if expression is evaluated as true, this template will be spawned.", + "type": "string" + } + } + }, + "v1alpha1.CorruptSpec": { + "type": "object", + "properties": { + "correlation": { + "description": "+optional", + "type": "string", + "default": "0" + }, + "corrupt": { + "type": "string" + } + } + }, + "v1alpha1.DNSChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific DNS chaos action.\nSupported action: error, random\nDefault action: error\n+kubebuilder:validation:Enum=error;random", + "type": "string" + }, + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "duration": { + "description": "Duration represents the duration of the chaos action", + "type": "string" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "patterns": { + "description": "Choose which domain names to take effect, support the placeholder ? and wildcard *, or the Specified domain name.\nNote:\n 1. The wildcard * must be at the end of the string. For example, chaos-*.org is invalid.\n 2. if the patterns is empty, will take effect on all the domain names.\nFor example:\n\t\tThe value is [\"google.com\", \"github.*\", \"chaos-mes?.org\"],\n\t\twill take effect on \"google.com\", \"github.com\" and \"chaos-mesh.org\"\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "value": { + "description": "Value is required when the mode is set to ` + "`" + `FixedMode` + "`" + ` / ` + "`" + `FixedPercentMode` + "`" + ` / ` + "`" + `RandomMaxPercentMode` + "`" + `.\nIf ` + "`" + `FixedMode` + "`" + `, provide an integer of pods to do chaos action.\nIf ` + "`" + `FixedPercentMode` + "`" + `, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF ` + "`" + `RandomMaxPercentMode` + "`" + `, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.DelaySpec": { + "type": "object", + "properties": { + "correlation": { + "description": "+optional", + "type": "string", + "default": "0" + }, + "jitter": { + "description": "+optional", + "type": "string", + "default": "0ms" + }, + "latency": { + "type": "string" + }, + "reorder": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.ReorderSpec" + } + } + }, + "v1alpha1.DiskFillSpec": { + "type": "object", + "properties": { + "fill-by-fallocate": { + "description": "fill disk by fallocate", + "type": "boolean" + }, + "path": { + "description": "specifies the location to fill data in. if path not provided,\npayload will read/write from/into a temp file, temp file will be deleted after writing", + "type": "string" + }, + "size": { + "description": "specifies how many units of data will write into the file path. support unit: c=1, w=2, b=512, kB=1000,\nK=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 BYTES. example : 1M | 512kB", + "type": "string" + } + } + }, + "v1alpha1.DiskPayloadSpec": { + "type": "object", + "properties": { + "path": { + "description": "specifies the location to fill data in. if path not provided,\npayload will read/write from/into a temp file, temp file will be deleted after writing", + "type": "string" + }, + "payload-process-num": { + "description": "specifies the number of process work on writing, default 1, only 1-255 is valid value", + "type": "integer" + }, + "size": { + "description": "specifies how many units of data will write into the file path. support unit: c=1, w=2, b=512, kB=1000,\nK=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 BYTES. example : 1M | 512kB", + "type": "string" + } + } + }, + "v1alpha1.DuplicateSpec": { + "type": "object", + "properties": { + "correlation": { + "description": "+optional", + "type": "string", + "default": "0" + }, + "duplicate": { + "type": "string" + } + } + }, + "v1alpha1.FailKernRequest": { + "type": "object", + "properties": { + "callchain": { + "description": "Callchain indicate a special call chain, such as:\n ext4_mount\n -\u003e mount_subtree\n -\u003e ...\n -\u003e should_failslab\nWith an optional set of predicates and an optional set of\nparameters, which used with predicates. You can read call chan\nand predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples\nto learn more.\nIf no special call chain, just keep Callchain empty, which means it will fail at any call chain\nwith slab alloc (eg: kmalloc).", + "type": "array", + "items": { + "$ref": "#/definitions/v1alpha1.Frame" + } + }, + "failtype": { + "description": "FailType indicates what to fail, can be set to '0' / '1' / '2'\nIf ` + "`" + `0` + "`" + `, indicates slab to fail (should_failslab)\nIf ` + "`" + `1` + "`" + `, indicates alloc_page to fail (should_fail_alloc_page)\nIf ` + "`" + `2` + "`" + `, indicates bio to fail (should_fail_bio)\nYou can read:\n 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html\n 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt\nto learn more\n+kubebuilder:validation:Maximum=2\n+kubebuilder:validation:Minimum=0", + "type": "integer" + }, + "headers": { + "description": "Headers indicates the appropriate kernel headers you need.\nEg: \"linux/mmzone.h\", \"linux/blkdev.h\" and so on", + "type": "array", + "items": { + "type": "string" + } + }, + "probability": { + "description": "Probability indicates the fails with probability.\nIf you want 1%, please set this field with 1.\n+kubebuilder:validation:Minimum=0\n+kubebuilder:validation:Maximum=100", + "type": "integer" + }, + "times": { + "description": "Times indicates the max times of fails.\n+kubebuilder:validation:Minimum=0", + "type": "integer" + } + } + }, + "v1alpha1.FileAppendSpec": { + "type": "object", + "properties": { + "count": { + "description": "Count is the number of times to append the data.", + "type": "integer" + }, + "data": { + "description": "Data is the data for append.", + "type": "string" + }, + "file-name": { + "description": "FileName is the name of the file to be created, modified, deleted, renamed, or appended.", + "type": "string" + } + } + }, + "v1alpha1.FileCreateSpec": { + "type": "object", + "properties": { + "dir-name": { + "description": "DirName is the directory name to create or delete.", + "type": "string" + }, + "file-name": { + "description": "FileName is the name of the file to be created, modified, deleted, renamed, or appended.", + "type": "string" + } + } + }, + "v1alpha1.FileDeleteSpec": { + "type": "object", + "properties": { + "dir-name": { + "description": "DirName is the directory name to create or delete.", + "type": "string" + }, + "file-name": { + "description": "FileName is the name of the file to be created, modified, deleted, renamed, or appended.", + "type": "string" + } + } + }, + "v1alpha1.FileModifyPrivilegeSpec": { + "type": "object", + "properties": { + "file-name": { + "description": "FileName is the name of the file to be created, modified, deleted, renamed, or appended.", + "type": "string" + }, + "privilege": { + "description": "Privilege is the file privilege to be set.", + "type": "integer" + } + } + }, + "v1alpha1.FileRenameSpec": { + "type": "object", + "properties": { + "dest-file": { + "description": "DestFile is the name to be renamed.", + "type": "string" + }, + "source-file": { + "description": "SourceFile is the name need to be renamed.", + "type": "string" + } + } + }, + "v1alpha1.FileReplaceSpec": { + "type": "object", + "properties": { + "dest-string": { + "description": "DestStr is the destination string of the file.", + "type": "string" + }, + "file-name": { + "description": "FileName is the name of the file to be created, modified, deleted, renamed, or appended.", + "type": "string" + }, + "line": { + "description": "Line is the line number of the file to be replaced.", + "type": "integer" + }, + "origin-string": { + "description": "OriginStr is the origin string of the file.", + "type": "string" + } + } + }, + "v1alpha1.Frame": { + "type": "object", + "properties": { + "funcname": { + "description": "Funcname can be find from kernel source or ` + "`" + `/proc/kallsyms` + "`" + `, such as ` + "`" + `ext4_mount` + "`" + `", + "type": "string" + }, + "parameters": { + "description": "Parameters is used with predicate, for example, if you want to inject slab error\nin ` + "`" + `d_alloc_parallel(struct dentry *parent, const struct qstr *name)` + "`" + ` with a special\nname ` + "`" + `bananas` + "`" + `, you need to set it to ` + "`" + `struct dentry *parent, const struct qstr *name` + "`" + `\notherwise omit it.", + "type": "string" + }, + "predicate": { + "description": "Predicate will access the arguments of this Frame, example with Parameters's, you can\nset it to ` + "`" + `STRNCMP(name-\u003ename, \"bananas\", 8)` + "`" + ` to make inject only with it, or omit it\nto inject for all d_alloc_parallel call chain.", + "type": "string" + } + } + }, + "v1alpha1.GCPChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific gcp chaos action.\nSupported action: node-stop / node-reset / disk-loss\nDefault action: node-stop\n+kubebuilder:validation:Enum=node-stop;node-reset;disk-loss", + "type": "string" + }, + "deviceNames": { + "description": "The device name of disks to detach.\nNeeded in disk-loss.\n+ui:form:when=action=='disk-loss'\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "duration": { + "description": "Duration represents the duration of the chaos action.\n+optional", + "type": "string" + }, + "instance": { + "description": "Instance defines the name of the instance", + "type": "string" + }, + "project": { + "description": "Project defines the ID of gcp project.", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "secretName": { + "description": "SecretName defines the name of kubernetes secret. It is used for GCP credentials.\n+optional", + "type": "string" + }, + "zone": { + "description": "Zone defines the zone of gcp project.", + "type": "string" + } + } + }, + "v1alpha1.HTTPAbortSpec": { + "type": "object", + "properties": { + "code": { + "description": "Code is a rule to select target by http status code in response", + "type": "string" + }, + "method": { + "description": "HTTP method", + "type": "string" + }, + "path": { + "description": "Match path of Uri with wildcard matches", + "type": "string" + }, + "port": { + "description": "The TCP port that the target service listens on", + "type": "integer" + }, + "proxy_ports": { + "description": "Composed with one of the port of HTTP connection, we will only attack HTTP connection with port inside proxy_ports", + "type": "array", + "items": { + "type": "integer" + } + }, + "target": { + "description": "HTTP target: Request or Response", + "type": "string" + } + } + }, + "v1alpha1.HTTPChaosSpec": { + "type": "object", + "properties": { + "abort": { + "description": "Abort is a rule to abort a http session.\n+optional", + "type": "boolean" + }, + "code": { + "description": "Code is a rule to select target by http status code in response.\n+optional", + "type": "integer" + }, + "delay": { + "description": "Delay represents the delay of the target request/response.\nA duration string is a possibly unsigned sequence of\ndecimal numbers, each with optional fraction and a unit suffix,\nsuch as \"300ms\", \"2h45m\".\nValid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\n+optional", + "type": "string" + }, + "duration": { + "description": "Duration represents the duration of the chaos action.\n+optional", + "type": "string" + }, + "method": { + "description": "Method is a rule to select target by http method in request.\n+optional", + "type": "string" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "patch": { + "description": "Patch is a rule to patch some contents in target.\n+optional", + "$ref": "#/definitions/v1alpha1.PodHttpChaosPatchActions" + }, + "path": { + "description": "Path is a rule to select target by uri path in http request.\n+optional", + "type": "string" + }, + "port": { + "description": "Port represents the target port to be proxy of.", + "type": "integer" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "replace": { + "description": "Replace is a rule to replace some contents in target.\n+optional", + "$ref": "#/definitions/v1alpha1.PodHttpChaosReplaceActions" + }, + "request_headers": { + "description": "RequestHeaders is a rule to select target by http headers in request.\nThe key-value pairs represent header name and header value pairs.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "response_headers": { + "description": "ResponseHeaders is a rule to select target by http headers in response.\nThe key-value pairs represent header name and header value pairs.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "target": { + "description": "Target is the object to be selected and injected.\n+kubebuilder:validation:Enum=Request;Response", + "type": "string" + }, + "tls": { + "description": "TLS is the tls config,\nwill override PodHttpChaos if there are multiple HTTPChaos experiments are applied\n+optional", + "$ref": "#/definitions/v1alpha1.PodHttpChaosTLS" + }, + "value": { + "description": "Value is required when the mode is set to ` + "`" + `FixedMode` + "`" + ` / ` + "`" + `FixedPercentMode` + "`" + ` / ` + "`" + `RandomMaxPercentMode` + "`" + `.\nIf ` + "`" + `FixedMode` + "`" + `, provide an integer of pods to do chaos action.\nIf ` + "`" + `FixedPercentMode` + "`" + `, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF ` + "`" + `RandomMaxPercentMode` + "`" + `, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.HTTPConfigSpec": { + "type": "object", + "properties": { + "file_path": { + "description": "The config file path", + "type": "string" + } + } + }, + "v1alpha1.HTTPCriteria": { + "type": "object", + "properties": { + "statusCode": { + "description": "StatusCode defines the expected http status code for the request.\nA statusCode string could be a single code (e.g. 200), or\nan inclusive range (e.g. 200-400, both ` + "`" + `200` + "`" + ` and ` + "`" + `400` + "`" + ` are included).", + "type": "string" + } + } + }, + "v1alpha1.HTTPDelaySpec": { + "type": "object", + "properties": { + "code": { + "description": "Code is a rule to select target by http status code in response", + "type": "string" + }, + "delay": { + "description": "Delay represents the delay of the target request/response", + "type": "string" + }, + "method": { + "description": "HTTP method", + "type": "string" + }, + "path": { + "description": "Match path of Uri with wildcard matches", + "type": "string" + }, + "port": { + "description": "The TCP port that the target service listens on", + "type": "integer" + }, + "proxy_ports": { + "description": "Composed with one of the port of HTTP connection, we will only attack HTTP connection with port inside proxy_ports", + "type": "array", + "items": { + "type": "integer" + } + }, + "target": { + "description": "HTTP target: Request or Response", + "type": "string" + } + } + }, + "v1alpha1.HTTPRequestSpec": { + "type": "object", + "properties": { + "count": { + "description": "The number of requests to send", + "type": "integer" + }, + "enable-conn-pool": { + "description": "Enable connection pool", + "type": "boolean" + }, + "url": { + "description": "Request to send\"", + "type": "string" + } + } + }, + "v1alpha1.HTTPStatusCheck": { + "type": "object", + "properties": { + "body": { + "description": "+optional", + "type": "string" + }, + "criteria": { + "description": "Criteria defines how to determine the result of the status check.", + "$ref": "#/definitions/v1alpha1.HTTPCriteria" + }, + "headers": { + "description": "+optional", + "$ref": "#/definitions/http.Header" + }, + "method": { + "description": "+optional\n+kubebuilder:validation:Enum=GET;POST\n+kubebuilder:default=GET", + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "v1alpha1.IOChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific pod chaos action.\nSupported action: latency / fault / attrOverride / mistake\n+kubebuilder:validation:Enum=latency;fault;attrOverride;mistake", + "type": "string" + }, + "attr": { + "description": "Attr defines the overrided attribution\n+ui:form:when=action=='attrOverride'\n+optional", + "$ref": "#/definitions/v1alpha1.AttrOverrideSpec" + }, + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "delay": { + "description": "Delay defines the value of I/O chaos action delay.\nA delay string is a possibly signed sequence of\ndecimal numbers, each with optional fraction and a unit suffix,\nsuch as \"300ms\".\nValid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\n+ui:form:when=action=='latency'\n+optional", + "type": "string" + }, + "duration": { + "description": "Duration represents the duration of the chaos action.\nIt is required when the action is ` + "`" + `PodFailureAction` + "`" + `.\nA duration string is a possibly signed sequence of\ndecimal numbers, each with optional fraction and a unit suffix,\nsuch as \"300ms\", \"-1.5h\" or \"2h45m\".\nValid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\n+optional", + "type": "string" + }, + "errno": { + "description": "Errno defines the error code that returned by I/O action.\nrefer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html\n+ui:form:when=action=='fault'\n+optional", + "type": "integer" + }, + "methods": { + "description": "Methods defines the I/O methods for injecting I/O chaos action.\ndefault: all I/O methods.\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "mistake": { + "description": "Mistake defines what types of incorrectness are injected to IO operations\n+ui:form:when=action=='mistake'\n+optional", + "$ref": "#/definitions/v1alpha1.MistakeSpec" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "path": { + "description": "Path defines the path of files for injecting I/O chaos action.\n+optional", + "type": "string" + }, + "percent": { + "description": "Percent defines the percentage of injection errors and provides a number from 0-100.\ndefault: 100.\n+optional\n+kubebuilder:default=100", + "type": "integer" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "value": { + "description": "Value is required when the mode is set to ` + "`" + `FixedMode` + "`" + ` / ` + "`" + `FixedPercentMode` + "`" + ` / ` + "`" + `RandomMaxPercentMode` + "`" + `.\nIf ` + "`" + `FixedMode` + "`" + `, provide an integer of pods to do chaos action.\nIf ` + "`" + `FixedPercentMode` + "`" + `, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF ` + "`" + `RandomMaxPercentMode` + "`" + `, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + }, + "volumePath": { + "description": "VolumePath represents the mount path of injected volume", + "type": "string" + } + } + }, + "v1alpha1.JVMChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific jvm chaos action.\nSupported action: latency;return;exception;stress;gc;ruleData\n+kubebuilder:validation:Enum=latency;return;exception;stress;gc;ruleData;mysql", + "type": "string" + }, + "class": { + "description": "+optional\nJava class", + "type": "string" + }, + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "cpuCount": { + "description": "+optional\nthe CPU core number needs to use, only set it when action is stress", + "type": "integer" + }, + "database": { + "description": "the match database\ndefault value is \"\", means match all database", + "type": "string" + }, + "duration": { + "description": "Duration represents the duration of the chaos action\n+optional", + "type": "string" + }, + "exception": { + "description": "+optional\nthe exception which needs to throw for action ` + "`" + `exception` + "`" + `\nor the exception message needs to throw in action ` + "`" + `mysql` + "`" + `", + "type": "string" + }, + "latency": { + "description": "+optional\nthe latency duration for action 'latency', unit ms\nor the latency duration in action ` + "`" + `mysql` + "`" + `", + "type": "integer" + }, + "memType": { + "description": "+optional\nthe memory type needs to locate, only set it when action is stress, the value can be 'stack' or 'heap'", + "type": "string" + }, + "method": { + "description": "+optional\nthe method in Java class", + "type": "string" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "mysqlConnectorVersion": { + "description": "the version of mysql-connector-java, only support 5.X.X(set to \"5\") and 8.X.X(set to \"8\") now", + "type": "string" + }, + "name": { + "description": "+optional\nbyteman rule name, should be unique, and will generate one if not set", + "type": "string" + }, + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "ruleData": { + "description": "+optional\nthe byteman rule's data for action 'ruleData'", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "sqlType": { + "description": "the match sql type\ndefault value is \"\", means match all SQL type.\nThe value can be 'select', 'insert', 'update', 'delete', 'replace'.", + "type": "string" + }, + "table": { + "description": "the match table\ndefault value is \"\", means match all table", + "type": "string" + }, + "value": { + "description": "+optional\nthe return value for action 'return'", + "type": "string" + } + } + }, + "v1alpha1.JVMExceptionSpec": { + "type": "object", + "properties": { + "class": { + "description": "+optional\nJava class", + "type": "string" + }, + "exception": { + "description": "the exception which needs to throw for action ` + "`" + `exception` + "`" + `", + "type": "string" + }, + "method": { + "description": "+optional\nthe method in Java class", + "type": "string" + }, + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + } + } + }, + "v1alpha1.JVMGCSpec": { + "type": "object", + "properties": { + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + } + } + }, + "v1alpha1.JVMLatencySpec": { + "type": "object", + "properties": { + "class": { + "description": "+optional\nJava class", + "type": "string" + }, + "latency": { + "description": "the latency duration for action 'latency', unit ms", + "type": "integer" + }, + "method": { + "description": "+optional\nthe method in Java class", + "type": "string" + }, + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + } + } + }, + "v1alpha1.JVMReturnSpec": { + "type": "object", + "properties": { + "class": { + "description": "+optional\nJava class", + "type": "string" + }, + "method": { + "description": "+optional\nthe method in Java class", + "type": "string" + }, + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + }, + "value": { + "description": "the return value for action 'return'", + "type": "string" + } + } + }, + "v1alpha1.JVMRuleDataSpec": { + "type": "object", + "properties": { + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + }, + "rule-data": { + "description": "RuleData used to save the rule file's data, will use it when recover", + "type": "string" + } + } + }, + "v1alpha1.JVMStressSpec": { + "type": "object", + "properties": { + "cpu-count": { + "description": "the CPU core number need to use, only set it when action is stress", + "type": "integer" + }, + "mem-type": { + "description": "the memory type need to locate, only set it when action is stress, the value can be 'stack' or 'heap'", + "type": "string" + }, + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + } + } + }, + "v1alpha1.KafkaFillSpec": { + "type": "object", + "properties": { + "host": { + "description": "The host of kafka server", + "type": "string" + }, + "maxBytes": { + "description": "The max bytes to fill", + "type": "integer" + }, + "messageSize": { + "description": "The size of each message", + "type": "integer" + }, + "password": { + "description": "The password of kafka client", + "type": "string" + }, + "port": { + "description": "The port of kafka server", + "type": "integer" + }, + "reloadCommand": { + "description": "The command to reload kafka config", + "type": "string" + }, + "topic": { + "description": "The topic to attack", + "type": "string" + }, + "username": { + "description": "The username of kafka client", + "type": "string" + } + } + }, + "v1alpha1.KafkaFloodSpec": { + "type": "object", + "properties": { + "host": { + "description": "The host of kafka server", + "type": "string" + }, + "messageSize": { + "description": "The size of each message", + "type": "integer" + }, + "password": { + "description": "The password of kafka client", + "type": "string" + }, + "port": { + "description": "The port of kafka server", + "type": "integer" + }, + "threads": { + "description": "The number of worker threads", + "type": "integer" + }, + "topic": { + "description": "The topic to attack", + "type": "string" + }, + "username": { + "description": "The username of kafka client", + "type": "string" + } + } + }, + "v1alpha1.KafkaIOSpec": { + "type": "object", + "properties": { + "configFile": { + "description": "The path of server config", + "type": "string" + }, + "nonReadable": { + "description": "Make kafka cluster non-readable", + "type": "boolean" + }, + "nonWritable": { + "description": "Make kafka cluster non-writable", + "type": "boolean" + }, + "topic": { + "description": "The topic to attack", + "type": "string" + } + } + }, + "v1alpha1.KernelChaosSpec": { + "type": "object", + "properties": { + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "duration": { + "description": "Duration represents the duration of the chaos action", + "type": "string" + }, + "failKernRequest": { + "description": "FailKernRequest defines the request of kernel injection", + "$ref": "#/definitions/v1alpha1.FailKernRequest" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "value": { + "description": "Value is required when the mode is set to ` + "`" + `FixedMode` + "`" + ` / ` + "`" + `FixedPercentMode` + "`" + ` / ` + "`" + `RandomMaxPercentMode` + "`" + `.\nIf ` + "`" + `FixedMode` + "`" + `, provide an integer of pods to do chaos action.\nIf ` + "`" + `FixedPercentMode` + "`" + `, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF ` + "`" + `RandomMaxPercentMode` + "`" + `, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.LossSpec": { + "type": "object", + "properties": { + "correlation": { + "description": "+optional", + "type": "string", + "default": "0" + }, + "loss": { + "type": "string" + } + } + }, + "v1alpha1.MemoryStressor": { + "type": "object", + "properties": { + "oomScoreAdj": { + "description": "OOMScoreAdj sets the oom_score_adj of the stress process. See ` + "`" + `man 5 proc` + "`" + ` to know more\nabout this option.\n+kubebuilder:validation:Minimum=-1000\n+kubebuilder:validation:Maximum=1000\n+kubebuilder:default=0\n+optional", + "type": "integer" + }, + "options": { + "description": "extend stress-ng options\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "size": { + "description": "Size specifies N bytes consumed per vm worker, default is the total available memory.\nOne can specify the size as % of total available memory or in units of B, KB/KiB,\nMB/MiB, GB/GiB, TB/TiB.\n+optional", + "type": "string" + }, + "workers": { + "description": "Workers specifies N workers to apply the stressor.\nMaximum 8192 workers can run by stress-ng\n+kubebuilder:validation:Maximum=8192", + "type": "integer" + } + } + }, + "v1alpha1.MistakeSpec": { + "type": "object", + "properties": { + "filling": { + "description": "Filling determines what is filled in the mistake data.\n+optional\n+kubebuilder:validation:Enum=zero;random", + "type": "string" + }, + "maxLength": { + "description": "Max length of each wrong data segment in bytes\n+optional\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "maxOccurrences": { + "description": "There will be [1, MaxOccurrences] segments of wrong data.\n+optional\n+kubebuilder:validation:Minimum=1", + "type": "integer" + } + } + }, + "v1alpha1.NetworkBandwidthSpec": { + "type": "object", + "properties": { + "buffer": { + "description": "+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "device": { + "type": "string" + }, + "hostname": { + "type": "string" + }, + "ip-address": { + "type": "string" + }, + "limit": { + "description": "+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "minburst": { + "type": "integer" + }, + "peakrate": { + "type": "integer" + }, + "rate": { + "type": "string" + } + } + }, + "v1alpha1.NetworkChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific network chaos action.\nSupported action: partition, netem, delay, loss, duplicate, corrupt\nDefault action: delay\n+kubebuilder:validation:Enum=netem;delay;loss;duplicate;corrupt;partition;bandwidth", + "type": "string" + }, + "bandwidth": { + "description": "Bandwidth represents the detail about bandwidth control action\n+ui:form:when=action=='bandwidth'\n+optional", + "$ref": "#/definitions/v1alpha1.BandwidthSpec" + }, + "corrupt": { + "description": "Corrupt represents the detail about corrupt action\n+ui:form:when=action=='corrupt'\n+optional", + "$ref": "#/definitions/v1alpha1.CorruptSpec" + }, + "delay": { + "description": "Delay represents the detail about delay action\n+ui:form:when=action=='delay'\n+optional", + "$ref": "#/definitions/v1alpha1.DelaySpec" + }, + "device": { + "description": "Device represents the network device to be affected.\n+optional", + "type": "string" + }, + "direction": { + "description": "Direction represents the direction, this applies on netem and network partition action\n+optional\n+kubebuilder:validation:Enum=to;from;both\n+kubebuilder:default=to", + "type": "string" + }, + "duplicate": { + "description": "DuplicateSpec represents the detail about loss action\n+ui:form:when=action=='duplicate'\n+optional", + "$ref": "#/definitions/v1alpha1.DuplicateSpec" + }, + "duration": { + "description": "Duration represents the duration of the chaos action", + "type": "string" + }, + "externalTargets": { + "description": "ExternalTargets represents network targets outside k8s\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "loss": { + "description": "Loss represents the detail about loss action\n+ui:form:when=action=='loss'\n+optional", + "$ref": "#/definitions/v1alpha1.LossSpec" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "rate": { + "description": "Rate represents the detail about rate control action\n+ui:form:when=action=='rate'\n+optional", + "$ref": "#/definitions/v1alpha1.RateSpec" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "target": { + "description": "Target represents network target, this applies on netem and network partition action\n+optional", + "$ref": "#/definitions/v1alpha1.PodSelector" + }, + "targetDevice": { + "description": "TargetDevice represents the network device to be affected in target scope.\n+optional", + "type": "string" + }, + "value": { + "description": "Value is required when the mode is set to ` + "`" + `FixedMode` + "`" + ` / ` + "`" + `FixedPercentMode` + "`" + ` / ` + "`" + `RandomMaxPercentMode` + "`" + `.\nIf ` + "`" + `FixedMode` + "`" + `, provide an integer of pods to do chaos action.\nIf ` + "`" + `FixedPercentMode` + "`" + `, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF ` + "`" + `RandomMaxPercentMode` + "`" + `, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.NetworkCorruptSpec": { + "type": "object", + "properties": { + "correlation": { + "description": "correlation is percentage (10 is 10%)", + "type": "string" + }, + "device": { + "description": "the network interface to impact", + "type": "string" + }, + "egress-port": { + "description": "only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + }, + "hostname": { + "description": "only impact traffic to these hostnames", + "type": "string" + }, + "ip-address": { + "description": "only impact egress traffic to these IP addresses", + "type": "string" + }, + "ip-protocol": { + "description": "only impact traffic using this IP protocol, supported: tcp, udp, icmp, all", + "type": "string" + }, + "percent": { + "description": "percentage of packets to corrupt (10 is 10%)", + "type": "string" + }, + "source-port": { + "description": "only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + } + } + }, + "v1alpha1.NetworkDNSSpec": { + "type": "object", + "properties": { + "dns-domain-name": { + "description": "map this host to specified IP", + "type": "string" + }, + "dns-ip": { + "description": "map specified host to this IP address", + "type": "string" + }, + "dns-server": { + "description": "update the DNS server in /etc/resolv.conf with this value", + "type": "string" + } + } + }, + "v1alpha1.NetworkDelaySpec": { + "type": "object", + "properties": { + "accept-tcp-flags": { + "description": "only the packet which match the tcp flag can be accepted, others will be dropped.\nonly set when the IPProtocol is tcp, used for partition.", + "type": "string" + }, + "correlation": { + "description": "correlation is percentage (10 is 10%)", + "type": "string" + }, + "device": { + "description": "the network interface to impact", + "type": "string" + }, + "egress-port": { + "description": "only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + }, + "hostname": { + "description": "only impact traffic to these hostnames", + "type": "string" + }, + "ip-address": { + "description": "only impact egress traffic to these IP addresses", + "type": "string" + }, + "ip-protocol": { + "description": "only impact traffic using this IP protocol, supported: tcp, udp, icmp, all", + "type": "string" + }, + "jitter": { + "description": "jitter time, time units: ns, us (or µs), ms, s, m, h.", + "type": "string" + }, + "latency": { + "description": "delay egress time, time units: ns, us (or µs), ms, s, m, h.", + "type": "string" + }, + "source-port": { + "description": "only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + } + } + }, + "v1alpha1.NetworkDownSpec": { + "type": "object", + "properties": { + "device": { + "description": "The network interface to impact", + "type": "string" + }, + "duration": { + "description": "NIC down time, time units: ns, us (or µs), ms, s, m, h.", + "type": "string" + } + } + }, + "v1alpha1.NetworkDuplicateSpec": { + "type": "object", + "properties": { + "correlation": { + "description": "correlation is percentage (10 is 10%)", + "type": "string" + }, + "device": { + "description": "the network interface to impact", + "type": "string" + }, + "egress-port": { + "description": "only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + }, + "hostname": { + "description": "only impact traffic to these hostnames", + "type": "string" + }, + "ip-address": { + "description": "only impact egress traffic to these IP addresses", + "type": "string" + }, + "ip-protocol": { + "description": "only impact traffic using this IP protocol, supported: tcp, udp, icmp, all", + "type": "string" + }, + "percent": { + "description": "percentage of packets to duplicate (10 is 10%)", + "type": "string" + }, + "source-port": { + "description": "only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + } + } + }, + "v1alpha1.NetworkFloodSpec": { + "type": "object", + "properties": { + "duration": { + "description": "The number of seconds to run the iperf test", + "type": "string" + }, + "ip-address": { + "description": "Generate traffic to this IP address", + "type": "string" + }, + "parallel": { + "description": "The number of iperf parallel client threads to run", + "type": "integer" + }, + "port": { + "description": "Generate traffic to this port on the IP address", + "type": "string" + }, + "rate": { + "description": "The speed of network traffic, allows bps, kbps, mbps, gbps, tbps unit. bps means bytes per second", + "type": "string" + } + } + }, + "v1alpha1.NetworkLossSpec": { + "type": "object", + "properties": { + "correlation": { + "description": "correlation is percentage (10 is 10%)", + "type": "string" + }, + "device": { + "description": "the network interface to impact", + "type": "string" + }, + "egress-port": { + "description": "only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + }, + "hostname": { + "description": "only impact traffic to these hostnames", + "type": "string" + }, + "ip-address": { + "description": "only impact egress traffic to these IP addresses", + "type": "string" + }, + "ip-protocol": { + "description": "only impact traffic using this IP protocol, supported: tcp, udp, icmp, all", + "type": "string" + }, + "percent": { + "description": "percentage of packets to loss (10 is 10%)", + "type": "string" + }, + "source-port": { + "description": "only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + } + } + }, + "v1alpha1.NetworkPartitionSpec": { + "type": "object", + "properties": { + "accept-tcp-flags": { + "description": "only the packet which match the tcp flag can be accepted, others will be dropped.\nonly set when the IPProtocol is tcp, used for partition.", + "type": "string" + }, + "device": { + "description": "the network interface to impact", + "type": "string" + }, + "direction": { + "description": "specifies the partition direction, values can be 'from', 'to'.\n'from' means packets coming from the 'IPAddress' or 'Hostname' and going to your server,\n'to' means packets originating from your server and going to the 'IPAddress' or 'Hostname'.", + "type": "string" + }, + "hostname": { + "description": "only impact traffic to these hostnames", + "type": "string" + }, + "ip-address": { + "description": "only impact egress traffic to these IP addresses", + "type": "string" + }, + "ip-protocol": { + "description": "only impact egress traffic to these IP addresses", + "type": "string" + } + } + }, + "v1alpha1.PMJVMMySQLSpec": { + "type": "object", + "properties": { + "database": { + "description": "the match database\ndefault value is \"\", means match all database", + "type": "string" + }, + "exception": { + "description": "The exception which needs to throw for action ` + "`" + `exception` + "`" + `\nor the exception message needs to throw in action ` + "`" + `mysql` + "`" + `", + "type": "string" + }, + "latency": { + "description": "The latency duration for action 'latency'\nor the latency duration in action ` + "`" + `mysql` + "`" + `", + "type": "integer" + }, + "mysqlConnectorVersion": { + "description": "the version of mysql-connector-java, only support 5.X.X(set to \"5\") and 8.X.X(set to \"8\") now", + "type": "string" + }, + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + }, + "sqlType": { + "description": "the match sql type\ndefault value is \"\", means match all SQL type.\nThe value can be 'select', 'insert', 'update', 'delete', 'replace'.", + "type": "string" + }, + "table": { + "description": "the match table\ndefault value is \"\", means match all table", + "type": "string" + } + } + }, + "v1alpha1.PhysicalMachineChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "+kubebuilder:validation:Enum=stress-cpu;stress-mem;disk-read-payload;disk-write-payload;disk-fill;network-corrupt;network-duplicate;network-loss;network-delay;network-partition;network-dns;network-bandwidth;network-flood;network-down;process;jvm-exception;jvm-gc;jvm-latency;jvm-return;jvm-stress;jvm-rule-data;jvm-mysql;clock;redis-expiration;redis-penetration;redis-cacheLimit;redis-restart;redis-stop;kafka-fill;kafka-flood;kafka-io;file-create;file-modify;file-delete;file-rename;file-append;file-replace;vm;user_defined", + "type": "string" + }, + "address": { + "description": "DEPRECATED: Use Selector instead.\nOnly one of Address and Selector could be specified.\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "clock": { + "description": "+ui:form:when=action=='clock'\n+optional", + "$ref": "#/definitions/v1alpha1.ClockSpec" + }, + "disk-fill": { + "description": "+ui:form:when=action=='disk-fill'\n+optional", + "$ref": "#/definitions/v1alpha1.DiskFillSpec" + }, + "disk-read-payload": { + "description": "+ui:form:when=action=='disk-read-payload'\n+optional", + "$ref": "#/definitions/v1alpha1.DiskPayloadSpec" + }, + "disk-write-payload": { + "description": "+ui:form:when=action=='disk-write-payload'\n+optional", + "$ref": "#/definitions/v1alpha1.DiskPayloadSpec" + }, + "duration": { + "description": "Duration represents the duration of the chaos action\n+optional", + "type": "string" + }, + "file-append": { + "description": "+ui:form:when=action=='file-append'\n+optional", + "$ref": "#/definitions/v1alpha1.FileAppendSpec" + }, + "file-create": { + "description": "+ui:form:when=action=='file-create'\n+optional", + "$ref": "#/definitions/v1alpha1.FileCreateSpec" + }, + "file-delete": { + "description": "+ui:form:when=action=='file-delete'\n+optional", + "$ref": "#/definitions/v1alpha1.FileDeleteSpec" + }, + "file-modify": { + "description": "+ui:form:when=action=='file-modify'\n+optional", + "$ref": "#/definitions/v1alpha1.FileModifyPrivilegeSpec" + }, + "file-rename": { + "description": "+ui:form:when=action=='file-create'\n+optional", + "$ref": "#/definitions/v1alpha1.FileRenameSpec" + }, + "file-replace": { + "description": "+ui:form:when=action=='file-replace'\n+optional", + "$ref": "#/definitions/v1alpha1.FileReplaceSpec" + }, + "http-abort": { + "description": "+ui:form:when=action=='http-abort'\n+optional", + "$ref": "#/definitions/v1alpha1.HTTPAbortSpec" + }, + "http-config": { + "description": "+ui:form:when=action=='http-config'\n+optional", + "$ref": "#/definitions/v1alpha1.HTTPConfigSpec" + }, + "http-delay": { + "description": "+ui:form:when=action=='http-delay'\n+optional", + "$ref": "#/definitions/v1alpha1.HTTPDelaySpec" + }, + "http-request": { + "description": "+ui:form:when=action=='http-request'\n+optional", + "$ref": "#/definitions/v1alpha1.HTTPRequestSpec" + }, + "jvm-exception": { + "description": "+ui:form:when=action=='jvm-exception'\n+optional", + "$ref": "#/definitions/v1alpha1.JVMExceptionSpec" + }, + "jvm-gc": { + "description": "+ui:form:when=action=='jvm-gc'\n+optional", + "$ref": "#/definitions/v1alpha1.JVMGCSpec" + }, + "jvm-latency": { + "description": "+ui:form:when=action=='jvm-latency'\n+optional", + "$ref": "#/definitions/v1alpha1.JVMLatencySpec" + }, + "jvm-mysql": { + "description": "+ui:form:when=action=='jvm-mysql'\n+optional", + "$ref": "#/definitions/v1alpha1.PMJVMMySQLSpec" + }, + "jvm-return": { + "description": "+ui:form:when=action=='jvm-return'\n+optional", + "$ref": "#/definitions/v1alpha1.JVMReturnSpec" + }, + "jvm-rule-data": { + "description": "+ui:form:when=action=='jvm-rule-data'\n+optional", + "$ref": "#/definitions/v1alpha1.JVMRuleDataSpec" + }, + "jvm-stress": { + "description": "+ui:form:when=action=='jvm-stress'\n+optional", + "$ref": "#/definitions/v1alpha1.JVMStressSpec" + }, + "kafka-fill": { + "description": "+ui:form:when=action=='kafka-fill'\n+optional", + "$ref": "#/definitions/v1alpha1.KafkaFillSpec" + }, + "kafka-flood": { + "description": "+ui:form:when=action=='kafka-flood'\n+optional", + "$ref": "#/definitions/v1alpha1.KafkaFloodSpec" + }, + "kafka-io": { + "description": "+ui:form:when=action=='kafka-io'\n+optional", + "$ref": "#/definitions/v1alpha1.KafkaIOSpec" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "network-bandwidth": { + "description": "+ui:form:when=action=='network-bandwidth'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkBandwidthSpec" + }, + "network-corrupt": { + "description": "+ui:form:when=action=='network-corrupt'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkCorruptSpec" + }, + "network-delay": { + "description": "+ui:form:when=action=='network-delay'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkDelaySpec" + }, + "network-dns": { + "description": "+ui:form:when=action=='network-dns'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkDNSSpec" + }, + "network-down": { + "description": "+ui:form:when=action=='network-down'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkDownSpec" + }, + "network-duplicate": { + "description": "+ui:form:when=action=='network-duplicate'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkDuplicateSpec" + }, + "network-flood": { + "description": "+ui:form:when=action=='network-flood'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkFloodSpec" + }, + "network-loss": { + "description": "+ui:form:when=action=='network-loss'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkLossSpec" + }, + "network-partition": { + "description": "+ui:form:when=action=='network-partition'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkPartitionSpec" + }, + "process": { + "description": "+ui:form:when=action=='process'\n+optional", + "$ref": "#/definitions/v1alpha1.ProcessSpec" + }, + "redis-cacheLimit": { + "description": "+ui:form:when=action=='redis-cacheLimit'\n+optional", + "$ref": "#/definitions/v1alpha1.RedisCacheLimitSpec" + }, + "redis-expiration": { + "description": "+ui:form:when=action=='redis-expiration'\n+optional", + "$ref": "#/definitions/v1alpha1.RedisExpirationSpec" + }, + "redis-penetration": { + "description": "+ui:form:when=action=='redis-penetration'\n+optional", + "$ref": "#/definitions/v1alpha1.RedisPenetrationSpec" + }, + "redis-restart": { + "description": "+ui:form:when=action=='redis-restart'\n+optional", + "$ref": "#/definitions/v1alpha1.RedisSentinelRestartSpec" + }, + "redis-stop": { + "description": "+ui:form:when=action=='redis-stop'\n+optional", + "$ref": "#/definitions/v1alpha1.RedisSentinelStopSpec" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select physical machines that are used to inject chaos action.\n+optional", + "$ref": "#/definitions/v1alpha1.PhysicalMachineSelectorSpec" + }, + "stress-cpu": { + "description": "+ui:form:when=action=='stress-cpu'\n+optional", + "$ref": "#/definitions/v1alpha1.StressCPUSpec" + }, + "stress-mem": { + "description": "+ui:form:when=action=='stress-mem'\n+optional", + "$ref": "#/definitions/v1alpha1.StressMemorySpec" + }, + "user_defined": { + "description": "+ui:form:when=action=='user_defined'\n+optional", + "$ref": "#/definitions/v1alpha1.UserDefinedSpec" + }, + "value": { + "description": "Value is required when the mode is set to ` + "`" + `FixedMode` + "`" + ` / ` + "`" + `FixedPercentMode` + "`" + ` / ` + "`" + `RandomMaxPercentMode` + "`" + `.\nIf ` + "`" + `FixedMode` + "`" + `, provide an integer of physical machines to do chaos action.\nIf ` + "`" + `FixedPercentMode` + "`" + `, provide a number from 0-100 to specify the percent of physical machines the server can do chaos action.\nIF ` + "`" + `RandomMaxPercentMode` + "`" + `, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + }, + "vm": { + "description": "+ui:form:when=action=='vm'\n+optional", + "$ref": "#/definitions/v1alpha1.VMSpec" + } + } + }, + "v1alpha1.PhysicalMachineSelectorSpec": { + "type": "object", + "properties": { + "annotationSelectors": { + "description": "Map of string keys and values that can be used to select objects.\nA selector based on annotations.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "fieldSelectors": { + "description": "Map of string keys and values that can be used to select objects.\nA selector based on fields.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labelSelectors": { + "description": "Map of string keys and values that can be used to select objects.\nA selector based on labels.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "namespaces": { + "description": "Namespaces is a set of namespace to which objects belong.\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "physicalMachines": { + "description": "PhysicalMachines is a map of string keys and a set values that used to select physical machines.\nThe key defines the namespace which physical machine belong,\nand each value is a set of physical machine names.\n+optional", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "v1alpha1.PodChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific pod chaos action.\nSupported action: pod-kill / pod-failure / container-kill\nDefault action: pod-kill\n+kubebuilder:validation:Enum=pod-kill;pod-failure;container-kill", + "type": "string" + }, + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "duration": { + "description": "Duration represents the duration of the chaos action.\nIt is required when the action is ` + "`" + `PodFailureAction` + "`" + `.\nA duration string is a possibly signed sequence of\ndecimal numbers, each with optional fraction and a unit suffix,\nsuch as \"300ms\", \"-1.5h\" or \"2h45m\".\nValid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\n+optional", + "type": "string" + }, + "gracePeriod": { + "description": "GracePeriod is used in pod-kill action. It represents the duration in seconds before the pod should be deleted.\nValue must be non-negative integer. The default value is zero that indicates delete immediately.\n+optional\n+kubebuilder:validation:Minimum=0", + "type": "integer" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "value": { + "description": "Value is required when the mode is set to ` + "`" + `FixedMode` + "`" + ` / ` + "`" + `FixedPercentMode` + "`" + ` / ` + "`" + `RandomMaxPercentMode` + "`" + `.\nIf ` + "`" + `FixedMode` + "`" + `, provide an integer of pods to do chaos action.\nIf ` + "`" + `FixedPercentMode` + "`" + `, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF ` + "`" + `RandomMaxPercentMode` + "`" + `, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.PodHttpChaosPatchActions": { + "type": "object", + "properties": { + "body": { + "description": "Body is a rule to patch message body of target.\n+optional", + "$ref": "#/definitions/v1alpha1.PodHttpChaosPatchBodyAction" + }, + "headers": { + "description": "Headers is a rule to append http headers of target.\nFor example: ` + "`" + `[[\"Set-Cookie\", \"\u003cone cookie\u003e\"], [\"Set-Cookie\", \"\u003canother cookie\u003e\"]]` + "`" + `.\n+optional", + "type": "array", + "items": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "queries": { + "description": "Queries is a rule to append uri queries of target(Request only).\nFor example: ` + "`" + `[[\"foo\", \"bar\"], [\"foo\", \"unknown\"]]` + "`" + `.\n+optional", + "type": "array", + "items": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "v1alpha1.PodHttpChaosPatchBodyAction": { + "type": "object", + "properties": { + "type": { + "description": "Type represents the patch type, only support ` + "`" + `JSON` + "`" + ` as [merge patch json](https://tools.ietf.org/html/rfc7396) currently.", + "type": "string" + }, + "value": { + "description": "Value is the patch contents.", + "type": "string" + } + } + }, + "v1alpha1.PodHttpChaosReplaceActions": { + "type": "object", + "properties": { + "body": { + "description": "Body is a rule to replace http message body in target.\n+optional", + "type": "array", + "items": { + "type": "integer" + } + }, + "code": { + "description": "Code is a rule to replace http status code in response.\n+optional", + "type": "integer" + }, + "headers": { + "description": "Headers is a rule to replace http headers of target.\nThe key-value pairs represent header name and header value pairs.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "method": { + "description": "Method is a rule to replace http method in request.\n+optional", + "type": "string" + }, + "path": { + "description": "Path is rule to to replace uri path in http request.\n+optional", + "type": "string" + }, + "queries": { + "description": "Queries is a rule to replace uri queries in http request.\nFor example, with value ` + "`" + `{ \"foo\": \"unknown\" }` + "`" + `, the ` + "`" + `/?foo=bar` + "`" + ` will be altered to ` + "`" + `/?foo=unknown` + "`" + `,\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "v1alpha1.PodHttpChaosTLS": { + "type": "object", + "properties": { + "caName": { + "description": "CAName represents the data name of ca file in secret, ` + "`" + `ca.crt` + "`" + ` for example\n+optional", + "type": "string" + }, + "certName": { + "description": "CertName represents the data name of cert file in secret, ` + "`" + `tls.crt` + "`" + ` for example", + "type": "string" + }, + "keyName": { + "description": "KeyName represents the data name of key file in secret, ` + "`" + `tls.key` + "`" + ` for example", + "type": "string" + }, + "secretName": { + "description": "SecretName represents the name of required secret resource", + "type": "string" + }, + "secretNamespace": { + "description": "SecretNamespace represents the namespace of required secret resource", + "type": "string" + } + } + }, + "v1alpha1.PodSelector": { + "type": "object", + "properties": { + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "value": { + "description": "Value is required when the mode is set to ` + "`" + `FixedMode` + "`" + ` / ` + "`" + `FixedPercentMode` + "`" + ` / ` + "`" + `RandomMaxPercentMode` + "`" + `.\nIf ` + "`" + `FixedMode` + "`" + `, provide an integer of pods to do chaos action.\nIf ` + "`" + `FixedPercentMode` + "`" + `, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF ` + "`" + `RandomMaxPercentMode` + "`" + `, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.PodSelectorSpec": { + "type": "object", + "properties": { + "annotationSelectors": { + "description": "Map of string keys and values that can be used to select objects.\nA selector based on annotations.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "fieldSelectors": { + "description": "Map of string keys and values that can be used to select objects.\nA selector based on fields.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labelSelectors": { + "description": "Map of string keys and values that can be used to select objects.\nA selector based on labels.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "namespaces": { + "description": "Namespaces is a set of namespace to which objects belong.\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "nodeSelectors": { + "description": "Map of string keys and values that can be used to select nodes.\nSelector which must match a node's labels,\nand objects must belong to these selected nodes.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "nodes": { + "description": "Nodes is a set of node name and objects must belong to these nodes.\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "podPhaseSelectors": { + "description": "PodPhaseSelectors is a set of condition of a pod at the current time.\nsupported value: Pending / Running / Succeeded / Failed / Unknown\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "pods": { + "description": "Pods is a map of string keys and a set values that used to select pods.\nThe key defines the namespace which pods belong,\nand the each values is a set of pod names.\n+optional", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "v1alpha1.ProcessSpec": { + "type": "object", + "properties": { + "process": { + "description": "the process name or the process ID", + "type": "string" + }, + "recoverCmd": { + "description": "the command to be run when recovering experiment", + "type": "string" + }, + "signal": { + "description": "the signal number to send", + "type": "integer" + } + } + }, + "v1alpha1.RateSpec": { + "type": "object", + "properties": { + "rate": { + "description": "Rate is the speed knob. Allows bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means bytes per second.", + "type": "string" + } + } + }, + "v1alpha1.RedisCacheLimitSpec": { + "type": "object", + "properties": { + "addr": { + "description": "The adress of Redis server", + "type": "string" + }, + "cacheSize": { + "description": "The size of ` + "`" + `maxmemory` + "`" + `", + "type": "string" + }, + "password": { + "description": "The password of Redis server", + "type": "string" + }, + "percent": { + "description": "Specifies maxmemory as a percentage of the original value", + "type": "string" + } + } + }, + "v1alpha1.RedisExpirationSpec": { + "type": "object", + "properties": { + "addr": { + "description": "The adress of Redis server", + "type": "string" + }, + "expiration": { + "description": "The expiration of the keys", + "type": "string" + }, + "key": { + "description": "The keys to be expired", + "type": "string" + }, + "option": { + "description": "Additional options for ` + "`" + `expiration` + "`" + `", + "type": "string" + }, + "password": { + "description": "The password of Redis server", + "type": "string" + } + } + }, + "v1alpha1.RedisPenetrationSpec": { + "type": "object", + "properties": { + "addr": { + "description": "The adress of Redis server", + "type": "string" + }, + "password": { + "description": "The password of Redis server", + "type": "string" + }, + "requestNum": { + "description": "The number of requests to be sent", + "type": "integer" + } + } + }, + "v1alpha1.RedisSentinelRestartSpec": { + "type": "object", + "properties": { + "addr": { + "description": "The adress of Redis server", + "type": "string" + }, + "conf": { + "description": "The path of Sentinel conf", + "type": "string" + }, + "flushConfig": { + "description": "The control flag determines whether to flush config", + "type": "boolean" + }, + "password": { + "description": "The password of Redis server", + "type": "string" + }, + "redisPath": { + "description": "The path of ` + "`" + `redis-server` + "`" + ` command-line tool", + "type": "boolean" + } + } + }, + "v1alpha1.RedisSentinelStopSpec": { + "type": "object", + "properties": { + "addr": { + "description": "The adress of Redis server", + "type": "string" + }, + "conf": { + "description": "The path of Sentinel conf", + "type": "string" + }, + "flushConfig": { + "description": "The control flag determines whether to flush config", + "type": "boolean" + }, + "password": { + "description": "The password of Redis server", + "type": "string" + }, + "redisPath": { + "description": "The path of ` + "`" + `redis-server` + "`" + ` command-line tool", + "type": "boolean" + } + } + }, + "v1alpha1.ReorderSpec": { + "type": "object", + "properties": { + "correlation": { + "description": "+optional", + "type": "string", + "default": "0" + }, + "gap": { + "type": "integer" + }, + "reorder": { + "type": "string" + } + } + }, + "v1alpha1.Schedule": { + "type": "object", + "properties": { + "annotations": { + "description": "Annotations is an unstructured key value map stored with a resource that may be\nset by external tools to store and retrieve arbitrary metadata. They are not\nqueryable and should be preserved when modifying objects.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "creationTimestamp": { + "description": "CreationTimestamp is a timestamp representing the server time when this object was\ncreated. It is not guaranteed to be set in happens-before order across separate operations.\nClients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system.\nRead-only.\nNull for lists.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "type": "string" + }, + "deletionGracePeriodSeconds": { + "description": "Number of seconds allowed for this object to gracefully terminate before\nit will be removed from the system. Only set when deletionTimestamp is also set.\nMay only be shortened.\nRead-only.\n+optional", + "type": "integer" + }, + "deletionTimestamp": { + "description": "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This\nfield is set by the server when a graceful deletion is requested by the user, and is not\ndirectly settable by a client. The resource is expected to be deleted (no longer visible\nfrom resource lists, and not reachable by name) after the time in this field, once the\nfinalizers list is empty. As long as the finalizers list contains items, deletion is blocked.\nOnce the deletionTimestamp is set, this value may not be unset or be set further into the\nfuture, although it may be shortened or the resource may be deleted prior to this time.\nFor example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react\nby sending a graceful termination signal to the containers in the pod. After that 30 seconds,\nthe Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,\nremove the pod from the API. In the presence of network partitions, this object may still\nexist after this timestamp, until an administrator or automated process can determine the\nresource is fully terminated.\nIf not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested.\nRead-only.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "type": "string" + }, + "finalizers": { + "description": "Must be empty before the object is deleted from the registry. Each entry\nis an identifier for the responsible component that will remove the entry\nfrom the list. If the deletionTimestamp of the object is non-nil, entries\nin this list can only be removed.\nFinalizers may be processed and removed in any order. Order is NOT enforced\nbecause it introduces significant risk of stuck finalizers.\nfinalizers is a shared field, any actor with permission can reorder it.\nIf the finalizer list is processed in order, then this can lead to a situation\nin which the component responsible for the first finalizer in the list is\nwaiting for a signal (field value, external system, or other) produced by a\ncomponent responsible for a finalizer later in the list, resulting in a deadlock.\nWithout enforced ordering finalizers are free to order amongst themselves and\nare not vulnerable to ordering changes in the list.\n+optional\n+patchStrategy=merge", + "type": "array", + "items": { + "type": "string" + } + }, + "generateName": { + "description": "GenerateName is an optional prefix, used by the server, to generate a unique\nname ONLY IF the Name field has not been provided.\nIf this field is used, the name returned to the client will be different\nthan the name passed. This value will also be combined with a unique suffix.\nThe provided value has the same validation rules as the Name field,\nand may be truncated by the length of the suffix required to make the value\nunique on the server.\n\nIf this field is specified and the generated name exists, the server will return a 409.\n\nApplied only if Name is not specified.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency\n+optional", + "type": "string" + }, + "generation": { + "description": "A sequence number representing a specific generation of the desired state.\nPopulated by the system. Read-only.\n+optional", + "type": "integer" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "labels": { + "description": "Map of string keys and values that can be used to organize and categorize\n(scope and select) objects. May match selectors of replication controllers\nand services.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "managedFields": { + "description": "ManagedFields maps workflow-id and version to the set of fields\nthat are managed by that workflow. This is mostly for internal\nhousekeeping, and users typically shouldn't need to set or\nunderstand this field. A workflow can be the user's name, a\ncontroller's name, or the name of a specific apply path like\n\"ci-cd\". The set of fields is always in the version that the\nworkflow used when modifying the object.\n\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ManagedFieldsEntry" + } + }, + "name": { + "description": "Name must be unique within a namespace. Is required when creating resources, although\nsome resources may allow a client to request the generation of an appropriate name\nautomatically. Name is primarily intended for creation idempotence and configuration\ndefinition.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names\n+optional", + "type": "string" + }, + "namespace": { + "description": "Namespace defines the space within which each name must be unique. An empty namespace is\nequivalent to the \"default\" namespace, but \"default\" is the canonical representation.\nNot all objects are required to be scoped to a namespace - the value of this field for\nthose objects will be empty.\n\nMust be a DNS_LABEL.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces\n+optional", + "type": "string" + }, + "ownerReferences": { + "description": "List of objects depended by this object. If ALL objects in the list have\nbeen deleted, this object will be garbage collected. If this object is managed by a controller,\nthen an entry in this list will point to this controller, with the controller field set to true.\nThere cannot be more than one managing controller.\n+optional\n+patchMergeKey=uid\n+patchStrategy=merge", + "type": "array", + "items": { + "$ref": "#/definitions/v1.OwnerReference" + } + }, + "resourceVersion": { + "description": "An opaque value that represents the internal version of this object that can\nbe used by clients to determine when objects have changed. May be used for optimistic\nconcurrency, change detection, and the watch operation on a resource or set of resources.\nClients must treat these values as opaque and passed unmodified back to the server.\nThey may only be valid for a particular resource or set of resources.\n\nPopulated by the system.\nRead-only.\nValue must be treated as opaque by clients and .\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency\n+optional", + "type": "string" + }, + "selfLink": { + "description": "Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.\n+optional", + "type": "string" + }, + "spec": { + "$ref": "#/definitions/v1alpha1.ScheduleSpec" + }, + "status": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.ScheduleStatus" + }, + "uid": { + "description": "UID is the unique in time and space value for this object. It is typically generated by\nthe server on successful creation of a resource and is not allowed to change on PUT\noperations.\n\nPopulated by the system.\nRead-only.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids\n+optional", + "type": "string" + } + } + }, + "v1alpha1.ScheduleSpec": { + "type": "object", + "properties": { + "awsChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.AWSChaosSpec" + }, + "azureChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.AzureChaosSpec" + }, + "blockChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.BlockChaosSpec" + }, + "concurrencyPolicy": { + "description": "+optional\n+kubebuilder:default=Forbid\n+kubebuilder:validation:Enum=Forbid;Allow", + "type": "string" + }, + "dnsChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.DNSChaosSpec" + }, + "gcpChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.GCPChaosSpec" + }, + "historyLimit": { + "description": "+optional\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "httpChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.HTTPChaosSpec" + }, + "ioChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.IOChaosSpec" + }, + "jvmChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.JVMChaosSpec" + }, + "kernelChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.KernelChaosSpec" + }, + "networkChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.NetworkChaosSpec" + }, + "physicalmachineChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.PhysicalMachineChaosSpec" + }, + "podChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.PodChaosSpec" + }, + "schedule": { + "type": "string" + }, + "startingDeadlineSeconds": { + "description": "+optional\n+nullable\n+kubebuilder:validation:Minimum=0\n+kubebuilder:validation:ExclusiveMinimum=true", + "type": "integer" + }, + "stressChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.StressChaosSpec" + }, + "timeChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.TimeChaosSpec" + }, + "type": { + "type": "string" + }, + "workflow": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.WorkflowSpec" + } + } + }, + "v1alpha1.ScheduleStatus": { + "type": "object", + "properties": { + "active": { + "description": "+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ObjectReference" + } + }, + "time": { + "description": "+optional\n+nullable", + "type": "string" + } + } + }, + "v1alpha1.StatusCheckSpec": { + "type": "object", + "properties": { + "duration": { + "description": "Duration defines the duration of the whole status check if the\nnumber of failed execution does not exceed the failure threshold.\nDuration is available to both ` + "`" + `Synchronous` + "`" + ` and ` + "`" + `Continuous` + "`" + ` mode.\nA duration string is a possibly signed sequence of\ndecimal numbers, each with optional fraction and a unit suffix,\nsuch as \"300ms\", \"-1.5h\" or \"2h45m\".\nValid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\n+optional", + "type": "string" + }, + "failureThreshold": { + "description": "FailureThreshold defines the minimum consecutive failure\nfor the status check to be considered failed.\n+optional\n+kubebuilder:default=3\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "http": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.HTTPStatusCheck" + }, + "intervalSeconds": { + "description": "IntervalSeconds defines how often (in seconds) to perform\nan execution of status check.\n+optional\n+kubebuilder:default=10\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "mode": { + "description": "Mode defines the execution mode of the status check.\nSupport type: Synchronous / Continuous\n+optional\n+kubebuilder:validation:Enum=Synchronous;Continuous", + "type": "string" + }, + "recordsHistoryLimit": { + "description": "RecordsHistoryLimit defines the number of record to retain.\n+optional\n+kubebuilder:default=100\n+kubebuilder:validation:Minimum=1\n+kubebuilder:validation:Maximum=1000", + "type": "integer" + }, + "successThreshold": { + "description": "SuccessThreshold defines the minimum consecutive successes\nfor the status check to be considered successful.\nSuccessThreshold only works for ` + "`" + `Synchronous` + "`" + ` mode.\n+optional\n+kubebuilder:default=1\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "timeoutSeconds": { + "description": "TimeoutSeconds defines the number of seconds after which\nan execution of status check times out.\n+optional\n+kubebuilder:default=1\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "type": { + "description": "Type defines the specific status check type.\nSupport type: HTTP\n+kubebuilder:default=HTTP\n+kubebuilder:validation:Enum=HTTP", + "type": "string" + } + } + }, + "v1alpha1.StatusCheckTemplate": { + "type": "object", + "properties": { + "duration": { + "description": "Duration defines the duration of the whole status check if the\nnumber of failed execution does not exceed the failure threshold.\nDuration is available to both ` + "`" + `Synchronous` + "`" + ` and ` + "`" + `Continuous` + "`" + ` mode.\nA duration string is a possibly signed sequence of\ndecimal numbers, each with optional fraction and a unit suffix,\nsuch as \"300ms\", \"-1.5h\" or \"2h45m\".\nValid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\n+optional", + "type": "string" + }, + "failureThreshold": { + "description": "FailureThreshold defines the minimum consecutive failure\nfor the status check to be considered failed.\n+optional\n+kubebuilder:default=3\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "http": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.HTTPStatusCheck" + }, + "intervalSeconds": { + "description": "IntervalSeconds defines how often (in seconds) to perform\nan execution of status check.\n+optional\n+kubebuilder:default=10\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "mode": { + "description": "Mode defines the execution mode of the status check.\nSupport type: Synchronous / Continuous\n+optional\n+kubebuilder:validation:Enum=Synchronous;Continuous", + "type": "string" + }, + "recordsHistoryLimit": { + "description": "RecordsHistoryLimit defines the number of record to retain.\n+optional\n+kubebuilder:default=100\n+kubebuilder:validation:Minimum=1\n+kubebuilder:validation:Maximum=1000", + "type": "integer" + }, + "successThreshold": { + "description": "SuccessThreshold defines the minimum consecutive successes\nfor the status check to be considered successful.\nSuccessThreshold only works for ` + "`" + `Synchronous` + "`" + ` mode.\n+optional\n+kubebuilder:default=1\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "timeoutSeconds": { + "description": "TimeoutSeconds defines the number of seconds after which\nan execution of status check times out.\n+optional\n+kubebuilder:default=1\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "type": { + "description": "Type defines the specific status check type.\nSupport type: HTTP\n+kubebuilder:default=HTTP\n+kubebuilder:validation:Enum=HTTP", + "type": "string" + } + } + }, + "v1alpha1.StressCPUSpec": { + "type": "object", + "properties": { + "load": { + "description": "specifies P percent loading per CPU worker. 0 is effectively a sleep (no load) and 100 is full loading.", + "type": "integer" + }, + "options": { + "description": "extend stress-ng options", + "type": "array", + "items": { + "type": "string" + } + }, + "workers": { + "description": "specifies N workers to apply the stressor.", + "type": "integer" + } + } + }, + "v1alpha1.StressChaosSpec": { + "type": "object", + "properties": { + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "duration": { + "description": "Duration represents the duration of the chaos action\n+optional", + "type": "string" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "stressngStressors": { + "description": "StressngStressors defines plenty of stressors just like ` + "`" + `Stressors` + "`" + ` except that it's an experimental\nfeature and more powerful. You can define stressors in ` + "`" + `stress-ng` + "`" + ` (see also ` + "`" + `man stress-ng` + "`" + `) dialect,\nhowever not all of the supported stressors are well tested. It maybe retired in later releases. You\nshould always use ` + "`" + `Stressors` + "`" + ` to define the stressors and use this only when you want more stressors\nunsupported by ` + "`" + `Stressors` + "`" + `. When both ` + "`" + `StressngStressors` + "`" + ` and ` + "`" + `Stressors` + "`" + ` are defined, ` + "`" + `StressngStressors` + "`" + `\nwins.\n+optional", + "type": "string" + }, + "stressors": { + "description": "Stressors defines plenty of stressors supported to stress system components out.\nYou can use one or more of them to make up various kinds of stresses. At least\none of the stressors should be specified.\n+optional", + "$ref": "#/definitions/v1alpha1.Stressors" + }, + "value": { + "description": "Value is required when the mode is set to ` + "`" + `FixedMode` + "`" + ` / ` + "`" + `FixedPercentMode` + "`" + ` / ` + "`" + `RandomMaxPercentMode` + "`" + `.\nIf ` + "`" + `FixedMode` + "`" + `, provide an integer of pods to do chaos action.\nIf ` + "`" + `FixedPercentMode` + "`" + `, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF ` + "`" + `RandomMaxPercentMode` + "`" + `, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.StressMemorySpec": { + "type": "object", + "properties": { + "options": { + "description": "extend stress-ng options", + "type": "array", + "items": { + "type": "string" + } + }, + "size": { + "description": "specifies N bytes consumed per vm worker, default is the total available memory.\nOne can specify the size as % of total available memory or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB..", + "type": "string" + } + } + }, + "v1alpha1.Stressors": { + "type": "object", + "properties": { + "cpu": { + "description": "CPUStressor stresses CPU out\n+optional", + "$ref": "#/definitions/v1alpha1.CPUStressor" + }, + "memory": { + "description": "MemoryStressor stresses virtual memory out\n+optional", + "$ref": "#/definitions/v1alpha1.MemoryStressor" + } + } + }, + "v1alpha1.Task": { + "type": "object", + "properties": { + "container": { + "description": "Container is the main container image to run in the pod", + "$ref": "#/definitions/v1.Container" + }, + "volumes": { + "description": "Volumes is a list of volumes that can be mounted by containers in a template.\n+patchStrategy=merge\n+patchMergeKey=name", + "type": "array", + "items": { + "$ref": "#/definitions/v1.Volume" + } + } + } + }, + "v1alpha1.Template": { + "type": "object", + "properties": { + "abortWithStatusCheck": { + "description": "AbortWithStatusCheck describe whether to abort the workflow when the failure threshold of StatusCheck is exceeded.\nOnly used when Type is TypeStatusCheck.\n+optional", + "type": "boolean" + }, + "awsChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.AWSChaosSpec" + }, + "azureChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.AzureChaosSpec" + }, + "blockChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.BlockChaosSpec" + }, + "children": { + "description": "Children describes the children steps of serial or parallel node. Only used when Type is TypeSerial or TypeParallel.\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "conditionalBranches": { + "description": "ConditionalBranches describes the conditional branches of custom tasks. Only used when Type is TypeTask.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1alpha1.ConditionalBranch" + } + }, + "deadline": { + "description": "+optional", + "type": "string" + }, + "dnsChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.DNSChaosSpec" + }, + "gcpChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.GCPChaosSpec" + }, + "httpChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.HTTPChaosSpec" + }, + "ioChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.IOChaosSpec" + }, + "jvmChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.JVMChaosSpec" + }, + "kernelChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.KernelChaosSpec" + }, + "name": { + "type": "string" + }, + "networkChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.NetworkChaosSpec" + }, + "physicalmachineChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.PhysicalMachineChaosSpec" + }, + "podChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.PodChaosSpec" + }, + "schedule": { + "description": "Schedule describe the Schedule(describing scheduled chaos) to be injected with chaos nodes. Only used when Type is TypeSchedule.\n+optional", + "$ref": "#/definitions/v1alpha1.ChaosOnlyScheduleSpec" + }, + "statusCheck": { + "description": "StatusCheck describe the behavior of StatusCheck. Only used when Type is TypeStatusCheck.\n+optional", + "$ref": "#/definitions/v1alpha1.StatusCheckSpec" + }, + "stressChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.StressChaosSpec" + }, + "task": { + "description": "Task describes the behavior of the custom task. Only used when Type is TypeTask.\n+optional", + "$ref": "#/definitions/v1alpha1.Task" + }, + "templateType": { + "type": "string" + }, + "timeChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.TimeChaosSpec" + } + } + }, + "v1alpha1.TimeChaosSpec": { + "type": "object", + "properties": { + "clockIds": { + "description": "ClockIds defines all affected clock id\nAll available options are [\"CLOCK_REALTIME\",\"CLOCK_MONOTONIC\",\"CLOCK_PROCESS_CPUTIME_ID\",\"CLOCK_THREAD_CPUTIME_ID\",\n\"CLOCK_MONOTONIC_RAW\",\"CLOCK_REALTIME_COARSE\",\"CLOCK_MONOTONIC_COARSE\",\"CLOCK_BOOTTIME\",\"CLOCK_REALTIME_ALARM\",\n\"CLOCK_BOOTTIME_ALARM\"]\nDefault value is [\"CLOCK_REALTIME\"]", + "type": "array", + "items": { + "type": "string" + } + }, + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "duration": { + "description": "Duration represents the duration of the chaos action", + "type": "string" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "timeOffset": { + "description": "TimeOffset defines the delta time of injected program. It's a possibly signed sequence of decimal numbers, such as\n\"300ms\", \"-1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".", + "type": "string" + }, + "value": { + "description": "Value is required when the mode is set to ` + "`" + `FixedMode` + "`" + ` / ` + "`" + `FixedPercentMode` + "`" + ` / ` + "`" + `RandomMaxPercentMode` + "`" + `.\nIf ` + "`" + `FixedMode` + "`" + `, provide an integer of pods to do chaos action.\nIf ` + "`" + `FixedPercentMode` + "`" + `, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF ` + "`" + `RandomMaxPercentMode` + "`" + `, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.Timespec": { + "type": "object", + "properties": { + "nsec": { + "type": "integer" + }, + "sec": { + "type": "integer" + } + } + }, + "v1alpha1.UserDefinedSpec": { + "type": "object", + "properties": { + "attackCmd": { + "description": "The command to be executed when attack", + "type": "string" + }, + "recoverCmd": { + "description": "The command to be executed when recover", + "type": "string" + } + } + }, + "v1alpha1.VMSpec": { + "type": "object", + "properties": { + "vm-name": { + "description": "The name of the VM to be injected", + "type": "string" + } + } + }, + "v1alpha1.Workflow": { + "type": "object", + "properties": { + "annotations": { + "description": "Annotations is an unstructured key value map stored with a resource that may be\nset by external tools to store and retrieve arbitrary metadata. They are not\nqueryable and should be preserved when modifying objects.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "creationTimestamp": { + "description": "CreationTimestamp is a timestamp representing the server time when this object was\ncreated. It is not guaranteed to be set in happens-before order across separate operations.\nClients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system.\nRead-only.\nNull for lists.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "type": "string" + }, + "deletionGracePeriodSeconds": { + "description": "Number of seconds allowed for this object to gracefully terminate before\nit will be removed from the system. Only set when deletionTimestamp is also set.\nMay only be shortened.\nRead-only.\n+optional", + "type": "integer" + }, + "deletionTimestamp": { + "description": "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This\nfield is set by the server when a graceful deletion is requested by the user, and is not\ndirectly settable by a client. The resource is expected to be deleted (no longer visible\nfrom resource lists, and not reachable by name) after the time in this field, once the\nfinalizers list is empty. As long as the finalizers list contains items, deletion is blocked.\nOnce the deletionTimestamp is set, this value may not be unset or be set further into the\nfuture, although it may be shortened or the resource may be deleted prior to this time.\nFor example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react\nby sending a graceful termination signal to the containers in the pod. After that 30 seconds,\nthe Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,\nremove the pod from the API. In the presence of network partitions, this object may still\nexist after this timestamp, until an administrator or automated process can determine the\nresource is fully terminated.\nIf not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested.\nRead-only.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "type": "string" + }, + "finalizers": { + "description": "Must be empty before the object is deleted from the registry. Each entry\nis an identifier for the responsible component that will remove the entry\nfrom the list. If the deletionTimestamp of the object is non-nil, entries\nin this list can only be removed.\nFinalizers may be processed and removed in any order. Order is NOT enforced\nbecause it introduces significant risk of stuck finalizers.\nfinalizers is a shared field, any actor with permission can reorder it.\nIf the finalizer list is processed in order, then this can lead to a situation\nin which the component responsible for the first finalizer in the list is\nwaiting for a signal (field value, external system, or other) produced by a\ncomponent responsible for a finalizer later in the list, resulting in a deadlock.\nWithout enforced ordering finalizers are free to order amongst themselves and\nare not vulnerable to ordering changes in the list.\n+optional\n+patchStrategy=merge", + "type": "array", + "items": { + "type": "string" + } + }, + "generateName": { + "description": "GenerateName is an optional prefix, used by the server, to generate a unique\nname ONLY IF the Name field has not been provided.\nIf this field is used, the name returned to the client will be different\nthan the name passed. This value will also be combined with a unique suffix.\nThe provided value has the same validation rules as the Name field,\nand may be truncated by the length of the suffix required to make the value\nunique on the server.\n\nIf this field is specified and the generated name exists, the server will return a 409.\n\nApplied only if Name is not specified.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency\n+optional", + "type": "string" + }, + "generation": { + "description": "A sequence number representing a specific generation of the desired state.\nPopulated by the system. Read-only.\n+optional", + "type": "integer" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "labels": { + "description": "Map of string keys and values that can be used to organize and categorize\n(scope and select) objects. May match selectors of replication controllers\nand services.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "managedFields": { + "description": "ManagedFields maps workflow-id and version to the set of fields\nthat are managed by that workflow. This is mostly for internal\nhousekeeping, and users typically shouldn't need to set or\nunderstand this field. A workflow can be the user's name, a\ncontroller's name, or the name of a specific apply path like\n\"ci-cd\". The set of fields is always in the version that the\nworkflow used when modifying the object.\n\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ManagedFieldsEntry" + } + }, + "name": { + "description": "Name must be unique within a namespace. Is required when creating resources, although\nsome resources may allow a client to request the generation of an appropriate name\nautomatically. Name is primarily intended for creation idempotence and configuration\ndefinition.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names\n+optional", + "type": "string" + }, + "namespace": { + "description": "Namespace defines the space within which each name must be unique. An empty namespace is\nequivalent to the \"default\" namespace, but \"default\" is the canonical representation.\nNot all objects are required to be scoped to a namespace - the value of this field for\nthose objects will be empty.\n\nMust be a DNS_LABEL.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces\n+optional", + "type": "string" + }, + "ownerReferences": { + "description": "List of objects depended by this object. If ALL objects in the list have\nbeen deleted, this object will be garbage collected. If this object is managed by a controller,\nthen an entry in this list will point to this controller, with the controller field set to true.\nThere cannot be more than one managing controller.\n+optional\n+patchMergeKey=uid\n+patchStrategy=merge", + "type": "array", + "items": { + "$ref": "#/definitions/v1.OwnerReference" + } + }, + "resourceVersion": { + "description": "An opaque value that represents the internal version of this object that can\nbe used by clients to determine when objects have changed. May be used for optimistic\nconcurrency, change detection, and the watch operation on a resource or set of resources.\nClients must treat these values as opaque and passed unmodified back to the server.\nThey may only be valid for a particular resource or set of resources.\n\nPopulated by the system.\nRead-only.\nValue must be treated as opaque by clients and .\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency\n+optional", + "type": "string" + }, + "selfLink": { + "description": "Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.\n+optional", + "type": "string" + }, + "spec": { + "description": "Spec defines the behavior of a workflow", + "$ref": "#/definitions/v1alpha1.WorkflowSpec" + }, + "status": { + "description": "+optional\nMost recently observed status of the workflow", + "$ref": "#/definitions/v1alpha1.WorkflowStatus" + }, + "uid": { + "description": "UID is the unique in time and space value for this object. It is typically generated by\nthe server on successful creation of a resource and is not allowed to change on PUT\noperations.\n\nPopulated by the system.\nRead-only.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids\n+optional", + "type": "string" + } + } + }, + "v1alpha1.WorkflowCondition": { + "type": "object", + "properties": { + "reason": { + "type": "string" + }, + "startTime": { + "type": "string" + }, + "status": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "v1alpha1.WorkflowSpec": { + "type": "object", + "properties": { + "entry": { + "type": "string" + }, + "templates": { + "type": "array", + "items": { + "$ref": "#/definitions/v1alpha1.Template" + } + } + } + }, + "v1alpha1.WorkflowStatus": { + "type": "object", + "properties": { + "conditions": { + "description": "Represents the latest available observations of a workflow's current state.\n+optional\n+patchMergeKey=type\n+patchStrategy=merge", + "type": "array", + "items": { + "$ref": "#/definitions/v1alpha1.WorkflowCondition" + } + }, + "endTime": { + "description": "+optional", + "type": "string" + }, + "entryNode": { + "description": "+optional", + "type": "string" + }, + "startTime": { + "description": "+optional", + "type": "string" + } + } + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "2.5", + Host: "", + BasePath: "/api", + Schemes: []string{}, + Title: "Chaos Mesh Dashboard API", + Description: "Swagger for Chaos Mesh Dashboard. If you encounter any problems with API, please click on the issues link below to report.", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/pkg/dashboard/swaggerdocs/placeholder.go b/pkg/dashboard/swaggerdocs/placeholder.go new file mode 100644 index 0000000000..24bb98d823 --- /dev/null +++ b/pkg/dashboard/swaggerdocs/placeholder.go @@ -0,0 +1,21 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/* +Package swaggerdocs places swagger docs. + +This file ensures that the `swaggerdocs` package still exists when `swagger` is not enabled. +*/ +package swaggerdocs diff --git a/pkg/dashboard/swaggerdocs/swagger.json b/pkg/dashboard/swaggerdocs/swagger.json new file mode 100644 index 0000000000..da96acd5f7 --- /dev/null +++ b/pkg/dashboard/swaggerdocs/swagger.json @@ -0,0 +1,7935 @@ +{ + "swagger": "2.0", + "info": { + "description": "Swagger for Chaos Mesh Dashboard. If you encounter any problems with API, please click on the issues link below to report.", + "title": "Chaos Mesh Dashboard API", + "contact": { + "name": "GitHub Issues", + "url": "https://github.com/chaos-mesh/chaos-mesh/issues" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "2.5" + }, + "basePath": "/api", + "paths": { + "/archives": { + "get": { + "description": "Get archived chaos experiments.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Get archived chaos experiments.", + "parameters": [ + { + "type": "string", + "description": "namespace", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "name", + "name": "name", + "in": "query" + }, + { + "enum": [ + "PodChaos", + "IOChaos", + "NetworkChaos", + "TimeChaos", + "KernelChaos", + "StressChaos" + ], + "type": "string", + "description": "kind", + "name": "kind", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.Archive" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the specified archived experiment.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Delete the specified archived experiment.", + "parameters": [ + { + "type": "string", + "description": "uids", + "name": "uids", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/archives/schedules": { + "get": { + "description": "Get archived schedule experiments.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Get archived schedule experiments.", + "parameters": [ + { + "type": "string", + "description": "namespace", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "name", + "name": "name", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.Archive" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the specified archived schedule.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Delete the specified archived schedule.", + "parameters": [ + { + "type": "string", + "description": "uids", + "name": "uids", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/archives/schedules/{uid}": { + "get": { + "description": "Get the detail of an archived schedule experiment.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Get the detail of an archived schedule experiment.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ArchiveDetail" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the specified archived schedule.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Delete the specified archived schedule.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/archives/workflows": { + "get": { + "description": "Get archived workflow.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Get archived workflow.", + "parameters": [ + { + "type": "string", + "description": "namespace", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "name", + "name": "name", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.Archive" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the specified archived workflows.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Delete the specified archived workflows.", + "parameters": [ + { + "type": "string", + "description": "uids", + "name": "uids", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/archives/workflows/{uid}": { + "get": { + "description": "Get the detail of an archived workflow.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Get the detail of an archived workflow.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ArchiveDetail" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the specified archived workflow.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Delete the specified archived workflow.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/archives/{uid}": { + "get": { + "description": "Get the archived chaos experiment's detail by uid.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Get an archived chaos experiment.", + "parameters": [ + { + "type": "string", + "description": "the archive uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ArchiveDetail" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the specified archived experiment.", + "produces": [ + "application/json" + ], + "tags": [ + "archives" + ], + "summary": "Delete the specified archived experiment.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/annotations": { + "get": { + "description": "Get the annotations of the pods in the specified namespace from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get the annotations of the pods in the specified namespace from Kubernetes cluster.", + "parameters": [ + { + "type": "string", + "description": "The pod's namespace list, split by ,", + "name": "podNamespaceList", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.MapStringSliceResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/chaos-available-namespaces": { + "get": { + "description": "Get all namespaces which could inject chaos(explosion scope) from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get all namespaces which could inject chaos(explosion scope) from Kubernetes cluster.", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/config": { + "get": { + "description": "Get the config of Dashboard.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get the config of Dashboard.", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/config.ChaosDashboardConfig" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/kinds": { + "get": { + "description": "Get all chaos kinds from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get all chaos kinds from Kubernetes cluster.", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/labels": { + "get": { + "description": "Get the labels of the pods in the specified namespace from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get the labels of the pods in the specified namespace from Kubernetes cluster.", + "parameters": [ + { + "type": "string", + "description": "The pod's namespace list, split by ,", + "name": "podNamespaceList", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.MapStringSliceResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/namespaces": { + "get": { + "description": "Get all from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get all namespaces from Kubernetes cluster.", + "deprecated": true, + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/physicalmachine-annotations": { + "get": { + "description": "Get the annotations of the physicalMachines in the specified namespace from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get the annotations of the physicalMachines in the specified namespace from Kubernetes cluster.", + "parameters": [ + { + "type": "string", + "description": "The physicalMachine's namespace list, split by ,", + "name": "physicalMachineNamespaceList", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.MapStringSliceResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/physicalmachine-labels": { + "get": { + "description": "Get the labels of the physicalMachines in the specified namespace from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get the labels of the physicalMachines in the specified namespace from Kubernetes cluster.", + "parameters": [ + { + "type": "string", + "description": "The physicalMachine's namespace list, split by ,", + "name": "physicalMachineNamespaceList", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.MapStringSliceResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/physicalmachines": { + "post": { + "description": "Get physicalMachines from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get physicalMachines from Kubernetes cluster.", + "parameters": [ + { + "description": "Request body", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1.PhysicalMachineSelectorSpec" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.PhysicalMachine" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/pods": { + "post": { + "description": "Get pods from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get pods from Kubernetes cluster.", + "parameters": [ + { + "description": "Request body", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.Pod" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/common/rbac-config": { + "get": { + "description": "Get the rbac config according to the user's choice.", + "produces": [ + "application/json" + ], + "tags": [ + "common" + ], + "summary": "Get the rbac config according to the user's choice.", + "parameters": [ + { + "type": "string", + "description": "The namespace of RBAC", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "The role of RBAC", + "name": "role", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/events": { + "get": { + "description": "Get events from db.", + "produces": [ + "application/json" + ], + "tags": [ + "events" + ], + "summary": "list events.", + "parameters": [ + { + "type": "string", + "description": "The create time of events", + "name": "created_at", + "in": "query" + }, + { + "type": "string", + "description": "The name of the object", + "name": "name", + "in": "query" + }, + { + "type": "string", + "description": "The namespace of the object", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "The UID of the object", + "name": "object_id", + "in": "query" + }, + { + "enum": [ + "PodChaos", + "IOChaos", + "NetworkChaos", + "TimeChaos", + "KernelChaos", + "StressChaos", + "AWSChaos", + "GCPChaos", + "DNSChaos", + "Schedule" + ], + "type": "string", + "description": "kind", + "name": "kind", + "in": "query" + }, + { + "type": "number", + "description": "The max length of events list", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/core.Event" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/events/workflow/{uid}": { + "get": { + "description": "list all events for Workflow and related WorkflowNode.", + "produces": [ + "application/json" + ], + "tags": [ + "events" + ], + "summary": "cascadeFetchEventsForWorkflow list all events for Workflow and related WorkflowNode.", + "parameters": [ + { + "type": "string", + "description": "The UID of the Workflow", + "name": "uid", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "The namespace of the object", + "name": "namespace", + "in": "query" + }, + { + "type": "number", + "description": "The max length of events list", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/core.Event" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/events/{id}": { + "get": { + "description": "Get the event from db by ID.", + "produces": [ + "application/json" + ], + "tags": [ + "events" + ], + "summary": "Get an event.", + "parameters": [ + { + "type": "integer", + "description": "The event ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/core.Event" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/experiments": { + "get": { + "description": "Get chaos experiments from k8s clusters in real time.", + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "List chaos experiments.", + "parameters": [ + { + "type": "string", + "description": "filter exps by namespace", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "filter exps by name", + "name": "name", + "in": "query" + }, + { + "enum": [ + "PodChaos", + "NetworkChaos", + "IOChaos", + "StressChaos", + "KernelChaos", + "TimeChaos", + "DNSChaos", + "AWSChaos", + "GCPChaos", + "JVMChaos", + "HTTPChaos" + ], + "type": "string", + "description": "filter exps by kind", + "name": "kind", + "in": "query" + }, + { + "enum": [ + "Injecting", + "Running", + "Finished", + "Paused" + ], + "type": "string", + "description": "filter exps by status", + "name": "status", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.Experiment" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "post": { + "description": "Pass a JSON object to create a new chaos experiment. The schema for JSON is the same as the YAML schema for the Kubernetes object.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "Create a new chaos experiment.", + "parameters": [ + { + "description": "the chaos definition", + "name": "chaos", + "in": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Batch delete chaos experiments by uids.", + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "Batch delete chaos experiments.", + "parameters": [ + { + "type": "string", + "description": "the experiment uids, split with comma. Example: ?uids=uid1,uid2", + "name": "uids", + "in": "query", + "required": true + }, + { + "enum": [ + "true", + "false" + ], + "type": "string", + "description": "force", + "name": "force", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/experiments/pause/{uid}": { + "put": { + "description": "Pause a chaos experiment.", + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "Pause a chaos experiment.", + "parameters": [ + { + "type": "string", + "description": "the experiment uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/experiments/start/{uid}": { + "put": { + "description": "Start a chaos experiment.", + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "Start a chaos experiment.", + "parameters": [ + { + "type": "string", + "description": "the experiment uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/experiments/state": { + "get": { + "description": "Get the status of all experiments.", + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "Get the status of all experiments.", + "parameters": [ + { + "type": "string", + "description": "namespace", + "name": "namespace", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/status.AllChaosStatus" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/experiments/{uid}": { + "get": { + "description": "Get the chaos experiment's detail by uid.", + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "Get a chaos experiment.", + "parameters": [ + { + "type": "string", + "description": "the experiment uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ExperimentDetail" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the chaos experiment by uid.", + "produces": [ + "application/json" + ], + "tags": [ + "experiments" + ], + "summary": "Delete a chaos experiment.", + "parameters": [ + { + "type": "string", + "description": "the experiment uid", + "name": "uid", + "in": "path", + "required": true + }, + { + "enum": [ + "true", + "false" + ], + "type": "string", + "description": "force", + "name": "force", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/schedules": { + "get": { + "description": "Get chaos schedules from k8s cluster in real time.", + "produces": [ + "application/json" + ], + "tags": [ + "schedules" + ], + "summary": "List chaos schedules.", + "parameters": [ + { + "type": "string", + "description": "filter schedules by namespace", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "filter schedules by name", + "name": "name", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.Schedule" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "post": { + "description": "Pass a JSON object to create a new schedule. The schema for JSON is the same as the YAML schema for the Kubernetes object.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "schedules" + ], + "summary": "Create a new schedule.", + "parameters": [ + { + "description": "the schedule definition", + "name": "schedule", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1.Schedule" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1alpha1.Schedule" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Batch delete schedules by uids.", + "produces": [ + "application/json" + ], + "tags": [ + "schedules" + ], + "summary": "Batch delete schedules.", + "parameters": [ + { + "type": "string", + "description": "the schedule uids, split with comma. Example: ?uids=uid1,uid2", + "name": "uids", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/schedules/pause/{uid}": { + "put": { + "description": "Pause a schedule.", + "produces": [ + "application/json" + ], + "tags": [ + "schedules" + ], + "summary": "Pause a schedule.", + "parameters": [ + { + "type": "string", + "description": "the schedule uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/schedules/start/{uid}": { + "put": { + "description": "Start a schedule.", + "produces": [ + "application/json" + ], + "tags": [ + "schedules" + ], + "summary": "Start a schedule.", + "parameters": [ + { + "type": "string", + "description": "the schedule uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/schedules/{uid}": { + "get": { + "description": "Get the schedule's detail by uid.", + "produces": [ + "application/json" + ], + "tags": [ + "schedules" + ], + "summary": "Get a schedule.", + "parameters": [ + { + "type": "string", + "description": "the schedule uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ScheduleDetail" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the schedule by uid.", + "produces": [ + "application/json" + ], + "tags": [ + "schedules" + ], + "summary": "Delete a schedule.", + "parameters": [ + { + "type": "string", + "description": "the schedule uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/templates/statuschecks": { + "get": { + "description": "Get status check templates from k8s cluster in real time.", + "produces": [ + "application/json" + ], + "tags": [ + "template" + ], + "summary": "List status check templates.", + "parameters": [ + { + "type": "string", + "description": "filter status check templates by namespace", + "name": "namespace", + "in": "query" + }, + { + "type": "string", + "description": "filter status check templates by name", + "name": "name", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.StatusCheckTemplateBase" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "post": { + "description": "Pass a JSON object to create a new status check template.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "templates" + ], + "summary": "Create a new status check template.", + "parameters": [ + { + "description": "the status check definition", + "name": "statuscheck", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.StatusCheckTemplate" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.StatusCheckTemplate" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/templates/statuschecks/statuscheck": { + "get": { + "description": "Get the status check template's detail by namespaced name.", + "produces": [ + "application/json" + ], + "tags": [ + "templates" + ], + "summary": "Get a status check template.", + "parameters": [ + { + "type": "string", + "description": "the namespace of status check templates", + "name": "namespace", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "the name of status check templates", + "name": "name", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.StatusCheckTemplateDetail" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "put": { + "description": "Update a status check template by namespaced name.", + "produces": [ + "application/json" + ], + "tags": [ + "templates" + ], + "summary": "Update a status check template.", + "parameters": [ + { + "description": "Request body", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.StatusCheckTemplate" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.StatusCheckTemplate" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the status check template by namespaced name.", + "produces": [ + "application/json" + ], + "tags": [ + "templates" + ], + "summary": "Delete a status check template.", + "parameters": [ + { + "type": "string", + "description": "the namespace of status check templates", + "name": "namespace", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "the name of status check templates", + "name": "name", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/workflows": { + "get": { + "description": "List workflows from Kubernetes cluster.", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "List workflows from Kubernetes cluster.", + "parameters": [ + { + "type": "string", + "description": "namespace, given empty string means list from all namespace", + "name": "namespace", + "in": "query" + }, + { + "enum": [ + "Initializing", + "Running", + "Errored", + "Finished" + ], + "type": "string", + "description": "status", + "name": "status", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/core.WorkflowMeta" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "post": { + "description": "Create a new workflow.", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "Create a new workflow.", + "parameters": [ + { + "description": "Request body", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1.Workflow" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/core.WorkflowDetail" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/workflows/parse-task/http": { + "post": { + "description": "Parse the rendered task back to the original request", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "Parse the rendered task back to the original request", + "parameters": [ + { + "description": "Rendered Task", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1.Template" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/curl.RequestForm" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/workflows/render-task/http": { + "post": { + "description": "Render a task which sends HTTP request", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "Render a task which sends HTTP request", + "parameters": [ + { + "description": "Origin HTTP Request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/curl.RequestForm" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1alpha1.Template" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/workflows/validate-task/http": { + "post": { + "description": "Validate the given template is a valid rendered HTTP Task", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "Validate the given template is a valid rendered HTTP Task", + "parameters": [ + { + "description": "Rendered Task", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1.Template" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "boolean" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + }, + "/workflows/{uid}": { + "get": { + "description": "Get detailed information about the specified workflow. If that object is not existed in kubernetes, it will only return ths persisted data in the database.", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "Get detailed information about the specified workflow.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/core.WorkflowDetail" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "put": { + "description": "Update a workflow.", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "Update a workflow.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + }, + { + "description": "Request body", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1.Workflow" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/core.WorkflowDetail" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + }, + "delete": { + "description": "Delete the specified workflow.", + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "Delete the specified workflow.", + "parameters": [ + { + "type": "string", + "description": "uid", + "name": "uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/utils.APIError" + } + } + } + } + } + }, + "definitions": { + "config.ChaosDashboardConfig": { + "type": "object", + "properties": { + "cluster_mode": { + "description": "ClusterScoped means control Chaos Object in cluster level(all namespace).", + "type": "boolean", + "default": true + }, + "dns_server_create": { + "description": "After v2.5, the DNS server is created by default.", + "type": "boolean", + "default": true + }, + "enableFilterNamespace": { + "description": "EnableFilterNamespace will filter namespace with annotation. Only the pods/containers in namespace\nannotated with `chaos-mesh.org/inject=enabled` will be injected.", + "type": "boolean", + "default": false + }, + "gcp_security_mode": { + "description": "GcpSecurityMode will use the gcloud authentication to login to GKE user", + "type": "boolean", + "default": false + }, + "listen_host": { + "type": "string", + "default": "0.0.0.0" + }, + "listen_port": { + "type": "integer", + "default": 2333 + }, + "root_path": { + "type": "string", + "default": "http://localhost:2333" + }, + "security_mode": { + "description": "SecurityMode will use the token login by the user if set to true", + "type": "boolean", + "default": true + }, + "target_namespace": { + "description": "TargetNamespace is the target namespace to injecting chaos.\nIt only works with ClusterScoped is false.", + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "core.ConditionalBranch": { + "type": "object", + "properties": { + "expression": { + "type": "string" + }, + "name": { + "type": "string" + }, + "template": { + "type": "string" + } + } + }, + "core.Event": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "kind": { + "type": "string" + }, + "message": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "object_id": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "core.KubeObjectDesc": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/core.KubeObjectMeta" + }, + "spec": {} + } + }, + "core.KubeObjectMeta": { + "type": "object", + "properties": { + "annotations": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + } + } + }, + "core.Node": { + "type": "object", + "properties": { + "conditional_branches": { + "type": "array", + "items": { + "$ref": "#/definitions/core.ConditionalBranch" + } + }, + "name": { + "type": "string" + }, + "parallel": { + "type": "array", + "items": { + "$ref": "#/definitions/core.NodeNameWithTemplate" + } + }, + "serial": { + "type": "array", + "items": { + "$ref": "#/definitions/core.NodeNameWithTemplate" + } + }, + "state": { + "type": "string" + }, + "template": { + "type": "string" + }, + "type": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "core.NodeNameWithTemplate": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "template": { + "type": "string" + } + } + }, + "core.Topology": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "$ref": "#/definitions/core.Node" + } + } + } + }, + "core.WorkflowDetail": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "end_time": { + "description": "EndTime represents the time when the workflow completed all steps.", + "type": "string" + }, + "entry": { + "description": "the entry node name", + "type": "string" + }, + "finish_time": { + "description": "FinishTime represents the time when the workflow was deleted from Kubernetes.", + "type": "string" + }, + "id": { + "type": "integer" + }, + "kube_object": { + "$ref": "#/definitions/core.KubeObjectDesc" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "status": { + "type": "string" + }, + "topology": { + "$ref": "#/definitions/core.Topology" + }, + "uid": { + "type": "string" + } + } + }, + "core.WorkflowMeta": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "end_time": { + "description": "EndTime represents the time when the workflow completed all steps.", + "type": "string" + }, + "entry": { + "description": "the entry node name", + "type": "string" + }, + "finish_time": { + "description": "FinishTime represents the time when the workflow was deleted from Kubernetes.", + "type": "string" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "status": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "curl.Header": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "curl.RequestForm": { + "type": "object", + "properties": { + "body": { + "type": "string" + }, + "followLocation": { + "type": "boolean" + }, + "header": { + "$ref": "#/definitions/curl.Header" + }, + "jsonContent": { + "type": "boolean" + }, + "method": { + "type": "string" + }, + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "http.Header": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "intstr.IntOrString": { + "type": "object", + "properties": { + "intVal": { + "type": "integer" + }, + "strVal": { + "type": "string" + }, + "type": { + "type": "integer" + } + } + }, + "resource.Quantity": { + "type": "object", + "properties": { + "Format": { + "type": "string" + } + } + }, + "status.AllChaosStatus": { + "type": "object", + "properties": { + "deleting": { + "type": "integer" + }, + "finished": { + "type": "integer" + }, + "injecting": { + "type": "integer" + }, + "paused": { + "type": "integer" + }, + "running": { + "type": "integer" + } + } + }, + "types.Archive": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "types.ArchiveDetail": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "kube_object": { + "$ref": "#/definitions/core.KubeObjectDesc" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "types.Experiment": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "failed_message": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "status": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "types.ExperimentDetail": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "failed_message": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "kube_object": { + "$ref": "#/definitions/core.KubeObjectDesc" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "status": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "types.PhysicalMachine": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + } + } + }, + "types.Pod": { + "type": "object", + "properties": { + "ip": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "state": { + "type": "string" + } + } + }, + "types.Schedule": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "status": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "types.ScheduleDetail": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "experiment_uids": { + "type": "array", + "items": { + "type": "string" + } + }, + "kind": { + "type": "string" + }, + "kube_object": { + "$ref": "#/definitions/core.KubeObjectDesc" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "status": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "types.StatusCheckTemplate": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "spec": { + "$ref": "#/definitions/v1alpha1.StatusCheckTemplate" + } + } + }, + "types.StatusCheckTemplateBase": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "uid": { + "type": "string" + } + } + }, + "types.StatusCheckTemplateDetail": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "spec": { + "$ref": "#/definitions/v1alpha1.StatusCheckTemplate" + }, + "uid": { + "type": "string" + } + } + }, + "utils.APIError": { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "full_text": { + "type": "string" + }, + "message": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "utils.MapStringSliceResponse": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "utils.Response": { + "type": "object", + "properties": { + "status": { + "type": "string" + } + } + }, + "v1.AWSElasticBlockStoreVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "partition": { + "description": "partition is the partition in the volume that you want to mount.\nIf omitted, the default is to mount by volume name.\nExamples: For volume /dev/sda1, you specify the partition as \"1\".\nSimilarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty).\n+optional", + "type": "integer" + }, + "readOnly": { + "description": "readOnly value true will force the readOnly setting in VolumeMounts.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\n+optional", + "type": "boolean" + }, + "volumeID": { + "description": "volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume).\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", + "type": "string" + } + } + }, + "v1.AzureDiskVolumeSource": { + "type": "object", + "properties": { + "cachingMode": { + "description": "cachingMode is the Host Caching mode: None, Read Only, Read Write.\n+optional", + "type": "string" + }, + "diskName": { + "description": "diskName is the Name of the data disk in the blob storage", + "type": "string" + }, + "diskURI": { + "description": "diskURI is the URI of data disk in the blob storage", + "type": "string" + }, + "fsType": { + "description": "fsType is Filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional", + "type": "string" + }, + "kind": { + "description": "kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared", + "type": "string" + }, + "readOnly": { + "description": "readOnly Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + } + } + }, + "v1.AzureFileVolumeSource": { + "type": "object", + "properties": { + "readOnly": { + "description": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "secretName": { + "description": "secretName is the name of secret that contains Azure Storage Account Name and Key", + "type": "string" + }, + "shareName": { + "description": "shareName is the azure share Name", + "type": "string" + } + } + }, + "v1.CSIVolumeSource": { + "type": "object", + "properties": { + "driver": { + "description": "driver is the name of the CSI driver that handles this volume.\nConsult with your admin for the correct name as registered in the cluster.", + "type": "string" + }, + "fsType": { + "description": "fsType to mount. Ex. \"ext4\", \"xfs\", \"ntfs\".\nIf not provided, the empty value is passed to the associated CSI driver\nwhich will determine the default filesystem to apply.\n+optional", + "type": "string" + }, + "nodePublishSecretRef": { + "description": "nodePublishSecretRef is a reference to the secret object containing\nsensitive information to pass to the CSI driver to complete the CSI\nNodePublishVolume and NodeUnpublishVolume calls.\nThis field is optional, and may be empty if no secret is required. If the\nsecret object contains more than one secret, all secret references are passed.\n+optional", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "readOnly": { + "description": "readOnly specifies a read-only configuration for the volume.\nDefaults to false (read/write).\n+optional", + "type": "boolean" + }, + "volumeAttributes": { + "description": "volumeAttributes stores driver-specific properties that are passed to the CSI\ndriver. Consult your driver's documentation for supported values.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "v1.Capabilities": { + "type": "object", + "properties": { + "add": { + "description": "Added capabilities\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "drop": { + "description": "Removed capabilities\n+optional", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "v1.CephFSVolumeSource": { + "type": "object", + "properties": { + "monitors": { + "description": "monitors is Required: Monitors is a collection of Ceph monitors\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", + "type": "array", + "items": { + "type": "string" + } + }, + "path": { + "description": "path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly is Optional: Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional", + "type": "boolean" + }, + "secretFile": { + "description": "secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional", + "type": "string" + }, + "secretRef": { + "description": "secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty.\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "user": { + "description": "user is optional: User is the rados user name, default is admin\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional", + "type": "string" + } + } + }, + "v1.CinderVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef is optional: points to a secret object containing parameters used to connect\nto OpenStack.\n+optional", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "volumeID": { + "description": "volumeID used to identify the volume in cinder.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md", + "type": "string" + } + } + }, + "v1.ConfigMapEnvSource": { + "type": "object", + "properties": { + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + }, + "optional": { + "description": "Specify whether the ConfigMap must be defined\n+optional", + "type": "boolean" + } + } + }, + "v1.ConfigMapKeySelector": { + "type": "object", + "properties": { + "key": { + "description": "The key to select.", + "type": "string" + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + }, + "optional": { + "description": "Specify whether the ConfigMap or its key must be defined\n+optional", + "type": "boolean" + } + } + }, + "v1.ConfigMapProjection": { + "type": "object", + "properties": { + "items": { + "description": "items if unspecified, each key-value pair in the Data field of the referenced\nConfigMap will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the ConfigMap,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.KeyToPath" + } + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + }, + "optional": { + "description": "optional specify whether the ConfigMap or its keys must be defined\n+optional", + "type": "boolean" + } + } + }, + "v1.ConfigMapVolumeSource": { + "type": "object", + "properties": { + "defaultMode": { + "description": "defaultMode is optional: mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nDefaults to 0644.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "items": { + "description": "items if unspecified, each key-value pair in the Data field of the referenced\nConfigMap will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the ConfigMap,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.KeyToPath" + } + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + }, + "optional": { + "description": "optional specify whether the ConfigMap or its keys must be defined\n+optional", + "type": "boolean" + } + } + }, + "v1.Container": { + "type": "object", + "properties": { + "args": { + "description": "Arguments to the entrypoint.\nThe container image's CMD is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "command": { + "description": "Entrypoint array. Not executed within a shell.\nThe container image's ENTRYPOINT is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "env": { + "description": "List of environment variables to set in the container.\nCannot be updated.\n+optional\n+patchMergeKey=name\n+patchStrategy=merge", + "type": "array", + "items": { + "$ref": "#/definitions/v1.EnvVar" + } + }, + "envFrom": { + "description": "List of sources to populate environment variables in the container.\nThe keys defined within a source must be a C_IDENTIFIER. All invalid keys\nwill be reported as an event when the container is starting. When a key exists in multiple\nsources, the value associated with the last source will take precedence.\nValues defined by an Env with a duplicate key will take precedence.\nCannot be updated.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.EnvFromSource" + } + }, + "image": { + "description": "Container image name.\nMore info: https://kubernetes.io/docs/concepts/containers/images\nThis field is optional to allow higher level config management to default or override\ncontainer images in workload controllers like Deployments and StatefulSets.\n+optional", + "type": "string" + }, + "imagePullPolicy": { + "description": "Image pull policy.\nOne of Always, Never, IfNotPresent.\nDefaults to Always if :latest tag is specified, or IfNotPresent otherwise.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/containers/images#updating-images\n+optional", + "type": "string" + }, + "lifecycle": { + "description": "Actions that the management system should take in response to container lifecycle events.\nCannot be updated.\n+optional", + "$ref": "#/definitions/v1.Lifecycle" + }, + "livenessProbe": { + "description": "Periodic probe of container liveness.\nContainer will be restarted if the probe fails.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "$ref": "#/definitions/v1.Probe" + }, + "name": { + "description": "Name of the container specified as a DNS_LABEL.\nEach container in a pod must have a unique name (DNS_LABEL).\nCannot be updated.", + "type": "string" + }, + "ports": { + "description": "List of ports to expose from the container. Not specifying a port here\nDOES NOT prevent that port from being exposed. Any port which is\nlistening on the default \"0.0.0.0\" address inside a container will be\naccessible from the network.\nModifying this array with strategic merge patch may corrupt the data.\nFor more information See https://github.com/kubernetes/kubernetes/issues/108255.\nCannot be updated.\n+optional\n+patchMergeKey=containerPort\n+patchStrategy=merge\n+listType=map\n+listMapKey=containerPort\n+listMapKey=protocol", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ContainerPort" + } + }, + "readinessProbe": { + "description": "Periodic probe of container service readiness.\nContainer will be removed from service endpoints if the probe fails.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "$ref": "#/definitions/v1.Probe" + }, + "resizePolicy": { + "description": "Resources resize policy for the container.\n+featureGate=InPlacePodVerticalScaling\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ContainerResizePolicy" + } + }, + "resources": { + "description": "Compute Resources required by this container.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\n+optional", + "$ref": "#/definitions/v1.ResourceRequirements" + }, + "restartPolicy": { + "description": "RestartPolicy defines the restart behavior of individual containers in a pod.\nThis field may only be set for init containers, and the only allowed value is \"Always\".\nFor non-init containers or when this field is not specified,\nthe restart behavior is defined by the Pod's restart policy and the container type.\nSetting the RestartPolicy as \"Always\" for the init container will have the following effect:\nthis init container will be continually restarted on\nexit until all regular containers have terminated. Once all regular\ncontainers have completed, all init containers with restartPolicy \"Always\"\nwill be shut down. This lifecycle differs from normal init containers and\nis often referred to as a \"sidecar\" container. Although this init\ncontainer still starts in the init container sequence, it does not wait\nfor the container to complete before proceeding to the next init\ncontainer. Instead, the next init container starts immediately after this\ninit container is started, or after any startupProbe has successfully\ncompleted.\n+featureGate=SidecarContainers\n+optional", + "type": "string" + }, + "securityContext": { + "description": "SecurityContext defines the security options the container should be run with.\nIf set, the fields of SecurityContext override the equivalent fields of PodSecurityContext.\nMore info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/\n+optional", + "$ref": "#/definitions/v1.SecurityContext" + }, + "startupProbe": { + "description": "StartupProbe indicates that the Pod has successfully initialized.\nIf specified, no other probes are executed until this completes successfully.\nIf this probe fails, the Pod will be restarted, just as if the livenessProbe failed.\nThis can be used to provide different probe parameters at the beginning of a Pod's lifecycle,\nwhen it might take a long time to load data or warm a cache, than during steady-state operation.\nThis cannot be updated.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "$ref": "#/definitions/v1.Probe" + }, + "stdin": { + "description": "Whether this container should allocate a buffer for stdin in the container runtime. If this\nis not set, reads from stdin in the container will always result in EOF.\nDefault is false.\n+optional", + "type": "boolean" + }, + "stdinOnce": { + "description": "Whether the container runtime should close the stdin channel after it has been opened by\na single attach. When stdin is true the stdin stream will remain open across multiple attach\nsessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the\nfirst client attaches to stdin, and then remains open and accepts data until the client disconnects,\nat which time stdin is closed and remains closed until the container is restarted. If this\nflag is false, a container processes that reads from stdin will never receive an EOF.\nDefault is false\n+optional", + "type": "boolean" + }, + "terminationMessagePath": { + "description": "Optional: Path at which the file to which the container's termination message\nwill be written is mounted into the container's filesystem.\nMessage written is intended to be brief final status, such as an assertion failure message.\nWill be truncated by the node if greater than 4096 bytes. The total message length across\nall containers will be limited to 12kb.\nDefaults to /dev/termination-log.\nCannot be updated.\n+optional", + "type": "string" + }, + "terminationMessagePolicy": { + "description": "Indicate how the termination message should be populated. File will use the contents of\nterminationMessagePath to populate the container status message on both success and failure.\nFallbackToLogsOnError will use the last chunk of container log output if the termination\nmessage file is empty and the container exited with an error.\nThe log output is limited to 2048 bytes or 80 lines, whichever is smaller.\nDefaults to File.\nCannot be updated.\n+optional", + "type": "string" + }, + "tty": { + "description": "Whether this container should allocate a TTY for itself, also requires 'stdin' to be true.\nDefault is false.\n+optional", + "type": "boolean" + }, + "volumeDevices": { + "description": "volumeDevices is the list of block devices to be used by the container.\n+patchMergeKey=devicePath\n+patchStrategy=merge\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.VolumeDevice" + } + }, + "volumeMounts": { + "description": "Pod volumes to mount into the container's filesystem.\nCannot be updated.\n+optional\n+patchMergeKey=mountPath\n+patchStrategy=merge", + "type": "array", + "items": { + "$ref": "#/definitions/v1.VolumeMount" + } + }, + "workingDir": { + "description": "Container's working directory.\nIf not specified, the container runtime's default will be used, which\nmight be configured in the container image.\nCannot be updated.\n+optional", + "type": "string" + } + } + }, + "v1.ContainerPort": { + "type": "object", + "properties": { + "containerPort": { + "description": "Number of port to expose on the pod's IP address.\nThis must be a valid port number, 0 \u003c x \u003c 65536.", + "type": "integer" + }, + "hostIP": { + "description": "What host IP to bind the external port to.\n+optional", + "type": "string" + }, + "hostPort": { + "description": "Number of port to expose on the host.\nIf specified, this must be a valid port number, 0 \u003c x \u003c 65536.\nIf HostNetwork is specified, this must match ContainerPort.\nMost containers do not need this.\n+optional", + "type": "integer" + }, + "name": { + "description": "If specified, this must be an IANA_SVC_NAME and unique within the pod. Each\nnamed port in a pod must have a unique name. Name for the port that can be\nreferred to by services.\n+optional", + "type": "string" + }, + "protocol": { + "description": "Protocol for port. Must be UDP, TCP, or SCTP.\nDefaults to \"TCP\".\n+optional\n+default=\"TCP\"", + "type": "string" + } + } + }, + "v1.ContainerResizePolicy": { + "type": "object", + "properties": { + "resourceName": { + "description": "Name of the resource to which this resource resize policy applies.\nSupported values: cpu, memory.", + "type": "string" + }, + "restartPolicy": { + "description": "Restart policy to apply when specified resource is resized.\nIf not specified, it defaults to NotRequired.", + "type": "string" + } + } + }, + "v1.DownwardAPIProjection": { + "type": "object", + "properties": { + "items": { + "description": "Items is a list of DownwardAPIVolume file\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.DownwardAPIVolumeFile" + } + } + } + }, + "v1.DownwardAPIVolumeFile": { + "type": "object", + "properties": { + "fieldRef": { + "description": "Required: Selects a field of the pod: only annotations, labels, name and namespace are supported.\n+optional", + "$ref": "#/definitions/v1.ObjectFieldSelector" + }, + "mode": { + "description": "Optional: mode bits used to set permissions on this file, must be an octal value\nbetween 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nIf not specified, the volume defaultMode will be used.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "path": { + "description": "Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..'", + "type": "string" + }, + "resourceFieldRef": { + "description": "Selects a resource of the container: only resources limits and requests\n(limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.\n+optional", + "$ref": "#/definitions/v1.ResourceFieldSelector" + } + } + }, + "v1.DownwardAPIVolumeSource": { + "type": "object", + "properties": { + "defaultMode": { + "description": "Optional: mode bits to use on created files by default. Must be a\nOptional: mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nDefaults to 0644.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "items": { + "description": "Items is a list of downward API volume file\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.DownwardAPIVolumeFile" + } + } + } + }, + "v1.EmptyDirVolumeSource": { + "type": "object", + "properties": { + "medium": { + "description": "medium represents what type of storage medium should back this directory.\nThe default is \"\" which means to use the node's default medium.\nMust be an empty string (default) or Memory.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir\n+optional", + "type": "string" + }, + "sizeLimit": { + "description": "sizeLimit is the total amount of local storage required for this EmptyDir volume.\nThe size limit is also applicable for memory medium.\nThe maximum usage on memory medium EmptyDir would be the minimum value between\nthe SizeLimit specified here and the sum of memory limits of all containers in a pod.\nThe default is nil which means that the limit is undefined.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir\n+optional", + "$ref": "#/definitions/resource.Quantity" + } + } + }, + "v1.EnvFromSource": { + "type": "object", + "properties": { + "configMapRef": { + "description": "The ConfigMap to select from\n+optional", + "$ref": "#/definitions/v1.ConfigMapEnvSource" + }, + "prefix": { + "description": "An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.\n+optional", + "type": "string" + }, + "secretRef": { + "description": "The Secret to select from\n+optional", + "$ref": "#/definitions/v1.SecretEnvSource" + } + } + }, + "v1.EnvVar": { + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable. Must be a C_IDENTIFIER.", + "type": "string" + }, + "value": { + "description": "Variable references $(VAR_NAME) are expanded\nusing the previously defined environment variables in the container and\nany service environment variables. If a variable cannot be resolved,\nthe reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e.\n\"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\".\nEscaped references will never be expanded, regardless of whether the variable\nexists or not.\nDefaults to \"\".\n+optional", + "type": "string" + }, + "valueFrom": { + "description": "Source for the environment variable's value. Cannot be used if value is not empty.\n+optional", + "$ref": "#/definitions/v1.EnvVarSource" + } + } + }, + "v1.EnvVarSource": { + "type": "object", + "properties": { + "configMapKeyRef": { + "description": "Selects a key of a ConfigMap.\n+optional", + "$ref": "#/definitions/v1.ConfigMapKeySelector" + }, + "fieldRef": { + "description": "Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['\u003cKEY\u003e']`, `metadata.annotations['\u003cKEY\u003e']`,\nspec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.\n+optional", + "$ref": "#/definitions/v1.ObjectFieldSelector" + }, + "resourceFieldRef": { + "description": "Selects a resource of the container: only resources limits and requests\n(limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.\n+optional", + "$ref": "#/definitions/v1.ResourceFieldSelector" + }, + "secretKeyRef": { + "description": "Selects a key of a secret in the pod's namespace\n+optional", + "$ref": "#/definitions/v1.SecretKeySelector" + } + } + }, + "v1.EphemeralVolumeSource": { + "type": "object", + "properties": { + "volumeClaimTemplate": { + "description": "Will be used to create a stand-alone PVC to provision the volume.\nThe pod in which this EphemeralVolumeSource is embedded will be the\nowner of the PVC, i.e. the PVC will be deleted together with the\npod. The name of the PVC will be `\u003cpod name\u003e-\u003cvolume name\u003e` where\n`\u003cvolume name\u003e` is the name from the `PodSpec.Volumes` array\nentry. Pod validation will reject the pod if the concatenated name\nis not valid for a PVC (for example, too long).\n\nAn existing PVC with that name that is not owned by the pod\nwill *not* be used for the pod to avoid using an unrelated\nvolume by mistake. Starting the pod is then blocked until\nthe unrelated PVC is removed. If such a pre-created PVC is\nmeant to be used by the pod, the PVC has to updated with an\nowner reference to the pod once the pod exists. Normally\nthis should not be necessary, but it may be useful when\nmanually reconstructing a broken cluster.\n\nThis field is read-only and no changes will be made by Kubernetes\nto the PVC after it has been created.\n\nRequired, must not be nil.", + "$ref": "#/definitions/v1.PersistentVolumeClaimTemplate" + } + } + }, + "v1.ExecAction": { + "type": "object", + "properties": { + "command": { + "description": "Command is the command line to execute inside the container, the working directory for the\ncommand is root ('/') in the container's filesystem. The command is simply exec'd, it is\nnot run inside a shell, so traditional shell instructions ('|', etc) won't work. To use\na shell, you need to explicitly call out to that shell.\nExit status of 0 is treated as live/healthy and non-zero is unhealthy.\n+optional", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "v1.FCVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "lun": { + "description": "lun is Optional: FC target lun number\n+optional", + "type": "integer" + }, + "readOnly": { + "description": "readOnly is Optional: Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "targetWWNs": { + "description": "targetWWNs is Optional: FC target worldwide names (WWNs)\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "wwids": { + "description": "wwids Optional: FC volume world wide identifiers (wwids)\nEither wwids or combination of targetWWNs and lun must be set, but not both simultaneously.\n+optional", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "v1.FieldsV1": { + "type": "object" + }, + "v1.FlexVolumeSource": { + "type": "object", + "properties": { + "driver": { + "description": "driver is the name of the driver to use for this volume.", + "type": "string" + }, + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". The default filesystem depends on FlexVolume script.\n+optional", + "type": "string" + }, + "options": { + "description": "options is Optional: this field holds extra command options if any.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "readOnly": { + "description": "readOnly is Optional: defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef is Optional: secretRef is reference to the secret object containing\nsensitive information to pass to the plugin scripts. This may be\nempty if no secret object is specified. If the secret object\ncontains more than one secret, all secrets are passed to the plugin\nscripts.\n+optional", + "$ref": "#/definitions/v1.LocalObjectReference" + } + } + }, + "v1.FlockerVolumeSource": { + "type": "object", + "properties": { + "datasetName": { + "description": "datasetName is Name of the dataset stored as metadata -\u003e name on the dataset for Flocker\nshould be considered as deprecated\n+optional", + "type": "string" + }, + "datasetUUID": { + "description": "datasetUUID is the UUID of the dataset. This is unique identifier of a Flocker dataset\n+optional", + "type": "string" + } + } + }, + "v1.GCEPersistentDiskVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "partition": { + "description": "partition is the partition in the volume that you want to mount.\nIf omitted, the default is to mount by volume name.\nExamples: For volume /dev/sda1, you specify the partition as \"1\".\nSimilarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty).\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional", + "type": "integer" + }, + "pdName": { + "description": "pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional", + "type": "boolean" + } + } + }, + "v1.GRPCAction": { + "type": "object", + "properties": { + "port": { + "description": "Port number of the gRPC service. Number must be in the range 1 to 65535.", + "type": "integer" + }, + "service": { + "description": "Service is the name of the service to place in the gRPC HealthCheckRequest\n(see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).\n\nIf this is not specified, the default behavior is defined by gRPC.\n+optional\n+default=\"\"", + "type": "string" + } + } + }, + "v1.GitRepoVolumeSource": { + "type": "object", + "properties": { + "directory": { + "description": "directory is the target directory name.\nMust not contain or start with '..'. If '.' is supplied, the volume directory will be the\ngit repository. Otherwise, if specified, the volume will contain the git repository in\nthe subdirectory with the given name.\n+optional", + "type": "string" + }, + "repository": { + "description": "repository is the URL", + "type": "string" + }, + "revision": { + "description": "revision is the commit hash for the specified revision.\n+optional", + "type": "string" + } + } + }, + "v1.GlusterfsVolumeSource": { + "type": "object", + "properties": { + "endpoints": { + "description": "endpoints is the endpoint name that details Glusterfs topology.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", + "type": "string" + }, + "path": { + "description": "path is the Glusterfs volume path.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the Glusterfs volume to be mounted with read-only permissions.\nDefaults to false.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod\n+optional", + "type": "boolean" + } + } + }, + "v1.HTTPGetAction": { + "type": "object", + "properties": { + "host": { + "description": "Host name to connect to, defaults to the pod IP. You probably want to set\n\"Host\" in httpHeaders instead.\n+optional", + "type": "string" + }, + "httpHeaders": { + "description": "Custom headers to set in the request. HTTP allows repeated headers.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.HTTPHeader" + } + }, + "path": { + "description": "Path to access on the HTTP server.\n+optional", + "type": "string" + }, + "port": { + "description": "Name or number of the port to access on the container.\nNumber must be in the range 1 to 65535.\nName must be an IANA_SVC_NAME.", + "$ref": "#/definitions/intstr.IntOrString" + }, + "scheme": { + "description": "Scheme to use for connecting to the host.\nDefaults to HTTP.\n+optional", + "type": "string" + } + } + }, + "v1.HTTPHeader": { + "type": "object", + "properties": { + "name": { + "description": "The header field name.\nThis will be canonicalized upon output, so case-variant names will be understood as the same header.", + "type": "string" + }, + "value": { + "description": "The header field value", + "type": "string" + } + } + }, + "v1.HostPathVolumeSource": { + "type": "object", + "properties": { + "path": { + "description": "path of the directory on the host.\nIf the path is a symlink, it will follow the link to the real path.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", + "type": "string" + }, + "type": { + "description": "type for HostPath Volume\nDefaults to \"\"\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath\n+optional", + "type": "string" + } + } + }, + "v1.ISCSIVolumeSource": { + "type": "object", + "properties": { + "chapAuthDiscovery": { + "description": "chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication\n+optional", + "type": "boolean" + }, + "chapAuthSession": { + "description": "chapAuthSession defines whether support iSCSI Session CHAP authentication\n+optional", + "type": "boolean" + }, + "fsType": { + "description": "fsType is the filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "initiatorName": { + "description": "initiatorName is the custom iSCSI Initiator Name.\nIf initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface\n\u003ctarget portal\u003e:\u003cvolume name\u003e will be created for the connection.\n+optional", + "type": "string" + }, + "iqn": { + "description": "iqn is the target iSCSI Qualified Name.", + "type": "string" + }, + "iscsiInterface": { + "description": "iscsiInterface is the interface Name that uses an iSCSI transport.\nDefaults to 'default' (tcp).\n+optional", + "type": "string" + }, + "lun": { + "description": "lun represents iSCSI Target Lun number.", + "type": "integer" + }, + "portals": { + "description": "portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port\nis other than default (typically TCP ports 860 and 3260).\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "readOnly": { + "description": "readOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef is the CHAP Secret for iSCSI target and initiator authentication\n+optional", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "targetPortal": { + "description": "targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port\nis other than default (typically TCP ports 860 and 3260).", + "type": "string" + } + } + }, + "v1.KeyToPath": { + "type": "object", + "properties": { + "key": { + "description": "key is the key to project.", + "type": "string" + }, + "mode": { + "description": "mode is Optional: mode bits used to set permissions on this file.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nIf not specified, the volume defaultMode will be used.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "path": { + "description": "path is the relative path of the file to map the key to.\nMay not be an absolute path.\nMay not contain the path element '..'.\nMay not start with the string '..'.", + "type": "string" + } + } + }, + "v1.LabelSelector": { + "type": "object", + "properties": { + "matchExpressions": { + "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.LabelSelectorRequirement" + } + }, + "matchLabels": { + "description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels\nmap is equivalent to an element of matchExpressions, whose key field is \"key\", the\noperator is \"In\", and the values array contains only \"value\". The requirements are ANDed.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "v1.LabelSelectorRequirement": { + "type": "object", + "properties": { + "key": { + "description": "key is the label key that the selector applies to.", + "type": "string" + }, + "operator": { + "description": "operator represents a key's relationship to a set of values.\nValid operators are In, NotIn, Exists and DoesNotExist.", + "type": "string" + }, + "values": { + "description": "values is an array of string values. If the operator is In or NotIn,\nthe values array must be non-empty. If the operator is Exists or DoesNotExist,\nthe values array must be empty. This array is replaced during a strategic\nmerge patch.\n+optional", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "v1.Lifecycle": { + "type": "object", + "properties": { + "postStart": { + "description": "PostStart is called immediately after a container is created. If the handler fails,\nthe container is terminated and restarted according to its restart policy.\nOther management of the container blocks until the hook completes.\nMore info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks\n+optional", + "$ref": "#/definitions/v1.LifecycleHandler" + }, + "preStop": { + "description": "PreStop is called immediately before a container is terminated due to an\nAPI request or management event such as liveness/startup probe failure,\npreemption, resource contention, etc. The handler is not called if the\ncontainer crashes or exits. The Pod's termination grace period countdown begins before the\nPreStop hook is executed. Regardless of the outcome of the handler, the\ncontainer will eventually terminate within the Pod's termination grace\nperiod (unless delayed by finalizers). Other management of the container blocks until the hook completes\nor until the termination grace period is reached.\nMore info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks\n+optional", + "$ref": "#/definitions/v1.LifecycleHandler" + } + } + }, + "v1.LifecycleHandler": { + "type": "object", + "properties": { + "exec": { + "description": "Exec specifies the action to take.\n+optional", + "$ref": "#/definitions/v1.ExecAction" + }, + "httpGet": { + "description": "HTTPGet specifies the http request to perform.\n+optional", + "$ref": "#/definitions/v1.HTTPGetAction" + }, + "tcpSocket": { + "description": "Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept\nfor the backward compatibility. There are no validation of this field and\nlifecycle hooks will fail in runtime when tcp handler is specified.\n+optional", + "$ref": "#/definitions/v1.TCPSocketAction" + } + } + }, + "v1.LocalObjectReference": { + "type": "object", + "properties": { + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + } + } + }, + "v1.ManagedFieldsEntry": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the version of this resource that this field set\napplies to. The format is \"group/version\" just like the top-level\nAPIVersion field. It is necessary to track the version of a field\nset because it cannot be automatically converted.", + "type": "string" + }, + "fieldsType": { + "description": "FieldsType is the discriminator for the different fields format and version.\nThere is currently only one possible value: \"FieldsV1\"", + "type": "string" + }, + "fieldsV1": { + "description": "FieldsV1 holds the first JSON version format as described in the \"FieldsV1\" type.\n+optional", + "$ref": "#/definitions/v1.FieldsV1" + }, + "manager": { + "description": "Manager is an identifier of the workflow managing these fields.", + "type": "string" + }, + "operation": { + "description": "Operation is the type of operation which lead to this ManagedFieldsEntry being created.\nThe only valid values for this field are 'Apply' and 'Update'.", + "type": "string" + }, + "subresource": { + "description": "Subresource is the name of the subresource used to update that object, or\nempty string if the object was updated through the main resource. The\nvalue of this field is used to distinguish between managers, even if they\nshare the same name. For example, a status update will be distinct from a\nregular update using the same manager name.\nNote that the APIVersion field is not related to the Subresource field and\nit always corresponds to the version of the main resource.", + "type": "string" + }, + "time": { + "description": "Time is the timestamp of when the ManagedFields entry was added. The\ntimestamp will also be updated if a field is added, the manager\nchanges any of the owned fields value or removes a field. The\ntimestamp does not update when a field is removed from the entry\nbecause another manager took it over.\n+optional", + "type": "string" + } + } + }, + "v1.NFSVolumeSource": { + "type": "object", + "properties": { + "path": { + "description": "path that is exported by the NFS server.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the NFS export to be mounted with read-only permissions.\nDefaults to false.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs\n+optional", + "type": "boolean" + }, + "server": { + "description": "server is the hostname or IP address of the NFS server.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", + "type": "string" + } + } + }, + "v1.ObjectFieldSelector": { + "type": "object", + "properties": { + "apiVersion": { + "description": "Version of the schema the FieldPath is written in terms of, defaults to \"v1\".\n+optional", + "type": "string" + }, + "fieldPath": { + "description": "Path of the field to select in the specified API version.", + "type": "string" + } + } + }, + "v1.ObjectReference": { + "type": "object", + "properties": { + "apiVersion": { + "description": "API version of the referent.\n+optional", + "type": "string" + }, + "fieldPath": { + "description": "If referring to a piece of an object instead of an entire object, this string\nshould contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2].\nFor example, if the object reference is to a container within a pod, this would take on a value like:\n\"spec.containers{name}\" (where \"name\" refers to the name of the container that triggered\nthe event) or if no container name is specified \"spec.containers[2]\" (container with\nindex 2 in this pod). This syntax is chosen only to have some well-defined way of\nreferencing a part of an object.\nTODO: this design is not final and this field is subject to change in the future.\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind of the referent.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\n+optional", + "type": "string" + }, + "namespace": { + "description": "Namespace of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/\n+optional", + "type": "string" + }, + "resourceVersion": { + "description": "Specific resourceVersion to which this reference is made, if any.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency\n+optional", + "type": "string" + }, + "uid": { + "description": "UID of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids\n+optional", + "type": "string" + } + } + }, + "v1.OwnerReference": { + "type": "object", + "properties": { + "apiVersion": { + "description": "API version of the referent.", + "type": "string" + }, + "blockOwnerDeletion": { + "description": "If true, AND if the owner has the \"foregroundDeletion\" finalizer, then\nthe owner cannot be deleted from the key-value store until this\nreference is removed.\nSee https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion\nfor how the garbage collector interacts with this field and enforces the foreground deletion.\nDefaults to false.\nTo set this field, a user needs \"delete\" permission of the owner,\notherwise 422 (Unprocessable Entity) will be returned.\n+optional", + "type": "boolean" + }, + "controller": { + "description": "If true, this reference points to the managing controller.\n+optional", + "type": "boolean" + }, + "kind": { + "description": "Kind of the referent.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names", + "type": "string" + }, + "uid": { + "description": "UID of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids", + "type": "string" + } + } + }, + "v1.PersistentVolumeClaimSpec": { + "type": "object", + "properties": { + "accessModes": { + "description": "accessModes contains the desired access modes the volume should have.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "dataSource": { + "description": "dataSource field can be used to specify either:\n* An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)\n* An existing PVC (PersistentVolumeClaim)\nIf the provisioner or an external controller can support the specified data source,\nit will create a new volume based on the contents of the specified data source.\nWhen the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef,\nand dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified.\nIf the namespace is specified, then dataSourceRef will not be copied to dataSource.\n+optional", + "$ref": "#/definitions/v1.TypedLocalObjectReference" + }, + "dataSourceRef": { + "description": "dataSourceRef specifies the object from which to populate the volume with data, if a non-empty\nvolume is desired. This may be any object from a non-empty API group (non\ncore object) or a PersistentVolumeClaim object.\nWhen this field is specified, volume binding will only succeed if the type of\nthe specified object matches some installed volume populator or dynamic\nprovisioner.\nThis field will replace the functionality of the dataSource field and as such\nif both fields are non-empty, they must have the same value. For backwards\ncompatibility, when namespace isn't specified in dataSourceRef,\nboth fields (dataSource and dataSourceRef) will be set to the same\nvalue automatically if one of them is empty and the other is non-empty.\nWhen namespace is specified in dataSourceRef,\ndataSource isn't set to the same value and must be empty.\nThere are three important differences between dataSource and dataSourceRef:\n* While dataSource only allows two specific types of objects, dataSourceRef\n allows any non-core object, as well as PersistentVolumeClaim objects.\n* While dataSource ignores disallowed values (dropping them), dataSourceRef\n preserves all values, and generates an error if a disallowed value is\n specified.\n* While dataSource only allows local objects, dataSourceRef allows objects\n in any namespaces.\n(Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled.\n(Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled.\n+optional", + "$ref": "#/definitions/v1.TypedObjectReference" + }, + "resources": { + "description": "resources represents the minimum resources the volume should have.\nIf RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements\nthat are lower than previous value but must still be higher than capacity recorded in the\nstatus field of the claim.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources\n+optional", + "$ref": "#/definitions/v1.ResourceRequirements" + }, + "selector": { + "description": "selector is a label query over volumes to consider for binding.\n+optional", + "$ref": "#/definitions/v1.LabelSelector" + }, + "storageClassName": { + "description": "storageClassName is the name of the StorageClass required by the claim.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1\n+optional", + "type": "string" + }, + "volumeMode": { + "description": "volumeMode defines what type of volume is required by the claim.\nValue of Filesystem is implied when not included in claim spec.\n+optional", + "type": "string" + }, + "volumeName": { + "description": "volumeName is the binding reference to the PersistentVolume backing this claim.\n+optional", + "type": "string" + } + } + }, + "v1.PersistentVolumeClaimTemplate": { + "type": "object", + "properties": { + "annotations": { + "description": "Annotations is an unstructured key value map stored with a resource that may be\nset by external tools to store and retrieve arbitrary metadata. They are not\nqueryable and should be preserved when modifying objects.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "creationTimestamp": { + "description": "CreationTimestamp is a timestamp representing the server time when this object was\ncreated. It is not guaranteed to be set in happens-before order across separate operations.\nClients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system.\nRead-only.\nNull for lists.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "type": "string" + }, + "deletionGracePeriodSeconds": { + "description": "Number of seconds allowed for this object to gracefully terminate before\nit will be removed from the system. Only set when deletionTimestamp is also set.\nMay only be shortened.\nRead-only.\n+optional", + "type": "integer" + }, + "deletionTimestamp": { + "description": "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This\nfield is set by the server when a graceful deletion is requested by the user, and is not\ndirectly settable by a client. The resource is expected to be deleted (no longer visible\nfrom resource lists, and not reachable by name) after the time in this field, once the\nfinalizers list is empty. As long as the finalizers list contains items, deletion is blocked.\nOnce the deletionTimestamp is set, this value may not be unset or be set further into the\nfuture, although it may be shortened or the resource may be deleted prior to this time.\nFor example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react\nby sending a graceful termination signal to the containers in the pod. After that 30 seconds,\nthe Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,\nremove the pod from the API. In the presence of network partitions, this object may still\nexist after this timestamp, until an administrator or automated process can determine the\nresource is fully terminated.\nIf not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested.\nRead-only.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "type": "string" + }, + "finalizers": { + "description": "Must be empty before the object is deleted from the registry. Each entry\nis an identifier for the responsible component that will remove the entry\nfrom the list. If the deletionTimestamp of the object is non-nil, entries\nin this list can only be removed.\nFinalizers may be processed and removed in any order. Order is NOT enforced\nbecause it introduces significant risk of stuck finalizers.\nfinalizers is a shared field, any actor with permission can reorder it.\nIf the finalizer list is processed in order, then this can lead to a situation\nin which the component responsible for the first finalizer in the list is\nwaiting for a signal (field value, external system, or other) produced by a\ncomponent responsible for a finalizer later in the list, resulting in a deadlock.\nWithout enforced ordering finalizers are free to order amongst themselves and\nare not vulnerable to ordering changes in the list.\n+optional\n+patchStrategy=merge", + "type": "array", + "items": { + "type": "string" + } + }, + "generateName": { + "description": "GenerateName is an optional prefix, used by the server, to generate a unique\nname ONLY IF the Name field has not been provided.\nIf this field is used, the name returned to the client will be different\nthan the name passed. This value will also be combined with a unique suffix.\nThe provided value has the same validation rules as the Name field,\nand may be truncated by the length of the suffix required to make the value\nunique on the server.\n\nIf this field is specified and the generated name exists, the server will return a 409.\n\nApplied only if Name is not specified.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency\n+optional", + "type": "string" + }, + "generation": { + "description": "A sequence number representing a specific generation of the desired state.\nPopulated by the system. Read-only.\n+optional", + "type": "integer" + }, + "labels": { + "description": "Map of string keys and values that can be used to organize and categorize\n(scope and select) objects. May match selectors of replication controllers\nand services.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "managedFields": { + "description": "ManagedFields maps workflow-id and version to the set of fields\nthat are managed by that workflow. This is mostly for internal\nhousekeeping, and users typically shouldn't need to set or\nunderstand this field. A workflow can be the user's name, a\ncontroller's name, or the name of a specific apply path like\n\"ci-cd\". The set of fields is always in the version that the\nworkflow used when modifying the object.\n\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ManagedFieldsEntry" + } + }, + "name": { + "description": "Name must be unique within a namespace. Is required when creating resources, although\nsome resources may allow a client to request the generation of an appropriate name\nautomatically. Name is primarily intended for creation idempotence and configuration\ndefinition.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names\n+optional", + "type": "string" + }, + "namespace": { + "description": "Namespace defines the space within which each name must be unique. An empty namespace is\nequivalent to the \"default\" namespace, but \"default\" is the canonical representation.\nNot all objects are required to be scoped to a namespace - the value of this field for\nthose objects will be empty.\n\nMust be a DNS_LABEL.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces\n+optional", + "type": "string" + }, + "ownerReferences": { + "description": "List of objects depended by this object. If ALL objects in the list have\nbeen deleted, this object will be garbage collected. If this object is managed by a controller,\nthen an entry in this list will point to this controller, with the controller field set to true.\nThere cannot be more than one managing controller.\n+optional\n+patchMergeKey=uid\n+patchStrategy=merge", + "type": "array", + "items": { + "$ref": "#/definitions/v1.OwnerReference" + } + }, + "resourceVersion": { + "description": "An opaque value that represents the internal version of this object that can\nbe used by clients to determine when objects have changed. May be used for optimistic\nconcurrency, change detection, and the watch operation on a resource or set of resources.\nClients must treat these values as opaque and passed unmodified back to the server.\nThey may only be valid for a particular resource or set of resources.\n\nPopulated by the system.\nRead-only.\nValue must be treated as opaque by clients and .\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency\n+optional", + "type": "string" + }, + "selfLink": { + "description": "Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.\n+optional", + "type": "string" + }, + "spec": { + "description": "The specification for the PersistentVolumeClaim. The entire content is\ncopied unchanged into the PVC that gets created from this\ntemplate. The same fields as in a PersistentVolumeClaim\nare also valid here.", + "$ref": "#/definitions/v1.PersistentVolumeClaimSpec" + }, + "uid": { + "description": "UID is the unique in time and space value for this object. It is typically generated by\nthe server on successful creation of a resource and is not allowed to change on PUT\noperations.\n\nPopulated by the system.\nRead-only.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids\n+optional", + "type": "string" + } + } + }, + "v1.PersistentVolumeClaimVolumeSource": { + "type": "object", + "properties": { + "claimName": { + "description": "claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", + "type": "string" + }, + "readOnly": { + "description": "readOnly Will force the ReadOnly setting in VolumeMounts.\nDefault false.\n+optional", + "type": "boolean" + } + } + }, + "v1.PhotonPersistentDiskVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", + "type": "string" + }, + "pdID": { + "description": "pdID is the ID that identifies Photon Controller persistent disk", + "type": "string" + } + } + }, + "v1.PortworxVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fSType represents the filesystem type to mount\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\". Implicitly inferred to be \"ext4\" if unspecified.", + "type": "string" + }, + "readOnly": { + "description": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "volumeID": { + "description": "volumeID uniquely identifies a Portworx volume", + "type": "string" + } + } + }, + "v1.Probe": { + "type": "object", + "properties": { + "exec": { + "description": "Exec specifies the action to take.\n+optional", + "$ref": "#/definitions/v1.ExecAction" + }, + "failureThreshold": { + "description": "Minimum consecutive failures for the probe to be considered failed after having succeeded.\nDefaults to 3. Minimum value is 1.\n+optional", + "type": "integer" + }, + "grpc": { + "description": "GRPC specifies an action involving a GRPC port.\n+optional", + "$ref": "#/definitions/v1.GRPCAction" + }, + "httpGet": { + "description": "HTTPGet specifies the http request to perform.\n+optional", + "$ref": "#/definitions/v1.HTTPGetAction" + }, + "initialDelaySeconds": { + "description": "Number of seconds after the container has started before liveness probes are initiated.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "type": "integer" + }, + "periodSeconds": { + "description": "How often (in seconds) to perform the probe.\nDefault to 10 seconds. Minimum value is 1.\n+optional", + "type": "integer" + }, + "successThreshold": { + "description": "Minimum consecutive successes for the probe to be considered successful after having failed.\nDefaults to 1. Must be 1 for liveness and startup. Minimum value is 1.\n+optional", + "type": "integer" + }, + "tcpSocket": { + "description": "TCPSocket specifies an action involving a TCP port.\n+optional", + "$ref": "#/definitions/v1.TCPSocketAction" + }, + "terminationGracePeriodSeconds": { + "description": "Optional duration in seconds the pod needs to terminate gracefully upon probe failure.\nThe grace period is the duration in seconds after the processes running in the pod are sent\na termination signal and the time when the processes are forcibly halted with a kill signal.\nSet this value longer than the expected cleanup time for your process.\nIf this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this\nvalue overrides the value provided by the pod spec.\nValue must be non-negative integer. The value zero indicates stop immediately via\nthe kill signal (no opportunity to shut down).\nThis is a beta field and requires enabling ProbeTerminationGracePeriod feature gate.\nMinimum value is 1. spec.terminationGracePeriodSeconds is used if unset.\n+optional", + "type": "integer" + }, + "timeoutSeconds": { + "description": "Number of seconds after which the probe times out.\nDefaults to 1 second. Minimum value is 1.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "type": "integer" + } + } + }, + "v1.ProjectedVolumeSource": { + "type": "object", + "properties": { + "defaultMode": { + "description": "defaultMode are the mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "sources": { + "description": "sources is the list of volume projections\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.VolumeProjection" + } + } + } + }, + "v1.QuobyteVolumeSource": { + "type": "object", + "properties": { + "group": { + "description": "group to map volume access to\nDefault is no group\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the Quobyte volume to be mounted with read-only permissions.\nDefaults to false.\n+optional", + "type": "boolean" + }, + "registry": { + "description": "registry represents a single or multiple Quobyte Registry services\nspecified as a string as host:port pair (multiple entries are separated with commas)\nwhich acts as the central registry for volumes", + "type": "string" + }, + "tenant": { + "description": "tenant owning the given Quobyte volume in the Backend\nUsed with dynamically provisioned Quobyte volumes, value is set by the plugin\n+optional", + "type": "string" + }, + "user": { + "description": "user to map volume access to\nDefaults to serivceaccount user\n+optional", + "type": "string" + }, + "volume": { + "description": "volume is a string that references an already created Quobyte volume by name.", + "type": "string" + } + } + }, + "v1.RBDVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#rbd\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "image": { + "description": "image is the rados image name.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + "type": "string" + }, + "keyring": { + "description": "keyring is the path to key ring for RBDUser.\nDefault is /etc/ceph/keyring.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional", + "type": "string" + }, + "monitors": { + "description": "monitors is a collection of Ceph monitors.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + "type": "array", + "items": { + "type": "string" + } + }, + "pool": { + "description": "pool is the rados pool name.\nDefault is rbd.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef is name of the authentication secret for RBDUser. If provided\noverrides keyring.\nDefault is nil.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "user": { + "description": "user is the rados user name.\nDefault is admin.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional", + "type": "string" + } + } + }, + "v1.ResourceClaim": { + "type": "object", + "properties": { + "name": { + "description": "Name must match the name of one entry in pod.spec.resourceClaims of\nthe Pod where this field is used. It makes that resource available\ninside a container.", + "type": "string" + } + } + }, + "v1.ResourceFieldSelector": { + "type": "object", + "properties": { + "containerName": { + "description": "Container name: required for volumes, optional for env vars\n+optional", + "type": "string" + }, + "divisor": { + "description": "Specifies the output format of the exposed resources, defaults to \"1\"\n+optional", + "$ref": "#/definitions/resource.Quantity" + }, + "resource": { + "description": "Required: resource to select", + "type": "string" + } + } + }, + "v1.ResourceList": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/resource.Quantity" + } + }, + "v1.ResourceRequirements": { + "type": "object", + "properties": { + "claims": { + "description": "Claims lists the names of resources, defined in spec.resourceClaims,\nthat are used by this container.\n\nThis is an alpha field and requires enabling the\nDynamicResourceAllocation feature gate.\n\nThis field is immutable. It can only be set for containers.\n\n+listType=map\n+listMapKey=name\n+featureGate=DynamicResourceAllocation\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ResourceClaim" + } + }, + "limits": { + "description": "Limits describes the maximum amount of compute resources allowed.\nMore info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\n+optional", + "$ref": "#/definitions/v1.ResourceList" + }, + "requests": { + "description": "Requests describes the minimum amount of compute resources required.\nIf Requests is omitted for a container, it defaults to Limits if that is explicitly specified,\notherwise to an implementation-defined value. Requests cannot exceed Limits.\nMore info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\n+optional", + "$ref": "#/definitions/v1.ResourceList" + } + } + }, + "v1.SELinuxOptions": { + "type": "object", + "properties": { + "level": { + "description": "Level is SELinux level label that applies to the container.\n+optional", + "type": "string" + }, + "role": { + "description": "Role is a SELinux role label that applies to the container.\n+optional", + "type": "string" + }, + "type": { + "description": "Type is a SELinux type label that applies to the container.\n+optional", + "type": "string" + }, + "user": { + "description": "User is a SELinux user label that applies to the container.\n+optional", + "type": "string" + } + } + }, + "v1.ScaleIOVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\".\nDefault is \"xfs\".\n+optional", + "type": "string" + }, + "gateway": { + "description": "gateway is the host address of the ScaleIO API Gateway.", + "type": "string" + }, + "protectionDomain": { + "description": "protectionDomain is the name of the ScaleIO Protection Domain for the configured storage.\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef references to the secret for ScaleIO user and other\nsensitive information. If this is not provided, Login operation will fail.", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "sslEnabled": { + "description": "sslEnabled Flag enable/disable SSL communication with Gateway, default false\n+optional", + "type": "boolean" + }, + "storageMode": { + "description": "storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned.\nDefault is ThinProvisioned.\n+optional", + "type": "string" + }, + "storagePool": { + "description": "storagePool is the ScaleIO Storage Pool associated with the protection domain.\n+optional", + "type": "string" + }, + "system": { + "description": "system is the name of the storage system as configured in ScaleIO.", + "type": "string" + }, + "volumeName": { + "description": "volumeName is the name of a volume already created in the ScaleIO system\nthat is associated with this volume source.", + "type": "string" + } + } + }, + "v1.SeccompProfile": { + "type": "object", + "properties": { + "localhostProfile": { + "description": "localhostProfile indicates a profile defined in a file on the node should be used.\nThe profile must be preconfigured on the node to work.\nMust be a descending path, relative to the kubelet's configured seccomp profile location.\nMust be set if type is \"Localhost\". Must NOT be set for any other type.\n+optional", + "type": "string" + }, + "type": { + "description": "type indicates which kind of seccomp profile will be applied.\nValid options are:\n\nLocalhost - a profile defined in a file on the node should be used.\nRuntimeDefault - the container runtime default profile should be used.\nUnconfined - no profile should be applied.\n+unionDiscriminator", + "type": "string" + } + } + }, + "v1.SecretEnvSource": { + "type": "object", + "properties": { + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + }, + "optional": { + "description": "Specify whether the Secret must be defined\n+optional", + "type": "boolean" + } + } + }, + "v1.SecretKeySelector": { + "type": "object", + "properties": { + "key": { + "description": "The key of the secret to select from. Must be a valid secret key.", + "type": "string" + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + }, + "optional": { + "description": "Specify whether the Secret or its key must be defined\n+optional", + "type": "boolean" + } + } + }, + "v1.SecretProjection": { + "type": "object", + "properties": { + "items": { + "description": "items if unspecified, each key-value pair in the Data field of the referenced\nSecret will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the Secret,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.KeyToPath" + } + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional", + "type": "string" + }, + "optional": { + "description": "optional field specify whether the Secret or its key must be defined\n+optional", + "type": "boolean" + } + } + }, + "v1.SecretVolumeSource": { + "type": "object", + "properties": { + "defaultMode": { + "description": "defaultMode is Optional: mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values\nfor mode bits. Defaults to 0644.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "items": { + "description": "items If unspecified, each key-value pair in the Data field of the referenced\nSecret will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the Secret,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.KeyToPath" + } + }, + "optional": { + "description": "optional field specify whether the Secret or its keys must be defined\n+optional", + "type": "boolean" + }, + "secretName": { + "description": "secretName is the name of the secret in the pod's namespace to use.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#secret\n+optional", + "type": "string" + } + } + }, + "v1.SecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "description": "AllowPrivilegeEscalation controls whether a process can gain more\nprivileges than its parent process. This bool directly controls if\nthe no_new_privs flag will be set on the container process.\nAllowPrivilegeEscalation is true always when the container is:\n1) run as Privileged\n2) has CAP_SYS_ADMIN\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "boolean" + }, + "capabilities": { + "description": "The capabilities to add/drop when running containers.\nDefaults to the default set of capabilities granted by the container runtime.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "$ref": "#/definitions/v1.Capabilities" + }, + "privileged": { + "description": "Run container in privileged mode.\nProcesses in privileged containers are essentially equivalent to root on the host.\nDefaults to false.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "boolean" + }, + "procMount": { + "description": "procMount denotes the type of proc mount to use for the containers.\nThe default is DefaultProcMount which uses the container runtime defaults for\nreadonly paths and masked paths.\nThis requires the ProcMountType feature flag to be enabled.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "string" + }, + "readOnlyRootFilesystem": { + "description": "Whether this container has a read-only root filesystem.\nDefault is false.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "boolean" + }, + "runAsGroup": { + "description": "The GID to run the entrypoint of the container process.\nUses runtime default if unset.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "integer" + }, + "runAsNonRoot": { + "description": "Indicates that the container must run as a non-root user.\nIf true, the Kubelet will validate the image at runtime to ensure that it\ndoes not run as UID 0 (root) and fail to start the container if it does.\nIf unset or false, no such validation will be performed.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\n+optional", + "type": "boolean" + }, + "runAsUser": { + "description": "The UID to run the entrypoint of the container process.\nDefaults to user specified in image metadata if unspecified.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "integer" + }, + "seLinuxOptions": { + "description": "The SELinux context to be applied to the container.\nIf unspecified, the container runtime will allocate a random SELinux context for each\ncontainer. May also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "$ref": "#/definitions/v1.SELinuxOptions" + }, + "seccompProfile": { + "description": "The seccomp options to use by this container. If seccomp options are\nprovided at both the pod \u0026 container level, the container options\noverride the pod options.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "$ref": "#/definitions/v1.SeccompProfile" + }, + "windowsOptions": { + "description": "The Windows specific settings applied to all containers.\nIf unspecified, the options from the PodSecurityContext will be used.\nIf set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is linux.\n+optional", + "$ref": "#/definitions/v1.WindowsSecurityContextOptions" + } + } + }, + "v1.ServiceAccountTokenProjection": { + "type": "object", + "properties": { + "audience": { + "description": "audience is the intended audience of the token. A recipient of a token\nmust identify itself with an identifier specified in the audience of the\ntoken, and otherwise should reject the token. The audience defaults to the\nidentifier of the apiserver.\n+optional", + "type": "string" + }, + "expirationSeconds": { + "description": "expirationSeconds is the requested duration of validity of the service\naccount token. As the token approaches expiration, the kubelet volume\nplugin will proactively rotate the service account token. The kubelet will\nstart trying to rotate the token if the token is older than 80 percent of\nits time to live or if the token is older than 24 hours.Defaults to 1 hour\nand must be at least 10 minutes.\n+optional", + "type": "integer" + }, + "path": { + "description": "path is the path relative to the mount point of the file to project the\ntoken into.", + "type": "string" + } + } + }, + "v1.StorageOSVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef specifies the secret to use for obtaining the StorageOS API\ncredentials. If not specified, default values will be attempted.\n+optional", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "volumeName": { + "description": "volumeName is the human-readable name of the StorageOS volume. Volume\nnames are only unique within a namespace.", + "type": "string" + }, + "volumeNamespace": { + "description": "volumeNamespace specifies the scope of the volume within StorageOS. If no\nnamespace is specified then the Pod's namespace will be used. This allows the\nKubernetes name scoping to be mirrored within StorageOS for tighter integration.\nSet VolumeName to any name to override the default behaviour.\nSet to \"default\" if you are not using namespaces within StorageOS.\nNamespaces that do not pre-exist within StorageOS will be created.\n+optional", + "type": "string" + } + } + }, + "v1.TCPSocketAction": { + "type": "object", + "properties": { + "host": { + "description": "Optional: Host name to connect to, defaults to the pod IP.\n+optional", + "type": "string" + }, + "port": { + "description": "Number or name of the port to access on the container.\nNumber must be in the range 1 to 65535.\nName must be an IANA_SVC_NAME.", + "$ref": "#/definitions/intstr.IntOrString" + } + } + }, + "v1.TypedLocalObjectReference": { + "type": "object", + "properties": { + "apiGroup": { + "description": "APIGroup is the group for the resource being referenced.\nIf APIGroup is not specified, the specified Kind must be in the core API group.\nFor any other third-party types, APIGroup is required.\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is the type of resource being referenced", + "type": "string" + }, + "name": { + "description": "Name is the name of resource being referenced", + "type": "string" + } + } + }, + "v1.TypedObjectReference": { + "type": "object", + "properties": { + "apiGroup": { + "description": "APIGroup is the group for the resource being referenced.\nIf APIGroup is not specified, the specified Kind must be in the core API group.\nFor any other third-party types, APIGroup is required.\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is the type of resource being referenced", + "type": "string" + }, + "name": { + "description": "Name is the name of resource being referenced", + "type": "string" + }, + "namespace": { + "description": "Namespace is the namespace of resource being referenced\nNote that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details.\n(Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled.\n+featureGate=CrossNamespaceVolumeDataSource\n+optional", + "type": "string" + } + } + }, + "v1.Volume": { + "type": "object", + "properties": { + "awsElasticBlockStore": { + "description": "awsElasticBlockStore represents an AWS Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\n+optional", + "$ref": "#/definitions/v1.AWSElasticBlockStoreVolumeSource" + }, + "azureDisk": { + "description": "azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.\n+optional", + "$ref": "#/definitions/v1.AzureDiskVolumeSource" + }, + "azureFile": { + "description": "azureFile represents an Azure File Service mount on the host and bind mount to the pod.\n+optional", + "$ref": "#/definitions/v1.AzureFileVolumeSource" + }, + "cephfs": { + "description": "cephFS represents a Ceph FS mount on the host that shares a pod's lifetime\n+optional", + "$ref": "#/definitions/v1.CephFSVolumeSource" + }, + "cinder": { + "description": "cinder represents a cinder volume attached and mounted on kubelets host machine.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional", + "$ref": "#/definitions/v1.CinderVolumeSource" + }, + "configMap": { + "description": "configMap represents a configMap that should populate this volume\n+optional", + "$ref": "#/definitions/v1.ConfigMapVolumeSource" + }, + "csi": { + "description": "csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature).\n+optional", + "$ref": "#/definitions/v1.CSIVolumeSource" + }, + "downwardAPI": { + "description": "downwardAPI represents downward API about the pod that should populate this volume\n+optional", + "$ref": "#/definitions/v1.DownwardAPIVolumeSource" + }, + "emptyDir": { + "description": "emptyDir represents a temporary directory that shares a pod's lifetime.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir\n+optional", + "$ref": "#/definitions/v1.EmptyDirVolumeSource" + }, + "ephemeral": { + "description": "ephemeral represents a volume that is handled by a cluster storage driver.\nThe volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts,\nand deleted when the pod is removed.\n\nUse this if:\na) the volume is only needed while the pod runs,\nb) features of normal volumes like restoring from snapshot or capacity\n tracking are needed,\nc) the storage driver is specified through a storage class, and\nd) the storage driver supports dynamic volume provisioning through\n a PersistentVolumeClaim (see EphemeralVolumeSource for more\n information on the connection between this volume type\n and PersistentVolumeClaim).\n\nUse PersistentVolumeClaim or one of the vendor-specific\nAPIs for volumes that persist for longer than the lifecycle\nof an individual pod.\n\nUse CSI for light-weight local ephemeral volumes if the CSI driver is meant to\nbe used that way - see the documentation of the driver for\nmore information.\n\nA pod can use both types of ephemeral volumes and\npersistent volumes at the same time.\n\n+optional", + "$ref": "#/definitions/v1.EphemeralVolumeSource" + }, + "fc": { + "description": "fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.\n+optional", + "$ref": "#/definitions/v1.FCVolumeSource" + }, + "flexVolume": { + "description": "flexVolume represents a generic volume resource that is\nprovisioned/attached using an exec based plugin.\n+optional", + "$ref": "#/definitions/v1.FlexVolumeSource" + }, + "flocker": { + "description": "flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running\n+optional", + "$ref": "#/definitions/v1.FlockerVolumeSource" + }, + "gcePersistentDisk": { + "description": "gcePersistentDisk represents a GCE Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional", + "$ref": "#/definitions/v1.GCEPersistentDiskVolumeSource" + }, + "gitRepo": { + "description": "gitRepo represents a git repository at a particular revision.\nDEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an\nEmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir\ninto the Pod's container.\n+optional", + "$ref": "#/definitions/v1.GitRepoVolumeSource" + }, + "glusterfs": { + "description": "glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md\n+optional", + "$ref": "#/definitions/v1.GlusterfsVolumeSource" + }, + "hostPath": { + "description": "hostPath represents a pre-existing file or directory on the host\nmachine that is directly exposed to the container. This is generally\nused for system agents or other privileged things that are allowed\nto see the host machine. Most containers will NOT need this.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath\n---\nTODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not\nmount host directories as read/write.\n+optional", + "$ref": "#/definitions/v1.HostPathVolumeSource" + }, + "iscsi": { + "description": "iscsi represents an ISCSI Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nMore info: https://examples.k8s.io/volumes/iscsi/README.md\n+optional", + "$ref": "#/definitions/v1.ISCSIVolumeSource" + }, + "name": { + "description": "name of the volume.\nMust be a DNS_LABEL and unique within the pod.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", + "type": "string" + }, + "nfs": { + "description": "nfs represents an NFS mount on the host that shares a pod's lifetime\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs\n+optional", + "$ref": "#/definitions/v1.NFSVolumeSource" + }, + "persistentVolumeClaim": { + "description": "persistentVolumeClaimVolumeSource represents a reference to a\nPersistentVolumeClaim in the same namespace.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims\n+optional", + "$ref": "#/definitions/v1.PersistentVolumeClaimVolumeSource" + }, + "photonPersistentDisk": { + "description": "photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine", + "$ref": "#/definitions/v1.PhotonPersistentDiskVolumeSource" + }, + "portworxVolume": { + "description": "portworxVolume represents a portworx volume attached and mounted on kubelets host machine\n+optional", + "$ref": "#/definitions/v1.PortworxVolumeSource" + }, + "projected": { + "description": "projected items for all in one resources secrets, configmaps, and downward API", + "$ref": "#/definitions/v1.ProjectedVolumeSource" + }, + "quobyte": { + "description": "quobyte represents a Quobyte mount on the host that shares a pod's lifetime\n+optional", + "$ref": "#/definitions/v1.QuobyteVolumeSource" + }, + "rbd": { + "description": "rbd represents a Rados Block Device mount on the host that shares a pod's lifetime.\nMore info: https://examples.k8s.io/volumes/rbd/README.md\n+optional", + "$ref": "#/definitions/v1.RBDVolumeSource" + }, + "scaleIO": { + "description": "scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.\n+optional", + "$ref": "#/definitions/v1.ScaleIOVolumeSource" + }, + "secret": { + "description": "secret represents a secret that should populate this volume.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#secret\n+optional", + "$ref": "#/definitions/v1.SecretVolumeSource" + }, + "storageos": { + "description": "storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.\n+optional", + "$ref": "#/definitions/v1.StorageOSVolumeSource" + }, + "vsphereVolume": { + "description": "vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine\n+optional", + "$ref": "#/definitions/v1.VsphereVirtualDiskVolumeSource" + } + } + }, + "v1.VolumeDevice": { + "type": "object", + "properties": { + "devicePath": { + "description": "devicePath is the path inside of the container that the device will be mapped to.", + "type": "string" + }, + "name": { + "description": "name must match the name of a persistentVolumeClaim in the pod", + "type": "string" + } + } + }, + "v1.VolumeMount": { + "type": "object", + "properties": { + "mountPath": { + "description": "Path within the container at which the volume should be mounted. Must\nnot contain ':'.", + "type": "string" + }, + "mountPropagation": { + "description": "mountPropagation determines how mounts are propagated from the host\nto container and the other way around.\nWhen not set, MountPropagationNone is used.\nThis field is beta in 1.10.\n+optional", + "type": "string" + }, + "name": { + "description": "This must match the Name of a Volume.", + "type": "string" + }, + "readOnly": { + "description": "Mounted read-only if true, read-write otherwise (false or unspecified).\nDefaults to false.\n+optional", + "type": "boolean" + }, + "subPath": { + "description": "Path within the volume from which the container's volume should be mounted.\nDefaults to \"\" (volume's root).\n+optional", + "type": "string" + }, + "subPathExpr": { + "description": "Expanded path within the volume from which the container's volume should be mounted.\nBehaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment.\nDefaults to \"\" (volume's root).\nSubPathExpr and SubPath are mutually exclusive.\n+optional", + "type": "string" + } + } + }, + "v1.VolumeProjection": { + "type": "object", + "properties": { + "configMap": { + "description": "configMap information about the configMap data to project\n+optional", + "$ref": "#/definitions/v1.ConfigMapProjection" + }, + "downwardAPI": { + "description": "downwardAPI information about the downwardAPI data to project\n+optional", + "$ref": "#/definitions/v1.DownwardAPIProjection" + }, + "secret": { + "description": "secret information about the secret data to project\n+optional", + "$ref": "#/definitions/v1.SecretProjection" + }, + "serviceAccountToken": { + "description": "serviceAccountToken is information about the serviceAccountToken data to project\n+optional", + "$ref": "#/definitions/v1.ServiceAccountTokenProjection" + } + } + }, + "v1.VsphereVirtualDiskVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional", + "type": "string" + }, + "storagePolicyID": { + "description": "storagePolicyID is the storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName.\n+optional", + "type": "string" + }, + "storagePolicyName": { + "description": "storagePolicyName is the storage Policy Based Management (SPBM) profile name.\n+optional", + "type": "string" + }, + "volumePath": { + "description": "volumePath is the path that identifies vSphere volume vmdk", + "type": "string" + } + } + }, + "v1.WindowsSecurityContextOptions": { + "type": "object", + "properties": { + "gmsaCredentialSpec": { + "description": "GMSACredentialSpec is where the GMSA admission webhook\n(https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the\nGMSA credential spec named by the GMSACredentialSpecName field.\n+optional", + "type": "string" + }, + "gmsaCredentialSpecName": { + "description": "GMSACredentialSpecName is the name of the GMSA credential spec to use.\n+optional", + "type": "string" + }, + "hostProcess": { + "description": "HostProcess determines if a container should be run as a 'Host Process' container.\nAll of a Pod's containers must have the same effective HostProcess value\n(it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).\nIn addition, if HostProcess is true then HostNetwork must also be set to true.\n+optional", + "type": "boolean" + }, + "runAsUserName": { + "description": "The UserName in Windows to run the entrypoint of the container process.\nDefaults to the user specified in image metadata if unspecified.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\n+optional", + "type": "string" + } + } + }, + "v1alpha1.AWSChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific aws chaos action.\nSupported action: ec2-stop / ec2-restart / detach-volume\nDefault action: ec2-stop\n+kubebuilder:validation:Enum=ec2-stop;ec2-restart;detach-volume", + "type": "string" + }, + "awsRegion": { + "description": "AWSRegion defines the region of aws.", + "type": "string" + }, + "deviceName": { + "description": "DeviceName indicates the name of the device.\nNeeded in detach-volume.\n+ui:form:when=action=='detach-volume'\n+optional", + "type": "string" + }, + "duration": { + "description": "Duration represents the duration of the chaos action.\n+optional", + "type": "string" + }, + "ec2Instance": { + "description": "Ec2Instance indicates the ID of the ec2 instance.", + "type": "string" + }, + "endpoint": { + "description": "Endpoint indicates the endpoint of the aws server. Just used it in test now.\n+ui:form:ignore\n+optional", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "secretName": { + "description": "SecretName defines the name of kubernetes secret.\n+optional", + "type": "string" + }, + "volumeID": { + "description": "EbsVolume indicates the ID of the EBS volume.\nNeeded in detach-volume.\n+ui:form:when=action=='detach-volume'\n+optional", + "type": "string" + } + } + }, + "v1alpha1.AttrOverrideSpec": { + "type": "object", + "properties": { + "atime": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.Timespec" + }, + "blocks": { + "description": "+optional", + "type": "integer" + }, + "ctime": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.Timespec" + }, + "gid": { + "description": "+optional", + "type": "integer" + }, + "ino": { + "description": "+optional", + "type": "integer" + }, + "kind": { + "description": "+optional", + "type": "string" + }, + "mtime": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.Timespec" + }, + "nlink": { + "description": "+optional", + "type": "integer" + }, + "perm": { + "description": "+optional", + "type": "integer" + }, + "rdev": { + "description": "+optional", + "type": "integer" + }, + "size": { + "description": "+optional", + "type": "integer" + }, + "uid": { + "description": "+optional", + "type": "integer" + } + } + }, + "v1alpha1.AzureChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific azure chaos action.\nSupported action: vm-stop / vm-restart / disk-detach\nDefault action: vm-stop\n+kubebuilder:validation:Enum=vm-stop;vm-restart;disk-detach", + "type": "string" + }, + "diskName": { + "description": "DiskName indicates the name of the disk.\nNeeded in disk-detach.\n+optional", + "type": "string" + }, + "duration": { + "description": "Duration represents the duration of the chaos action.\n+optional", + "type": "string" + }, + "lun": { + "description": "LUN indicates the Logical Unit Number of the data disk.\nNeeded in disk-detach.\n+optional", + "type": "integer" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "resourceGroupName": { + "description": "ResourceGroupName defines the name of ResourceGroup", + "type": "string" + }, + "secretName": { + "description": "SecretName defines the name of kubernetes secret. It is used for Azure credentials.\n+optional", + "type": "string" + }, + "subscriptionID": { + "description": "SubscriptionID defines the id of Azure subscription.", + "type": "string" + }, + "vmName": { + "description": "VMName defines the name of Virtual Machine", + "type": "string" + } + } + }, + "v1alpha1.BandwidthSpec": { + "type": "object", + "properties": { + "buffer": { + "description": "Buffer is the maximum amount of bytes that tokens can be available for instantaneously.\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "limit": { + "description": "Limit is the number of bytes that can be queued waiting for tokens to become available.\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "minburst": { + "description": "Minburst specifies the size of the peakrate bucket. For perfect\naccuracy, should be set to the MTU of the interface. If a\npeakrate is needed, but some burstiness is acceptable, this\nsize can be raised. A 3000 byte minburst allows around 3mbit/s\nof peakrate, given 1000 byte packets.\n+optional\n+kubebuilder:validation:Minimum=0", + "type": "integer" + }, + "peakrate": { + "description": "Peakrate is the maximum depletion rate of the bucket.\nThe peakrate does not need to be set, it is only necessary\nif perfect millisecond timescale shaping is required.\n+optional\n+kubebuilder:validation:Minimum=0", + "type": "integer" + }, + "rate": { + "description": "Rate is the speed knob. Allows bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means bytes per second.", + "type": "string" + } + } + }, + "v1alpha1.BlockChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific block chaos action.\nSupported action: delay\n+kubebuilder:validation:Enum=delay", + "type": "string" + }, + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "delay": { + "description": "Delay defines the delay distribution.\n+optional", + "$ref": "#/definitions/v1alpha1.BlockDelaySpec" + }, + "duration": { + "description": "Duration represents the duration of the chaos action.\n+optional", + "type": "string" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "value": { + "description": "Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`.\nIf `FixedMode`, provide an integer of pods to do chaos action.\nIf `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + }, + "volumeName": { + "type": "string" + } + } + }, + "v1alpha1.BlockDelaySpec": { + "type": "object", + "properties": { + "correlation": { + "description": "+optional", + "type": "string", + "default": "0" + }, + "jitter": { + "description": "+optional", + "type": "string", + "default": "0ms" + }, + "latency": { + "description": "Latency defines the latency of every io request.", + "type": "string" + } + } + }, + "v1alpha1.CPUStressor": { + "type": "object", + "properties": { + "load": { + "description": "Load specifies P percent loading per CPU worker. 0 is effectively a sleep (no load) and 100\nis full loading.\n+kubebuilder:validation:Minimum=0\n+kubebuilder:validation:Maximum=100\n+optional", + "type": "integer" + }, + "options": { + "description": "extend stress-ng options\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "workers": { + "description": "Workers specifies N workers to apply the stressor.\nMaximum 8192 workers can run by stress-ng\n+kubebuilder:validation:Maximum=8192", + "type": "integer" + } + } + }, + "v1alpha1.ChaosOnlyScheduleSpec": { + "type": "object", + "properties": { + "awsChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.AWSChaosSpec" + }, + "azureChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.AzureChaosSpec" + }, + "blockChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.BlockChaosSpec" + }, + "concurrencyPolicy": { + "description": "+optional\n+kubebuilder:validation:Enum=Forbid;Allow", + "type": "string" + }, + "dnsChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.DNSChaosSpec" + }, + "gcpChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.GCPChaosSpec" + }, + "historyLimit": { + "description": "+optional\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "httpChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.HTTPChaosSpec" + }, + "ioChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.IOChaosSpec" + }, + "jvmChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.JVMChaosSpec" + }, + "kernelChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.KernelChaosSpec" + }, + "networkChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.NetworkChaosSpec" + }, + "physicalmachineChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.PhysicalMachineChaosSpec" + }, + "podChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.PodChaosSpec" + }, + "schedule": { + "type": "string" + }, + "startingDeadlineSeconds": { + "description": "+optional\n+nullable\n+kubebuilder:validation:Minimum=0", + "type": "integer" + }, + "stressChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.StressChaosSpec" + }, + "timeChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.TimeChaosSpec" + }, + "type": { + "type": "string" + } + } + }, + "v1alpha1.ClockSpec": { + "type": "object", + "properties": { + "clock-ids-slice": { + "description": "the identifier of the particular clock on which to act.\nMore clock description in linux kernel can be found in man page of clock_getres, clock_gettime, clock_settime.\nMuti clock ids should be split with \",\"", + "type": "string" + }, + "pid": { + "description": "the pid of target program.", + "type": "integer" + }, + "time-offset": { + "description": "specifies the length of time offset.", + "type": "string" + } + } + }, + "v1alpha1.ConditionalBranch": { + "type": "object", + "properties": { + "expression": { + "description": "Expression is the expression for this conditional branch, expected type of result is boolean. If expression is empty, this branch will always be selected/the template will be spawned.\n+optional", + "type": "string" + }, + "target": { + "description": "Target is the name of other template, if expression is evaluated as true, this template will be spawned.", + "type": "string" + } + } + }, + "v1alpha1.CorruptSpec": { + "type": "object", + "properties": { + "correlation": { + "description": "+optional", + "type": "string", + "default": "0" + }, + "corrupt": { + "type": "string" + } + } + }, + "v1alpha1.DNSChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific DNS chaos action.\nSupported action: error, random\nDefault action: error\n+kubebuilder:validation:Enum=error;random", + "type": "string" + }, + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "duration": { + "description": "Duration represents the duration of the chaos action", + "type": "string" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "patterns": { + "description": "Choose which domain names to take effect, support the placeholder ? and wildcard *, or the Specified domain name.\nNote:\n 1. The wildcard * must be at the end of the string. For example, chaos-*.org is invalid.\n 2. if the patterns is empty, will take effect on all the domain names.\nFor example:\n\t\tThe value is [\"google.com\", \"github.*\", \"chaos-mes?.org\"],\n\t\twill take effect on \"google.com\", \"github.com\" and \"chaos-mesh.org\"\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "value": { + "description": "Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`.\nIf `FixedMode`, provide an integer of pods to do chaos action.\nIf `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.DelaySpec": { + "type": "object", + "properties": { + "correlation": { + "description": "+optional", + "type": "string", + "default": "0" + }, + "jitter": { + "description": "+optional", + "type": "string", + "default": "0ms" + }, + "latency": { + "type": "string" + }, + "reorder": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.ReorderSpec" + } + } + }, + "v1alpha1.DiskFillSpec": { + "type": "object", + "properties": { + "fill-by-fallocate": { + "description": "fill disk by fallocate", + "type": "boolean" + }, + "path": { + "description": "specifies the location to fill data in. if path not provided,\npayload will read/write from/into a temp file, temp file will be deleted after writing", + "type": "string" + }, + "size": { + "description": "specifies how many units of data will write into the file path. support unit: c=1, w=2, b=512, kB=1000,\nK=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 BYTES. example : 1M | 512kB", + "type": "string" + } + } + }, + "v1alpha1.DiskPayloadSpec": { + "type": "object", + "properties": { + "path": { + "description": "specifies the location to fill data in. if path not provided,\npayload will read/write from/into a temp file, temp file will be deleted after writing", + "type": "string" + }, + "payload-process-num": { + "description": "specifies the number of process work on writing, default 1, only 1-255 is valid value", + "type": "integer" + }, + "size": { + "description": "specifies how many units of data will write into the file path. support unit: c=1, w=2, b=512, kB=1000,\nK=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 BYTES. example : 1M | 512kB", + "type": "string" + } + } + }, + "v1alpha1.DuplicateSpec": { + "type": "object", + "properties": { + "correlation": { + "description": "+optional", + "type": "string", + "default": "0" + }, + "duplicate": { + "type": "string" + } + } + }, + "v1alpha1.FailKernRequest": { + "type": "object", + "properties": { + "callchain": { + "description": "Callchain indicate a special call chain, such as:\n ext4_mount\n -\u003e mount_subtree\n -\u003e ...\n -\u003e should_failslab\nWith an optional set of predicates and an optional set of\nparameters, which used with predicates. You can read call chan\nand predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples\nto learn more.\nIf no special call chain, just keep Callchain empty, which means it will fail at any call chain\nwith slab alloc (eg: kmalloc).", + "type": "array", + "items": { + "$ref": "#/definitions/v1alpha1.Frame" + } + }, + "failtype": { + "description": "FailType indicates what to fail, can be set to '0' / '1' / '2'\nIf `0`, indicates slab to fail (should_failslab)\nIf `1`, indicates alloc_page to fail (should_fail_alloc_page)\nIf `2`, indicates bio to fail (should_fail_bio)\nYou can read:\n 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html\n 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt\nto learn more\n+kubebuilder:validation:Maximum=2\n+kubebuilder:validation:Minimum=0", + "type": "integer" + }, + "headers": { + "description": "Headers indicates the appropriate kernel headers you need.\nEg: \"linux/mmzone.h\", \"linux/blkdev.h\" and so on", + "type": "array", + "items": { + "type": "string" + } + }, + "probability": { + "description": "Probability indicates the fails with probability.\nIf you want 1%, please set this field with 1.\n+kubebuilder:validation:Minimum=0\n+kubebuilder:validation:Maximum=100", + "type": "integer" + }, + "times": { + "description": "Times indicates the max times of fails.\n+kubebuilder:validation:Minimum=0", + "type": "integer" + } + } + }, + "v1alpha1.FileAppendSpec": { + "type": "object", + "properties": { + "count": { + "description": "Count is the number of times to append the data.", + "type": "integer" + }, + "data": { + "description": "Data is the data for append.", + "type": "string" + }, + "file-name": { + "description": "FileName is the name of the file to be created, modified, deleted, renamed, or appended.", + "type": "string" + } + } + }, + "v1alpha1.FileCreateSpec": { + "type": "object", + "properties": { + "dir-name": { + "description": "DirName is the directory name to create or delete.", + "type": "string" + }, + "file-name": { + "description": "FileName is the name of the file to be created, modified, deleted, renamed, or appended.", + "type": "string" + } + } + }, + "v1alpha1.FileDeleteSpec": { + "type": "object", + "properties": { + "dir-name": { + "description": "DirName is the directory name to create or delete.", + "type": "string" + }, + "file-name": { + "description": "FileName is the name of the file to be created, modified, deleted, renamed, or appended.", + "type": "string" + } + } + }, + "v1alpha1.FileModifyPrivilegeSpec": { + "type": "object", + "properties": { + "file-name": { + "description": "FileName is the name of the file to be created, modified, deleted, renamed, or appended.", + "type": "string" + }, + "privilege": { + "description": "Privilege is the file privilege to be set.", + "type": "integer" + } + } + }, + "v1alpha1.FileRenameSpec": { + "type": "object", + "properties": { + "dest-file": { + "description": "DestFile is the name to be renamed.", + "type": "string" + }, + "source-file": { + "description": "SourceFile is the name need to be renamed.", + "type": "string" + } + } + }, + "v1alpha1.FileReplaceSpec": { + "type": "object", + "properties": { + "dest-string": { + "description": "DestStr is the destination string of the file.", + "type": "string" + }, + "file-name": { + "description": "FileName is the name of the file to be created, modified, deleted, renamed, or appended.", + "type": "string" + }, + "line": { + "description": "Line is the line number of the file to be replaced.", + "type": "integer" + }, + "origin-string": { + "description": "OriginStr is the origin string of the file.", + "type": "string" + } + } + }, + "v1alpha1.Frame": { + "type": "object", + "properties": { + "funcname": { + "description": "Funcname can be find from kernel source or `/proc/kallsyms`, such as `ext4_mount`", + "type": "string" + }, + "parameters": { + "description": "Parameters is used with predicate, for example, if you want to inject slab error\nin `d_alloc_parallel(struct dentry *parent, const struct qstr *name)` with a special\nname `bananas`, you need to set it to `struct dentry *parent, const struct qstr *name`\notherwise omit it.", + "type": "string" + }, + "predicate": { + "description": "Predicate will access the arguments of this Frame, example with Parameters's, you can\nset it to `STRNCMP(name-\u003ename, \"bananas\", 8)` to make inject only with it, or omit it\nto inject for all d_alloc_parallel call chain.", + "type": "string" + } + } + }, + "v1alpha1.GCPChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific gcp chaos action.\nSupported action: node-stop / node-reset / disk-loss\nDefault action: node-stop\n+kubebuilder:validation:Enum=node-stop;node-reset;disk-loss", + "type": "string" + }, + "deviceNames": { + "description": "The device name of disks to detach.\nNeeded in disk-loss.\n+ui:form:when=action=='disk-loss'\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "duration": { + "description": "Duration represents the duration of the chaos action.\n+optional", + "type": "string" + }, + "instance": { + "description": "Instance defines the name of the instance", + "type": "string" + }, + "project": { + "description": "Project defines the ID of gcp project.", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "secretName": { + "description": "SecretName defines the name of kubernetes secret. It is used for GCP credentials.\n+optional", + "type": "string" + }, + "zone": { + "description": "Zone defines the zone of gcp project.", + "type": "string" + } + } + }, + "v1alpha1.HTTPAbortSpec": { + "type": "object", + "properties": { + "code": { + "description": "Code is a rule to select target by http status code in response", + "type": "string" + }, + "method": { + "description": "HTTP method", + "type": "string" + }, + "path": { + "description": "Match path of Uri with wildcard matches", + "type": "string" + }, + "port": { + "description": "The TCP port that the target service listens on", + "type": "integer" + }, + "proxy_ports": { + "description": "Composed with one of the port of HTTP connection, we will only attack HTTP connection with port inside proxy_ports", + "type": "array", + "items": { + "type": "integer" + } + }, + "target": { + "description": "HTTP target: Request or Response", + "type": "string" + } + } + }, + "v1alpha1.HTTPChaosSpec": { + "type": "object", + "properties": { + "abort": { + "description": "Abort is a rule to abort a http session.\n+optional", + "type": "boolean" + }, + "code": { + "description": "Code is a rule to select target by http status code in response.\n+optional", + "type": "integer" + }, + "delay": { + "description": "Delay represents the delay of the target request/response.\nA duration string is a possibly unsigned sequence of\ndecimal numbers, each with optional fraction and a unit suffix,\nsuch as \"300ms\", \"2h45m\".\nValid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\n+optional", + "type": "string" + }, + "duration": { + "description": "Duration represents the duration of the chaos action.\n+optional", + "type": "string" + }, + "method": { + "description": "Method is a rule to select target by http method in request.\n+optional", + "type": "string" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "patch": { + "description": "Patch is a rule to patch some contents in target.\n+optional", + "$ref": "#/definitions/v1alpha1.PodHttpChaosPatchActions" + }, + "path": { + "description": "Path is a rule to select target by uri path in http request.\n+optional", + "type": "string" + }, + "port": { + "description": "Port represents the target port to be proxy of.", + "type": "integer" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "replace": { + "description": "Replace is a rule to replace some contents in target.\n+optional", + "$ref": "#/definitions/v1alpha1.PodHttpChaosReplaceActions" + }, + "request_headers": { + "description": "RequestHeaders is a rule to select target by http headers in request.\nThe key-value pairs represent header name and header value pairs.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "response_headers": { + "description": "ResponseHeaders is a rule to select target by http headers in response.\nThe key-value pairs represent header name and header value pairs.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "target": { + "description": "Target is the object to be selected and injected.\n+kubebuilder:validation:Enum=Request;Response", + "type": "string" + }, + "tls": { + "description": "TLS is the tls config,\nwill override PodHttpChaos if there are multiple HTTPChaos experiments are applied\n+optional", + "$ref": "#/definitions/v1alpha1.PodHttpChaosTLS" + }, + "value": { + "description": "Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`.\nIf `FixedMode`, provide an integer of pods to do chaos action.\nIf `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.HTTPConfigSpec": { + "type": "object", + "properties": { + "file_path": { + "description": "The config file path", + "type": "string" + } + } + }, + "v1alpha1.HTTPCriteria": { + "type": "object", + "properties": { + "statusCode": { + "description": "StatusCode defines the expected http status code for the request.\nA statusCode string could be a single code (e.g. 200), or\nan inclusive range (e.g. 200-400, both `200` and `400` are included).", + "type": "string" + } + } + }, + "v1alpha1.HTTPDelaySpec": { + "type": "object", + "properties": { + "code": { + "description": "Code is a rule to select target by http status code in response", + "type": "string" + }, + "delay": { + "description": "Delay represents the delay of the target request/response", + "type": "string" + }, + "method": { + "description": "HTTP method", + "type": "string" + }, + "path": { + "description": "Match path of Uri with wildcard matches", + "type": "string" + }, + "port": { + "description": "The TCP port that the target service listens on", + "type": "integer" + }, + "proxy_ports": { + "description": "Composed with one of the port of HTTP connection, we will only attack HTTP connection with port inside proxy_ports", + "type": "array", + "items": { + "type": "integer" + } + }, + "target": { + "description": "HTTP target: Request or Response", + "type": "string" + } + } + }, + "v1alpha1.HTTPRequestSpec": { + "type": "object", + "properties": { + "count": { + "description": "The number of requests to send", + "type": "integer" + }, + "enable-conn-pool": { + "description": "Enable connection pool", + "type": "boolean" + }, + "url": { + "description": "Request to send\"", + "type": "string" + } + } + }, + "v1alpha1.HTTPStatusCheck": { + "type": "object", + "properties": { + "body": { + "description": "+optional", + "type": "string" + }, + "criteria": { + "description": "Criteria defines how to determine the result of the status check.", + "$ref": "#/definitions/v1alpha1.HTTPCriteria" + }, + "headers": { + "description": "+optional", + "$ref": "#/definitions/http.Header" + }, + "method": { + "description": "+optional\n+kubebuilder:validation:Enum=GET;POST\n+kubebuilder:default=GET", + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "v1alpha1.IOChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific pod chaos action.\nSupported action: latency / fault / attrOverride / mistake\n+kubebuilder:validation:Enum=latency;fault;attrOverride;mistake", + "type": "string" + }, + "attr": { + "description": "Attr defines the overrided attribution\n+ui:form:when=action=='attrOverride'\n+optional", + "$ref": "#/definitions/v1alpha1.AttrOverrideSpec" + }, + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "delay": { + "description": "Delay defines the value of I/O chaos action delay.\nA delay string is a possibly signed sequence of\ndecimal numbers, each with optional fraction and a unit suffix,\nsuch as \"300ms\".\nValid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\n+ui:form:when=action=='latency'\n+optional", + "type": "string" + }, + "duration": { + "description": "Duration represents the duration of the chaos action.\nIt is required when the action is `PodFailureAction`.\nA duration string is a possibly signed sequence of\ndecimal numbers, each with optional fraction and a unit suffix,\nsuch as \"300ms\", \"-1.5h\" or \"2h45m\".\nValid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\n+optional", + "type": "string" + }, + "errno": { + "description": "Errno defines the error code that returned by I/O action.\nrefer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html\n+ui:form:when=action=='fault'\n+optional", + "type": "integer" + }, + "methods": { + "description": "Methods defines the I/O methods for injecting I/O chaos action.\ndefault: all I/O methods.\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "mistake": { + "description": "Mistake defines what types of incorrectness are injected to IO operations\n+ui:form:when=action=='mistake'\n+optional", + "$ref": "#/definitions/v1alpha1.MistakeSpec" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "path": { + "description": "Path defines the path of files for injecting I/O chaos action.\n+optional", + "type": "string" + }, + "percent": { + "description": "Percent defines the percentage of injection errors and provides a number from 0-100.\ndefault: 100.\n+optional\n+kubebuilder:default=100", + "type": "integer" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "value": { + "description": "Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`.\nIf `FixedMode`, provide an integer of pods to do chaos action.\nIf `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + }, + "volumePath": { + "description": "VolumePath represents the mount path of injected volume", + "type": "string" + } + } + }, + "v1alpha1.JVMChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific jvm chaos action.\nSupported action: latency;return;exception;stress;gc;ruleData\n+kubebuilder:validation:Enum=latency;return;exception;stress;gc;ruleData;mysql", + "type": "string" + }, + "class": { + "description": "+optional\nJava class", + "type": "string" + }, + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "cpuCount": { + "description": "+optional\nthe CPU core number needs to use, only set it when action is stress", + "type": "integer" + }, + "database": { + "description": "the match database\ndefault value is \"\", means match all database", + "type": "string" + }, + "duration": { + "description": "Duration represents the duration of the chaos action\n+optional", + "type": "string" + }, + "exception": { + "description": "+optional\nthe exception which needs to throw for action `exception`\nor the exception message needs to throw in action `mysql`", + "type": "string" + }, + "latency": { + "description": "+optional\nthe latency duration for action 'latency', unit ms\nor the latency duration in action `mysql`", + "type": "integer" + }, + "memType": { + "description": "+optional\nthe memory type needs to locate, only set it when action is stress, the value can be 'stack' or 'heap'", + "type": "string" + }, + "method": { + "description": "+optional\nthe method in Java class", + "type": "string" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "mysqlConnectorVersion": { + "description": "the version of mysql-connector-java, only support 5.X.X(set to \"5\") and 8.X.X(set to \"8\") now", + "type": "string" + }, + "name": { + "description": "+optional\nbyteman rule name, should be unique, and will generate one if not set", + "type": "string" + }, + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "ruleData": { + "description": "+optional\nthe byteman rule's data for action 'ruleData'", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "sqlType": { + "description": "the match sql type\ndefault value is \"\", means match all SQL type.\nThe value can be 'select', 'insert', 'update', 'delete', 'replace'.", + "type": "string" + }, + "table": { + "description": "the match table\ndefault value is \"\", means match all table", + "type": "string" + }, + "value": { + "description": "+optional\nthe return value for action 'return'", + "type": "string" + } + } + }, + "v1alpha1.JVMExceptionSpec": { + "type": "object", + "properties": { + "class": { + "description": "+optional\nJava class", + "type": "string" + }, + "exception": { + "description": "the exception which needs to throw for action `exception`", + "type": "string" + }, + "method": { + "description": "+optional\nthe method in Java class", + "type": "string" + }, + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + } + } + }, + "v1alpha1.JVMGCSpec": { + "type": "object", + "properties": { + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + } + } + }, + "v1alpha1.JVMLatencySpec": { + "type": "object", + "properties": { + "class": { + "description": "+optional\nJava class", + "type": "string" + }, + "latency": { + "description": "the latency duration for action 'latency', unit ms", + "type": "integer" + }, + "method": { + "description": "+optional\nthe method in Java class", + "type": "string" + }, + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + } + } + }, + "v1alpha1.JVMReturnSpec": { + "type": "object", + "properties": { + "class": { + "description": "+optional\nJava class", + "type": "string" + }, + "method": { + "description": "+optional\nthe method in Java class", + "type": "string" + }, + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + }, + "value": { + "description": "the return value for action 'return'", + "type": "string" + } + } + }, + "v1alpha1.JVMRuleDataSpec": { + "type": "object", + "properties": { + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + }, + "rule-data": { + "description": "RuleData used to save the rule file's data, will use it when recover", + "type": "string" + } + } + }, + "v1alpha1.JVMStressSpec": { + "type": "object", + "properties": { + "cpu-count": { + "description": "the CPU core number need to use, only set it when action is stress", + "type": "integer" + }, + "mem-type": { + "description": "the memory type need to locate, only set it when action is stress, the value can be 'stack' or 'heap'", + "type": "string" + }, + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + } + } + }, + "v1alpha1.KafkaFillSpec": { + "type": "object", + "properties": { + "host": { + "description": "The host of kafka server", + "type": "string" + }, + "maxBytes": { + "description": "The max bytes to fill", + "type": "integer" + }, + "messageSize": { + "description": "The size of each message", + "type": "integer" + }, + "password": { + "description": "The password of kafka client", + "type": "string" + }, + "port": { + "description": "The port of kafka server", + "type": "integer" + }, + "reloadCommand": { + "description": "The command to reload kafka config", + "type": "string" + }, + "topic": { + "description": "The topic to attack", + "type": "string" + }, + "username": { + "description": "The username of kafka client", + "type": "string" + } + } + }, + "v1alpha1.KafkaFloodSpec": { + "type": "object", + "properties": { + "host": { + "description": "The host of kafka server", + "type": "string" + }, + "messageSize": { + "description": "The size of each message", + "type": "integer" + }, + "password": { + "description": "The password of kafka client", + "type": "string" + }, + "port": { + "description": "The port of kafka server", + "type": "integer" + }, + "threads": { + "description": "The number of worker threads", + "type": "integer" + }, + "topic": { + "description": "The topic to attack", + "type": "string" + }, + "username": { + "description": "The username of kafka client", + "type": "string" + } + } + }, + "v1alpha1.KafkaIOSpec": { + "type": "object", + "properties": { + "configFile": { + "description": "The path of server config", + "type": "string" + }, + "nonReadable": { + "description": "Make kafka cluster non-readable", + "type": "boolean" + }, + "nonWritable": { + "description": "Make kafka cluster non-writable", + "type": "boolean" + }, + "topic": { + "description": "The topic to attack", + "type": "string" + } + } + }, + "v1alpha1.KernelChaosSpec": { + "type": "object", + "properties": { + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "duration": { + "description": "Duration represents the duration of the chaos action", + "type": "string" + }, + "failKernRequest": { + "description": "FailKernRequest defines the request of kernel injection", + "$ref": "#/definitions/v1alpha1.FailKernRequest" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "value": { + "description": "Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`.\nIf `FixedMode`, provide an integer of pods to do chaos action.\nIf `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.LossSpec": { + "type": "object", + "properties": { + "correlation": { + "description": "+optional", + "type": "string", + "default": "0" + }, + "loss": { + "type": "string" + } + } + }, + "v1alpha1.MemoryStressor": { + "type": "object", + "properties": { + "oomScoreAdj": { + "description": "OOMScoreAdj sets the oom_score_adj of the stress process. See `man 5 proc` to know more\nabout this option.\n+kubebuilder:validation:Minimum=-1000\n+kubebuilder:validation:Maximum=1000\n+kubebuilder:default=0\n+optional", + "type": "integer" + }, + "options": { + "description": "extend stress-ng options\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "size": { + "description": "Size specifies N bytes consumed per vm worker, default is the total available memory.\nOne can specify the size as % of total available memory or in units of B, KB/KiB,\nMB/MiB, GB/GiB, TB/TiB.\n+optional", + "type": "string" + }, + "workers": { + "description": "Workers specifies N workers to apply the stressor.\nMaximum 8192 workers can run by stress-ng\n+kubebuilder:validation:Maximum=8192", + "type": "integer" + } + } + }, + "v1alpha1.MistakeSpec": { + "type": "object", + "properties": { + "filling": { + "description": "Filling determines what is filled in the mistake data.\n+optional\n+kubebuilder:validation:Enum=zero;random", + "type": "string" + }, + "maxLength": { + "description": "Max length of each wrong data segment in bytes\n+optional\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "maxOccurrences": { + "description": "There will be [1, MaxOccurrences] segments of wrong data.\n+optional\n+kubebuilder:validation:Minimum=1", + "type": "integer" + } + } + }, + "v1alpha1.NetworkBandwidthSpec": { + "type": "object", + "properties": { + "buffer": { + "description": "+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "device": { + "type": "string" + }, + "hostname": { + "type": "string" + }, + "ip-address": { + "type": "string" + }, + "limit": { + "description": "+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "minburst": { + "type": "integer" + }, + "peakrate": { + "type": "integer" + }, + "rate": { + "type": "string" + } + } + }, + "v1alpha1.NetworkChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific network chaos action.\nSupported action: partition, netem, delay, loss, duplicate, corrupt\nDefault action: delay\n+kubebuilder:validation:Enum=netem;delay;loss;duplicate;corrupt;partition;bandwidth", + "type": "string" + }, + "bandwidth": { + "description": "Bandwidth represents the detail about bandwidth control action\n+ui:form:when=action=='bandwidth'\n+optional", + "$ref": "#/definitions/v1alpha1.BandwidthSpec" + }, + "corrupt": { + "description": "Corrupt represents the detail about corrupt action\n+ui:form:when=action=='corrupt'\n+optional", + "$ref": "#/definitions/v1alpha1.CorruptSpec" + }, + "delay": { + "description": "Delay represents the detail about delay action\n+ui:form:when=action=='delay'\n+optional", + "$ref": "#/definitions/v1alpha1.DelaySpec" + }, + "device": { + "description": "Device represents the network device to be affected.\n+optional", + "type": "string" + }, + "direction": { + "description": "Direction represents the direction, this applies on netem and network partition action\n+optional\n+kubebuilder:validation:Enum=to;from;both\n+kubebuilder:default=to", + "type": "string" + }, + "duplicate": { + "description": "DuplicateSpec represents the detail about loss action\n+ui:form:when=action=='duplicate'\n+optional", + "$ref": "#/definitions/v1alpha1.DuplicateSpec" + }, + "duration": { + "description": "Duration represents the duration of the chaos action", + "type": "string" + }, + "externalTargets": { + "description": "ExternalTargets represents network targets outside k8s\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "loss": { + "description": "Loss represents the detail about loss action\n+ui:form:when=action=='loss'\n+optional", + "$ref": "#/definitions/v1alpha1.LossSpec" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "rate": { + "description": "Rate represents the detail about rate control action\n+ui:form:when=action=='rate'\n+optional", + "$ref": "#/definitions/v1alpha1.RateSpec" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "target": { + "description": "Target represents network target, this applies on netem and network partition action\n+optional", + "$ref": "#/definitions/v1alpha1.PodSelector" + }, + "targetDevice": { + "description": "TargetDevice represents the network device to be affected in target scope.\n+optional", + "type": "string" + }, + "value": { + "description": "Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`.\nIf `FixedMode`, provide an integer of pods to do chaos action.\nIf `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.NetworkCorruptSpec": { + "type": "object", + "properties": { + "correlation": { + "description": "correlation is percentage (10 is 10%)", + "type": "string" + }, + "device": { + "description": "the network interface to impact", + "type": "string" + }, + "egress-port": { + "description": "only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + }, + "hostname": { + "description": "only impact traffic to these hostnames", + "type": "string" + }, + "ip-address": { + "description": "only impact egress traffic to these IP addresses", + "type": "string" + }, + "ip-protocol": { + "description": "only impact traffic using this IP protocol, supported: tcp, udp, icmp, all", + "type": "string" + }, + "percent": { + "description": "percentage of packets to corrupt (10 is 10%)", + "type": "string" + }, + "source-port": { + "description": "only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + } + } + }, + "v1alpha1.NetworkDNSSpec": { + "type": "object", + "properties": { + "dns-domain-name": { + "description": "map this host to specified IP", + "type": "string" + }, + "dns-ip": { + "description": "map specified host to this IP address", + "type": "string" + }, + "dns-server": { + "description": "update the DNS server in /etc/resolv.conf with this value", + "type": "string" + } + } + }, + "v1alpha1.NetworkDelaySpec": { + "type": "object", + "properties": { + "accept-tcp-flags": { + "description": "only the packet which match the tcp flag can be accepted, others will be dropped.\nonly set when the IPProtocol is tcp, used for partition.", + "type": "string" + }, + "correlation": { + "description": "correlation is percentage (10 is 10%)", + "type": "string" + }, + "device": { + "description": "the network interface to impact", + "type": "string" + }, + "egress-port": { + "description": "only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + }, + "hostname": { + "description": "only impact traffic to these hostnames", + "type": "string" + }, + "ip-address": { + "description": "only impact egress traffic to these IP addresses", + "type": "string" + }, + "ip-protocol": { + "description": "only impact traffic using this IP protocol, supported: tcp, udp, icmp, all", + "type": "string" + }, + "jitter": { + "description": "jitter time, time units: ns, us (or µs), ms, s, m, h.", + "type": "string" + }, + "latency": { + "description": "delay egress time, time units: ns, us (or µs), ms, s, m, h.", + "type": "string" + }, + "source-port": { + "description": "only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + } + } + }, + "v1alpha1.NetworkDownSpec": { + "type": "object", + "properties": { + "device": { + "description": "The network interface to impact", + "type": "string" + }, + "duration": { + "description": "NIC down time, time units: ns, us (or µs), ms, s, m, h.", + "type": "string" + } + } + }, + "v1alpha1.NetworkDuplicateSpec": { + "type": "object", + "properties": { + "correlation": { + "description": "correlation is percentage (10 is 10%)", + "type": "string" + }, + "device": { + "description": "the network interface to impact", + "type": "string" + }, + "egress-port": { + "description": "only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + }, + "hostname": { + "description": "only impact traffic to these hostnames", + "type": "string" + }, + "ip-address": { + "description": "only impact egress traffic to these IP addresses", + "type": "string" + }, + "ip-protocol": { + "description": "only impact traffic using this IP protocol, supported: tcp, udp, icmp, all", + "type": "string" + }, + "percent": { + "description": "percentage of packets to duplicate (10 is 10%)", + "type": "string" + }, + "source-port": { + "description": "only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + } + } + }, + "v1alpha1.NetworkFloodSpec": { + "type": "object", + "properties": { + "duration": { + "description": "The number of seconds to run the iperf test", + "type": "string" + }, + "ip-address": { + "description": "Generate traffic to this IP address", + "type": "string" + }, + "parallel": { + "description": "The number of iperf parallel client threads to run", + "type": "integer" + }, + "port": { + "description": "Generate traffic to this port on the IP address", + "type": "string" + }, + "rate": { + "description": "The speed of network traffic, allows bps, kbps, mbps, gbps, tbps unit. bps means bytes per second", + "type": "string" + } + } + }, + "v1alpha1.NetworkLossSpec": { + "type": "object", + "properties": { + "correlation": { + "description": "correlation is percentage (10 is 10%)", + "type": "string" + }, + "device": { + "description": "the network interface to impact", + "type": "string" + }, + "egress-port": { + "description": "only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + }, + "hostname": { + "description": "only impact traffic to these hostnames", + "type": "string" + }, + "ip-address": { + "description": "only impact egress traffic to these IP addresses", + "type": "string" + }, + "ip-protocol": { + "description": "only impact traffic using this IP protocol, supported: tcp, udp, icmp, all", + "type": "string" + }, + "percent": { + "description": "percentage of packets to loss (10 is 10%)", + "type": "string" + }, + "source-port": { + "description": "only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010.\nit can only be used in conjunction with -p tcp or -p udp", + "type": "string" + } + } + }, + "v1alpha1.NetworkPartitionSpec": { + "type": "object", + "properties": { + "accept-tcp-flags": { + "description": "only the packet which match the tcp flag can be accepted, others will be dropped.\nonly set when the IPProtocol is tcp, used for partition.", + "type": "string" + }, + "device": { + "description": "the network interface to impact", + "type": "string" + }, + "direction": { + "description": "specifies the partition direction, values can be 'from', 'to'.\n'from' means packets coming from the 'IPAddress' or 'Hostname' and going to your server,\n'to' means packets originating from your server and going to the 'IPAddress' or 'Hostname'.", + "type": "string" + }, + "hostname": { + "description": "only impact traffic to these hostnames", + "type": "string" + }, + "ip-address": { + "description": "only impact egress traffic to these IP addresses", + "type": "string" + }, + "ip-protocol": { + "description": "only impact egress traffic to these IP addresses", + "type": "string" + } + } + }, + "v1alpha1.PMJVMMySQLSpec": { + "type": "object", + "properties": { + "database": { + "description": "the match database\ndefault value is \"\", means match all database", + "type": "string" + }, + "exception": { + "description": "The exception which needs to throw for action `exception`\nor the exception message needs to throw in action `mysql`", + "type": "string" + }, + "latency": { + "description": "The latency duration for action 'latency'\nor the latency duration in action `mysql`", + "type": "integer" + }, + "mysqlConnectorVersion": { + "description": "the version of mysql-connector-java, only support 5.X.X(set to \"5\") and 8.X.X(set to \"8\") now", + "type": "string" + }, + "pid": { + "description": "the pid of Java process which needs to attach", + "type": "integer" + }, + "port": { + "description": "+optional\nthe port of agent server, default 9277", + "type": "integer" + }, + "sqlType": { + "description": "the match sql type\ndefault value is \"\", means match all SQL type.\nThe value can be 'select', 'insert', 'update', 'delete', 'replace'.", + "type": "string" + }, + "table": { + "description": "the match table\ndefault value is \"\", means match all table", + "type": "string" + } + } + }, + "v1alpha1.PhysicalMachineChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "+kubebuilder:validation:Enum=stress-cpu;stress-mem;disk-read-payload;disk-write-payload;disk-fill;network-corrupt;network-duplicate;network-loss;network-delay;network-partition;network-dns;network-bandwidth;network-flood;network-down;process;jvm-exception;jvm-gc;jvm-latency;jvm-return;jvm-stress;jvm-rule-data;jvm-mysql;clock;redis-expiration;redis-penetration;redis-cacheLimit;redis-restart;redis-stop;kafka-fill;kafka-flood;kafka-io;file-create;file-modify;file-delete;file-rename;file-append;file-replace;vm;user_defined", + "type": "string" + }, + "address": { + "description": "DEPRECATED: Use Selector instead.\nOnly one of Address and Selector could be specified.\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "clock": { + "description": "+ui:form:when=action=='clock'\n+optional", + "$ref": "#/definitions/v1alpha1.ClockSpec" + }, + "disk-fill": { + "description": "+ui:form:when=action=='disk-fill'\n+optional", + "$ref": "#/definitions/v1alpha1.DiskFillSpec" + }, + "disk-read-payload": { + "description": "+ui:form:when=action=='disk-read-payload'\n+optional", + "$ref": "#/definitions/v1alpha1.DiskPayloadSpec" + }, + "disk-write-payload": { + "description": "+ui:form:when=action=='disk-write-payload'\n+optional", + "$ref": "#/definitions/v1alpha1.DiskPayloadSpec" + }, + "duration": { + "description": "Duration represents the duration of the chaos action\n+optional", + "type": "string" + }, + "file-append": { + "description": "+ui:form:when=action=='file-append'\n+optional", + "$ref": "#/definitions/v1alpha1.FileAppendSpec" + }, + "file-create": { + "description": "+ui:form:when=action=='file-create'\n+optional", + "$ref": "#/definitions/v1alpha1.FileCreateSpec" + }, + "file-delete": { + "description": "+ui:form:when=action=='file-delete'\n+optional", + "$ref": "#/definitions/v1alpha1.FileDeleteSpec" + }, + "file-modify": { + "description": "+ui:form:when=action=='file-modify'\n+optional", + "$ref": "#/definitions/v1alpha1.FileModifyPrivilegeSpec" + }, + "file-rename": { + "description": "+ui:form:when=action=='file-create'\n+optional", + "$ref": "#/definitions/v1alpha1.FileRenameSpec" + }, + "file-replace": { + "description": "+ui:form:when=action=='file-replace'\n+optional", + "$ref": "#/definitions/v1alpha1.FileReplaceSpec" + }, + "http-abort": { + "description": "+ui:form:when=action=='http-abort'\n+optional", + "$ref": "#/definitions/v1alpha1.HTTPAbortSpec" + }, + "http-config": { + "description": "+ui:form:when=action=='http-config'\n+optional", + "$ref": "#/definitions/v1alpha1.HTTPConfigSpec" + }, + "http-delay": { + "description": "+ui:form:when=action=='http-delay'\n+optional", + "$ref": "#/definitions/v1alpha1.HTTPDelaySpec" + }, + "http-request": { + "description": "+ui:form:when=action=='http-request'\n+optional", + "$ref": "#/definitions/v1alpha1.HTTPRequestSpec" + }, + "jvm-exception": { + "description": "+ui:form:when=action=='jvm-exception'\n+optional", + "$ref": "#/definitions/v1alpha1.JVMExceptionSpec" + }, + "jvm-gc": { + "description": "+ui:form:when=action=='jvm-gc'\n+optional", + "$ref": "#/definitions/v1alpha1.JVMGCSpec" + }, + "jvm-latency": { + "description": "+ui:form:when=action=='jvm-latency'\n+optional", + "$ref": "#/definitions/v1alpha1.JVMLatencySpec" + }, + "jvm-mysql": { + "description": "+ui:form:when=action=='jvm-mysql'\n+optional", + "$ref": "#/definitions/v1alpha1.PMJVMMySQLSpec" + }, + "jvm-return": { + "description": "+ui:form:when=action=='jvm-return'\n+optional", + "$ref": "#/definitions/v1alpha1.JVMReturnSpec" + }, + "jvm-rule-data": { + "description": "+ui:form:when=action=='jvm-rule-data'\n+optional", + "$ref": "#/definitions/v1alpha1.JVMRuleDataSpec" + }, + "jvm-stress": { + "description": "+ui:form:when=action=='jvm-stress'\n+optional", + "$ref": "#/definitions/v1alpha1.JVMStressSpec" + }, + "kafka-fill": { + "description": "+ui:form:when=action=='kafka-fill'\n+optional", + "$ref": "#/definitions/v1alpha1.KafkaFillSpec" + }, + "kafka-flood": { + "description": "+ui:form:when=action=='kafka-flood'\n+optional", + "$ref": "#/definitions/v1alpha1.KafkaFloodSpec" + }, + "kafka-io": { + "description": "+ui:form:when=action=='kafka-io'\n+optional", + "$ref": "#/definitions/v1alpha1.KafkaIOSpec" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "network-bandwidth": { + "description": "+ui:form:when=action=='network-bandwidth'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkBandwidthSpec" + }, + "network-corrupt": { + "description": "+ui:form:when=action=='network-corrupt'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkCorruptSpec" + }, + "network-delay": { + "description": "+ui:form:when=action=='network-delay'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkDelaySpec" + }, + "network-dns": { + "description": "+ui:form:when=action=='network-dns'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkDNSSpec" + }, + "network-down": { + "description": "+ui:form:when=action=='network-down'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkDownSpec" + }, + "network-duplicate": { + "description": "+ui:form:when=action=='network-duplicate'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkDuplicateSpec" + }, + "network-flood": { + "description": "+ui:form:when=action=='network-flood'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkFloodSpec" + }, + "network-loss": { + "description": "+ui:form:when=action=='network-loss'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkLossSpec" + }, + "network-partition": { + "description": "+ui:form:when=action=='network-partition'\n+optional", + "$ref": "#/definitions/v1alpha1.NetworkPartitionSpec" + }, + "process": { + "description": "+ui:form:when=action=='process'\n+optional", + "$ref": "#/definitions/v1alpha1.ProcessSpec" + }, + "redis-cacheLimit": { + "description": "+ui:form:when=action=='redis-cacheLimit'\n+optional", + "$ref": "#/definitions/v1alpha1.RedisCacheLimitSpec" + }, + "redis-expiration": { + "description": "+ui:form:when=action=='redis-expiration'\n+optional", + "$ref": "#/definitions/v1alpha1.RedisExpirationSpec" + }, + "redis-penetration": { + "description": "+ui:form:when=action=='redis-penetration'\n+optional", + "$ref": "#/definitions/v1alpha1.RedisPenetrationSpec" + }, + "redis-restart": { + "description": "+ui:form:when=action=='redis-restart'\n+optional", + "$ref": "#/definitions/v1alpha1.RedisSentinelRestartSpec" + }, + "redis-stop": { + "description": "+ui:form:when=action=='redis-stop'\n+optional", + "$ref": "#/definitions/v1alpha1.RedisSentinelStopSpec" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select physical machines that are used to inject chaos action.\n+optional", + "$ref": "#/definitions/v1alpha1.PhysicalMachineSelectorSpec" + }, + "stress-cpu": { + "description": "+ui:form:when=action=='stress-cpu'\n+optional", + "$ref": "#/definitions/v1alpha1.StressCPUSpec" + }, + "stress-mem": { + "description": "+ui:form:when=action=='stress-mem'\n+optional", + "$ref": "#/definitions/v1alpha1.StressMemorySpec" + }, + "user_defined": { + "description": "+ui:form:when=action=='user_defined'\n+optional", + "$ref": "#/definitions/v1alpha1.UserDefinedSpec" + }, + "value": { + "description": "Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`.\nIf `FixedMode`, provide an integer of physical machines to do chaos action.\nIf `FixedPercentMode`, provide a number from 0-100 to specify the percent of physical machines the server can do chaos action.\nIF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + }, + "vm": { + "description": "+ui:form:when=action=='vm'\n+optional", + "$ref": "#/definitions/v1alpha1.VMSpec" + } + } + }, + "v1alpha1.PhysicalMachineSelectorSpec": { + "type": "object", + "properties": { + "annotationSelectors": { + "description": "Map of string keys and values that can be used to select objects.\nA selector based on annotations.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "fieldSelectors": { + "description": "Map of string keys and values that can be used to select objects.\nA selector based on fields.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labelSelectors": { + "description": "Map of string keys and values that can be used to select objects.\nA selector based on labels.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "namespaces": { + "description": "Namespaces is a set of namespace to which objects belong.\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "physicalMachines": { + "description": "PhysicalMachines is a map of string keys and a set values that used to select physical machines.\nThe key defines the namespace which physical machine belong,\nand each value is a set of physical machine names.\n+optional", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "v1alpha1.PodChaosSpec": { + "type": "object", + "properties": { + "action": { + "description": "Action defines the specific pod chaos action.\nSupported action: pod-kill / pod-failure / container-kill\nDefault action: pod-kill\n+kubebuilder:validation:Enum=pod-kill;pod-failure;container-kill", + "type": "string" + }, + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "duration": { + "description": "Duration represents the duration of the chaos action.\nIt is required when the action is `PodFailureAction`.\nA duration string is a possibly signed sequence of\ndecimal numbers, each with optional fraction and a unit suffix,\nsuch as \"300ms\", \"-1.5h\" or \"2h45m\".\nValid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\n+optional", + "type": "string" + }, + "gracePeriod": { + "description": "GracePeriod is used in pod-kill action. It represents the duration in seconds before the pod should be deleted.\nValue must be non-negative integer. The default value is zero that indicates delete immediately.\n+optional\n+kubebuilder:validation:Minimum=0", + "type": "integer" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "value": { + "description": "Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`.\nIf `FixedMode`, provide an integer of pods to do chaos action.\nIf `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.PodHttpChaosPatchActions": { + "type": "object", + "properties": { + "body": { + "description": "Body is a rule to patch message body of target.\n+optional", + "$ref": "#/definitions/v1alpha1.PodHttpChaosPatchBodyAction" + }, + "headers": { + "description": "Headers is a rule to append http headers of target.\nFor example: `[[\"Set-Cookie\", \"\u003cone cookie\u003e\"], [\"Set-Cookie\", \"\u003canother cookie\u003e\"]]`.\n+optional", + "type": "array", + "items": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "queries": { + "description": "Queries is a rule to append uri queries of target(Request only).\nFor example: `[[\"foo\", \"bar\"], [\"foo\", \"unknown\"]]`.\n+optional", + "type": "array", + "items": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "v1alpha1.PodHttpChaosPatchBodyAction": { + "type": "object", + "properties": { + "type": { + "description": "Type represents the patch type, only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) currently.", + "type": "string" + }, + "value": { + "description": "Value is the patch contents.", + "type": "string" + } + } + }, + "v1alpha1.PodHttpChaosReplaceActions": { + "type": "object", + "properties": { + "body": { + "description": "Body is a rule to replace http message body in target.\n+optional", + "type": "array", + "items": { + "type": "integer" + } + }, + "code": { + "description": "Code is a rule to replace http status code in response.\n+optional", + "type": "integer" + }, + "headers": { + "description": "Headers is a rule to replace http headers of target.\nThe key-value pairs represent header name and header value pairs.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "method": { + "description": "Method is a rule to replace http method in request.\n+optional", + "type": "string" + }, + "path": { + "description": "Path is rule to to replace uri path in http request.\n+optional", + "type": "string" + }, + "queries": { + "description": "Queries is a rule to replace uri queries in http request.\nFor example, with value `{ \"foo\": \"unknown\" }`, the `/?foo=bar` will be altered to `/?foo=unknown`,\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "v1alpha1.PodHttpChaosTLS": { + "type": "object", + "properties": { + "caName": { + "description": "CAName represents the data name of ca file in secret, `ca.crt` for example\n+optional", + "type": "string" + }, + "certName": { + "description": "CertName represents the data name of cert file in secret, `tls.crt` for example", + "type": "string" + }, + "keyName": { + "description": "KeyName represents the data name of key file in secret, `tls.key` for example", + "type": "string" + }, + "secretName": { + "description": "SecretName represents the name of required secret resource", + "type": "string" + }, + "secretNamespace": { + "description": "SecretNamespace represents the namespace of required secret resource", + "type": "string" + } + } + }, + "v1alpha1.PodSelector": { + "type": "object", + "properties": { + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "value": { + "description": "Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`.\nIf `FixedMode`, provide an integer of pods to do chaos action.\nIf `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.PodSelectorSpec": { + "type": "object", + "properties": { + "annotationSelectors": { + "description": "Map of string keys and values that can be used to select objects.\nA selector based on annotations.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "fieldSelectors": { + "description": "Map of string keys and values that can be used to select objects.\nA selector based on fields.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labelSelectors": { + "description": "Map of string keys and values that can be used to select objects.\nA selector based on labels.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "namespaces": { + "description": "Namespaces is a set of namespace to which objects belong.\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "nodeSelectors": { + "description": "Map of string keys and values that can be used to select nodes.\nSelector which must match a node's labels,\nand objects must belong to these selected nodes.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "nodes": { + "description": "Nodes is a set of node name and objects must belong to these nodes.\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "podPhaseSelectors": { + "description": "PodPhaseSelectors is a set of condition of a pod at the current time.\nsupported value: Pending / Running / Succeeded / Failed / Unknown\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "pods": { + "description": "Pods is a map of string keys and a set values that used to select pods.\nThe key defines the namespace which pods belong,\nand the each values is a set of pod names.\n+optional", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "v1alpha1.ProcessSpec": { + "type": "object", + "properties": { + "process": { + "description": "the process name or the process ID", + "type": "string" + }, + "recoverCmd": { + "description": "the command to be run when recovering experiment", + "type": "string" + }, + "signal": { + "description": "the signal number to send", + "type": "integer" + } + } + }, + "v1alpha1.RateSpec": { + "type": "object", + "properties": { + "rate": { + "description": "Rate is the speed knob. Allows bit, kbit, mbit, gbit, tbit, bps, kbps, mbps, gbps, tbps unit. bps means bytes per second.", + "type": "string" + } + } + }, + "v1alpha1.RedisCacheLimitSpec": { + "type": "object", + "properties": { + "addr": { + "description": "The adress of Redis server", + "type": "string" + }, + "cacheSize": { + "description": "The size of `maxmemory`", + "type": "string" + }, + "password": { + "description": "The password of Redis server", + "type": "string" + }, + "percent": { + "description": "Specifies maxmemory as a percentage of the original value", + "type": "string" + } + } + }, + "v1alpha1.RedisExpirationSpec": { + "type": "object", + "properties": { + "addr": { + "description": "The adress of Redis server", + "type": "string" + }, + "expiration": { + "description": "The expiration of the keys", + "type": "string" + }, + "key": { + "description": "The keys to be expired", + "type": "string" + }, + "option": { + "description": "Additional options for `expiration`", + "type": "string" + }, + "password": { + "description": "The password of Redis server", + "type": "string" + } + } + }, + "v1alpha1.RedisPenetrationSpec": { + "type": "object", + "properties": { + "addr": { + "description": "The adress of Redis server", + "type": "string" + }, + "password": { + "description": "The password of Redis server", + "type": "string" + }, + "requestNum": { + "description": "The number of requests to be sent", + "type": "integer" + } + } + }, + "v1alpha1.RedisSentinelRestartSpec": { + "type": "object", + "properties": { + "addr": { + "description": "The adress of Redis server", + "type": "string" + }, + "conf": { + "description": "The path of Sentinel conf", + "type": "string" + }, + "flushConfig": { + "description": "The control flag determines whether to flush config", + "type": "boolean" + }, + "password": { + "description": "The password of Redis server", + "type": "string" + }, + "redisPath": { + "description": "The path of `redis-server` command-line tool", + "type": "boolean" + } + } + }, + "v1alpha1.RedisSentinelStopSpec": { + "type": "object", + "properties": { + "addr": { + "description": "The adress of Redis server", + "type": "string" + }, + "conf": { + "description": "The path of Sentinel conf", + "type": "string" + }, + "flushConfig": { + "description": "The control flag determines whether to flush config", + "type": "boolean" + }, + "password": { + "description": "The password of Redis server", + "type": "string" + }, + "redisPath": { + "description": "The path of `redis-server` command-line tool", + "type": "boolean" + } + } + }, + "v1alpha1.ReorderSpec": { + "type": "object", + "properties": { + "correlation": { + "description": "+optional", + "type": "string", + "default": "0" + }, + "gap": { + "type": "integer" + }, + "reorder": { + "type": "string" + } + } + }, + "v1alpha1.Schedule": { + "type": "object", + "properties": { + "annotations": { + "description": "Annotations is an unstructured key value map stored with a resource that may be\nset by external tools to store and retrieve arbitrary metadata. They are not\nqueryable and should be preserved when modifying objects.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "creationTimestamp": { + "description": "CreationTimestamp is a timestamp representing the server time when this object was\ncreated. It is not guaranteed to be set in happens-before order across separate operations.\nClients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system.\nRead-only.\nNull for lists.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "type": "string" + }, + "deletionGracePeriodSeconds": { + "description": "Number of seconds allowed for this object to gracefully terminate before\nit will be removed from the system. Only set when deletionTimestamp is also set.\nMay only be shortened.\nRead-only.\n+optional", + "type": "integer" + }, + "deletionTimestamp": { + "description": "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This\nfield is set by the server when a graceful deletion is requested by the user, and is not\ndirectly settable by a client. The resource is expected to be deleted (no longer visible\nfrom resource lists, and not reachable by name) after the time in this field, once the\nfinalizers list is empty. As long as the finalizers list contains items, deletion is blocked.\nOnce the deletionTimestamp is set, this value may not be unset or be set further into the\nfuture, although it may be shortened or the resource may be deleted prior to this time.\nFor example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react\nby sending a graceful termination signal to the containers in the pod. After that 30 seconds,\nthe Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,\nremove the pod from the API. In the presence of network partitions, this object may still\nexist after this timestamp, until an administrator or automated process can determine the\nresource is fully terminated.\nIf not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested.\nRead-only.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "type": "string" + }, + "finalizers": { + "description": "Must be empty before the object is deleted from the registry. Each entry\nis an identifier for the responsible component that will remove the entry\nfrom the list. If the deletionTimestamp of the object is non-nil, entries\nin this list can only be removed.\nFinalizers may be processed and removed in any order. Order is NOT enforced\nbecause it introduces significant risk of stuck finalizers.\nfinalizers is a shared field, any actor with permission can reorder it.\nIf the finalizer list is processed in order, then this can lead to a situation\nin which the component responsible for the first finalizer in the list is\nwaiting for a signal (field value, external system, or other) produced by a\ncomponent responsible for a finalizer later in the list, resulting in a deadlock.\nWithout enforced ordering finalizers are free to order amongst themselves and\nare not vulnerable to ordering changes in the list.\n+optional\n+patchStrategy=merge", + "type": "array", + "items": { + "type": "string" + } + }, + "generateName": { + "description": "GenerateName is an optional prefix, used by the server, to generate a unique\nname ONLY IF the Name field has not been provided.\nIf this field is used, the name returned to the client will be different\nthan the name passed. This value will also be combined with a unique suffix.\nThe provided value has the same validation rules as the Name field,\nand may be truncated by the length of the suffix required to make the value\nunique on the server.\n\nIf this field is specified and the generated name exists, the server will return a 409.\n\nApplied only if Name is not specified.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency\n+optional", + "type": "string" + }, + "generation": { + "description": "A sequence number representing a specific generation of the desired state.\nPopulated by the system. Read-only.\n+optional", + "type": "integer" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "labels": { + "description": "Map of string keys and values that can be used to organize and categorize\n(scope and select) objects. May match selectors of replication controllers\nand services.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "managedFields": { + "description": "ManagedFields maps workflow-id and version to the set of fields\nthat are managed by that workflow. This is mostly for internal\nhousekeeping, and users typically shouldn't need to set or\nunderstand this field. A workflow can be the user's name, a\ncontroller's name, or the name of a specific apply path like\n\"ci-cd\". The set of fields is always in the version that the\nworkflow used when modifying the object.\n\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ManagedFieldsEntry" + } + }, + "name": { + "description": "Name must be unique within a namespace. Is required when creating resources, although\nsome resources may allow a client to request the generation of an appropriate name\nautomatically. Name is primarily intended for creation idempotence and configuration\ndefinition.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names\n+optional", + "type": "string" + }, + "namespace": { + "description": "Namespace defines the space within which each name must be unique. An empty namespace is\nequivalent to the \"default\" namespace, but \"default\" is the canonical representation.\nNot all objects are required to be scoped to a namespace - the value of this field for\nthose objects will be empty.\n\nMust be a DNS_LABEL.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces\n+optional", + "type": "string" + }, + "ownerReferences": { + "description": "List of objects depended by this object. If ALL objects in the list have\nbeen deleted, this object will be garbage collected. If this object is managed by a controller,\nthen an entry in this list will point to this controller, with the controller field set to true.\nThere cannot be more than one managing controller.\n+optional\n+patchMergeKey=uid\n+patchStrategy=merge", + "type": "array", + "items": { + "$ref": "#/definitions/v1.OwnerReference" + } + }, + "resourceVersion": { + "description": "An opaque value that represents the internal version of this object that can\nbe used by clients to determine when objects have changed. May be used for optimistic\nconcurrency, change detection, and the watch operation on a resource or set of resources.\nClients must treat these values as opaque and passed unmodified back to the server.\nThey may only be valid for a particular resource or set of resources.\n\nPopulated by the system.\nRead-only.\nValue must be treated as opaque by clients and .\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency\n+optional", + "type": "string" + }, + "selfLink": { + "description": "Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.\n+optional", + "type": "string" + }, + "spec": { + "$ref": "#/definitions/v1alpha1.ScheduleSpec" + }, + "status": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.ScheduleStatus" + }, + "uid": { + "description": "UID is the unique in time and space value for this object. It is typically generated by\nthe server on successful creation of a resource and is not allowed to change on PUT\noperations.\n\nPopulated by the system.\nRead-only.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids\n+optional", + "type": "string" + } + } + }, + "v1alpha1.ScheduleSpec": { + "type": "object", + "properties": { + "awsChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.AWSChaosSpec" + }, + "azureChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.AzureChaosSpec" + }, + "blockChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.BlockChaosSpec" + }, + "concurrencyPolicy": { + "description": "+optional\n+kubebuilder:default=Forbid\n+kubebuilder:validation:Enum=Forbid;Allow", + "type": "string" + }, + "dnsChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.DNSChaosSpec" + }, + "gcpChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.GCPChaosSpec" + }, + "historyLimit": { + "description": "+optional\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "httpChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.HTTPChaosSpec" + }, + "ioChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.IOChaosSpec" + }, + "jvmChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.JVMChaosSpec" + }, + "kernelChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.KernelChaosSpec" + }, + "networkChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.NetworkChaosSpec" + }, + "physicalmachineChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.PhysicalMachineChaosSpec" + }, + "podChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.PodChaosSpec" + }, + "schedule": { + "type": "string" + }, + "startingDeadlineSeconds": { + "description": "+optional\n+nullable\n+kubebuilder:validation:Minimum=0\n+kubebuilder:validation:ExclusiveMinimum=true", + "type": "integer" + }, + "stressChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.StressChaosSpec" + }, + "timeChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.TimeChaosSpec" + }, + "type": { + "type": "string" + }, + "workflow": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.WorkflowSpec" + } + } + }, + "v1alpha1.ScheduleStatus": { + "type": "object", + "properties": { + "active": { + "description": "+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ObjectReference" + } + }, + "time": { + "description": "+optional\n+nullable", + "type": "string" + } + } + }, + "v1alpha1.StatusCheckSpec": { + "type": "object", + "properties": { + "duration": { + "description": "Duration defines the duration of the whole status check if the\nnumber of failed execution does not exceed the failure threshold.\nDuration is available to both `Synchronous` and `Continuous` mode.\nA duration string is a possibly signed sequence of\ndecimal numbers, each with optional fraction and a unit suffix,\nsuch as \"300ms\", \"-1.5h\" or \"2h45m\".\nValid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\n+optional", + "type": "string" + }, + "failureThreshold": { + "description": "FailureThreshold defines the minimum consecutive failure\nfor the status check to be considered failed.\n+optional\n+kubebuilder:default=3\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "http": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.HTTPStatusCheck" + }, + "intervalSeconds": { + "description": "IntervalSeconds defines how often (in seconds) to perform\nan execution of status check.\n+optional\n+kubebuilder:default=10\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "mode": { + "description": "Mode defines the execution mode of the status check.\nSupport type: Synchronous / Continuous\n+optional\n+kubebuilder:validation:Enum=Synchronous;Continuous", + "type": "string" + }, + "recordsHistoryLimit": { + "description": "RecordsHistoryLimit defines the number of record to retain.\n+optional\n+kubebuilder:default=100\n+kubebuilder:validation:Minimum=1\n+kubebuilder:validation:Maximum=1000", + "type": "integer" + }, + "successThreshold": { + "description": "SuccessThreshold defines the minimum consecutive successes\nfor the status check to be considered successful.\nSuccessThreshold only works for `Synchronous` mode.\n+optional\n+kubebuilder:default=1\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "timeoutSeconds": { + "description": "TimeoutSeconds defines the number of seconds after which\nan execution of status check times out.\n+optional\n+kubebuilder:default=1\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "type": { + "description": "Type defines the specific status check type.\nSupport type: HTTP\n+kubebuilder:default=HTTP\n+kubebuilder:validation:Enum=HTTP", + "type": "string" + } + } + }, + "v1alpha1.StatusCheckTemplate": { + "type": "object", + "properties": { + "duration": { + "description": "Duration defines the duration of the whole status check if the\nnumber of failed execution does not exceed the failure threshold.\nDuration is available to both `Synchronous` and `Continuous` mode.\nA duration string is a possibly signed sequence of\ndecimal numbers, each with optional fraction and a unit suffix,\nsuch as \"300ms\", \"-1.5h\" or \"2h45m\".\nValid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\n+optional", + "type": "string" + }, + "failureThreshold": { + "description": "FailureThreshold defines the minimum consecutive failure\nfor the status check to be considered failed.\n+optional\n+kubebuilder:default=3\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "http": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.HTTPStatusCheck" + }, + "intervalSeconds": { + "description": "IntervalSeconds defines how often (in seconds) to perform\nan execution of status check.\n+optional\n+kubebuilder:default=10\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "mode": { + "description": "Mode defines the execution mode of the status check.\nSupport type: Synchronous / Continuous\n+optional\n+kubebuilder:validation:Enum=Synchronous;Continuous", + "type": "string" + }, + "recordsHistoryLimit": { + "description": "RecordsHistoryLimit defines the number of record to retain.\n+optional\n+kubebuilder:default=100\n+kubebuilder:validation:Minimum=1\n+kubebuilder:validation:Maximum=1000", + "type": "integer" + }, + "successThreshold": { + "description": "SuccessThreshold defines the minimum consecutive successes\nfor the status check to be considered successful.\nSuccessThreshold only works for `Synchronous` mode.\n+optional\n+kubebuilder:default=1\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "timeoutSeconds": { + "description": "TimeoutSeconds defines the number of seconds after which\nan execution of status check times out.\n+optional\n+kubebuilder:default=1\n+kubebuilder:validation:Minimum=1", + "type": "integer" + }, + "type": { + "description": "Type defines the specific status check type.\nSupport type: HTTP\n+kubebuilder:default=HTTP\n+kubebuilder:validation:Enum=HTTP", + "type": "string" + } + } + }, + "v1alpha1.StressCPUSpec": { + "type": "object", + "properties": { + "load": { + "description": "specifies P percent loading per CPU worker. 0 is effectively a sleep (no load) and 100 is full loading.", + "type": "integer" + }, + "options": { + "description": "extend stress-ng options", + "type": "array", + "items": { + "type": "string" + } + }, + "workers": { + "description": "specifies N workers to apply the stressor.", + "type": "integer" + } + } + }, + "v1alpha1.StressChaosSpec": { + "type": "object", + "properties": { + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "duration": { + "description": "Duration represents the duration of the chaos action\n+optional", + "type": "string" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "stressngStressors": { + "description": "StressngStressors defines plenty of stressors just like `Stressors` except that it's an experimental\nfeature and more powerful. You can define stressors in `stress-ng` (see also `man stress-ng`) dialect,\nhowever not all of the supported stressors are well tested. It maybe retired in later releases. You\nshould always use `Stressors` to define the stressors and use this only when you want more stressors\nunsupported by `Stressors`. When both `StressngStressors` and `Stressors` are defined, `StressngStressors`\nwins.\n+optional", + "type": "string" + }, + "stressors": { + "description": "Stressors defines plenty of stressors supported to stress system components out.\nYou can use one or more of them to make up various kinds of stresses. At least\none of the stressors should be specified.\n+optional", + "$ref": "#/definitions/v1alpha1.Stressors" + }, + "value": { + "description": "Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`.\nIf `FixedMode`, provide an integer of pods to do chaos action.\nIf `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.StressMemorySpec": { + "type": "object", + "properties": { + "options": { + "description": "extend stress-ng options", + "type": "array", + "items": { + "type": "string" + } + }, + "size": { + "description": "specifies N bytes consumed per vm worker, default is the total available memory.\nOne can specify the size as % of total available memory or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB..", + "type": "string" + } + } + }, + "v1alpha1.Stressors": { + "type": "object", + "properties": { + "cpu": { + "description": "CPUStressor stresses CPU out\n+optional", + "$ref": "#/definitions/v1alpha1.CPUStressor" + }, + "memory": { + "description": "MemoryStressor stresses virtual memory out\n+optional", + "$ref": "#/definitions/v1alpha1.MemoryStressor" + } + } + }, + "v1alpha1.Task": { + "type": "object", + "properties": { + "container": { + "description": "Container is the main container image to run in the pod", + "$ref": "#/definitions/v1.Container" + }, + "volumes": { + "description": "Volumes is a list of volumes that can be mounted by containers in a template.\n+patchStrategy=merge\n+patchMergeKey=name", + "type": "array", + "items": { + "$ref": "#/definitions/v1.Volume" + } + } + } + }, + "v1alpha1.Template": { + "type": "object", + "properties": { + "abortWithStatusCheck": { + "description": "AbortWithStatusCheck describe whether to abort the workflow when the failure threshold of StatusCheck is exceeded.\nOnly used when Type is TypeStatusCheck.\n+optional", + "type": "boolean" + }, + "awsChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.AWSChaosSpec" + }, + "azureChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.AzureChaosSpec" + }, + "blockChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.BlockChaosSpec" + }, + "children": { + "description": "Children describes the children steps of serial or parallel node. Only used when Type is TypeSerial or TypeParallel.\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "conditionalBranches": { + "description": "ConditionalBranches describes the conditional branches of custom tasks. Only used when Type is TypeTask.\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1alpha1.ConditionalBranch" + } + }, + "deadline": { + "description": "+optional", + "type": "string" + }, + "dnsChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.DNSChaosSpec" + }, + "gcpChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.GCPChaosSpec" + }, + "httpChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.HTTPChaosSpec" + }, + "ioChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.IOChaosSpec" + }, + "jvmChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.JVMChaosSpec" + }, + "kernelChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.KernelChaosSpec" + }, + "name": { + "type": "string" + }, + "networkChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.NetworkChaosSpec" + }, + "physicalmachineChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.PhysicalMachineChaosSpec" + }, + "podChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.PodChaosSpec" + }, + "schedule": { + "description": "Schedule describe the Schedule(describing scheduled chaos) to be injected with chaos nodes. Only used when Type is TypeSchedule.\n+optional", + "$ref": "#/definitions/v1alpha1.ChaosOnlyScheduleSpec" + }, + "statusCheck": { + "description": "StatusCheck describe the behavior of StatusCheck. Only used when Type is TypeStatusCheck.\n+optional", + "$ref": "#/definitions/v1alpha1.StatusCheckSpec" + }, + "stressChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.StressChaosSpec" + }, + "task": { + "description": "Task describes the behavior of the custom task. Only used when Type is TypeTask.\n+optional", + "$ref": "#/definitions/v1alpha1.Task" + }, + "templateType": { + "type": "string" + }, + "timeChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.TimeChaosSpec" + } + } + }, + "v1alpha1.TimeChaosSpec": { + "type": "object", + "properties": { + "clockIds": { + "description": "ClockIds defines all affected clock id\nAll available options are [\"CLOCK_REALTIME\",\"CLOCK_MONOTONIC\",\"CLOCK_PROCESS_CPUTIME_ID\",\"CLOCK_THREAD_CPUTIME_ID\",\n\"CLOCK_MONOTONIC_RAW\",\"CLOCK_REALTIME_COARSE\",\"CLOCK_MONOTONIC_COARSE\",\"CLOCK_BOOTTIME\",\"CLOCK_REALTIME_ALARM\",\n\"CLOCK_BOOTTIME_ALARM\"]\nDefault value is [\"CLOCK_REALTIME\"]", + "type": "array", + "items": { + "type": "string" + } + }, + "containerNames": { + "description": "ContainerNames indicates list of the name of affected container.\nIf not set, the first container will be injected\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "duration": { + "description": "Duration represents the duration of the chaos action", + "type": "string" + }, + "mode": { + "description": "Mode defines the mode to run chaos action.\nSupported mode: one / all / fixed / fixed-percent / random-max-percent\n+kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "selector": { + "description": "Selector is used to select pods that are used to inject chaos action.", + "$ref": "#/definitions/v1alpha1.PodSelectorSpec" + }, + "timeOffset": { + "description": "TimeOffset defines the delta time of injected program. It's a possibly signed sequence of decimal numbers, such as\n\"300ms\", \"-1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".", + "type": "string" + }, + "value": { + "description": "Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`.\nIf `FixedMode`, provide an integer of pods to do chaos action.\nIf `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action.\nIF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action\n+optional", + "type": "string" + } + } + }, + "v1alpha1.Timespec": { + "type": "object", + "properties": { + "nsec": { + "type": "integer" + }, + "sec": { + "type": "integer" + } + } + }, + "v1alpha1.UserDefinedSpec": { + "type": "object", + "properties": { + "attackCmd": { + "description": "The command to be executed when attack", + "type": "string" + }, + "recoverCmd": { + "description": "The command to be executed when recover", + "type": "string" + } + } + }, + "v1alpha1.VMSpec": { + "type": "object", + "properties": { + "vm-name": { + "description": "The name of the VM to be injected", + "type": "string" + } + } + }, + "v1alpha1.Workflow": { + "type": "object", + "properties": { + "annotations": { + "description": "Annotations is an unstructured key value map stored with a resource that may be\nset by external tools to store and retrieve arbitrary metadata. They are not\nqueryable and should be preserved when modifying objects.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "creationTimestamp": { + "description": "CreationTimestamp is a timestamp representing the server time when this object was\ncreated. It is not guaranteed to be set in happens-before order across separate operations.\nClients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system.\nRead-only.\nNull for lists.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "type": "string" + }, + "deletionGracePeriodSeconds": { + "description": "Number of seconds allowed for this object to gracefully terminate before\nit will be removed from the system. Only set when deletionTimestamp is also set.\nMay only be shortened.\nRead-only.\n+optional", + "type": "integer" + }, + "deletionTimestamp": { + "description": "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This\nfield is set by the server when a graceful deletion is requested by the user, and is not\ndirectly settable by a client. The resource is expected to be deleted (no longer visible\nfrom resource lists, and not reachable by name) after the time in this field, once the\nfinalizers list is empty. As long as the finalizers list contains items, deletion is blocked.\nOnce the deletionTimestamp is set, this value may not be unset or be set further into the\nfuture, although it may be shortened or the resource may be deleted prior to this time.\nFor example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react\nby sending a graceful termination signal to the containers in the pod. After that 30 seconds,\nthe Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,\nremove the pod from the API. In the presence of network partitions, this object may still\nexist after this timestamp, until an administrator or automated process can determine the\nresource is fully terminated.\nIf not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested.\nRead-only.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "type": "string" + }, + "finalizers": { + "description": "Must be empty before the object is deleted from the registry. Each entry\nis an identifier for the responsible component that will remove the entry\nfrom the list. If the deletionTimestamp of the object is non-nil, entries\nin this list can only be removed.\nFinalizers may be processed and removed in any order. Order is NOT enforced\nbecause it introduces significant risk of stuck finalizers.\nfinalizers is a shared field, any actor with permission can reorder it.\nIf the finalizer list is processed in order, then this can lead to a situation\nin which the component responsible for the first finalizer in the list is\nwaiting for a signal (field value, external system, or other) produced by a\ncomponent responsible for a finalizer later in the list, resulting in a deadlock.\nWithout enforced ordering finalizers are free to order amongst themselves and\nare not vulnerable to ordering changes in the list.\n+optional\n+patchStrategy=merge", + "type": "array", + "items": { + "type": "string" + } + }, + "generateName": { + "description": "GenerateName is an optional prefix, used by the server, to generate a unique\nname ONLY IF the Name field has not been provided.\nIf this field is used, the name returned to the client will be different\nthan the name passed. This value will also be combined with a unique suffix.\nThe provided value has the same validation rules as the Name field,\nand may be truncated by the length of the suffix required to make the value\nunique on the server.\n\nIf this field is specified and the generated name exists, the server will return a 409.\n\nApplied only if Name is not specified.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency\n+optional", + "type": "string" + }, + "generation": { + "description": "A sequence number representing a specific generation of the desired state.\nPopulated by the system. Read-only.\n+optional", + "type": "integer" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "labels": { + "description": "Map of string keys and values that can be used to organize and categorize\n(scope and select) objects. May match selectors of replication controllers\nand services.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "managedFields": { + "description": "ManagedFields maps workflow-id and version to the set of fields\nthat are managed by that workflow. This is mostly for internal\nhousekeeping, and users typically shouldn't need to set or\nunderstand this field. A workflow can be the user's name, a\ncontroller's name, or the name of a specific apply path like\n\"ci-cd\". The set of fields is always in the version that the\nworkflow used when modifying the object.\n\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ManagedFieldsEntry" + } + }, + "name": { + "description": "Name must be unique within a namespace. Is required when creating resources, although\nsome resources may allow a client to request the generation of an appropriate name\nautomatically. Name is primarily intended for creation idempotence and configuration\ndefinition.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names\n+optional", + "type": "string" + }, + "namespace": { + "description": "Namespace defines the space within which each name must be unique. An empty namespace is\nequivalent to the \"default\" namespace, but \"default\" is the canonical representation.\nNot all objects are required to be scoped to a namespace - the value of this field for\nthose objects will be empty.\n\nMust be a DNS_LABEL.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces\n+optional", + "type": "string" + }, + "ownerReferences": { + "description": "List of objects depended by this object. If ALL objects in the list have\nbeen deleted, this object will be garbage collected. If this object is managed by a controller,\nthen an entry in this list will point to this controller, with the controller field set to true.\nThere cannot be more than one managing controller.\n+optional\n+patchMergeKey=uid\n+patchStrategy=merge", + "type": "array", + "items": { + "$ref": "#/definitions/v1.OwnerReference" + } + }, + "resourceVersion": { + "description": "An opaque value that represents the internal version of this object that can\nbe used by clients to determine when objects have changed. May be used for optimistic\nconcurrency, change detection, and the watch operation on a resource or set of resources.\nClients must treat these values as opaque and passed unmodified back to the server.\nThey may only be valid for a particular resource or set of resources.\n\nPopulated by the system.\nRead-only.\nValue must be treated as opaque by clients and .\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency\n+optional", + "type": "string" + }, + "selfLink": { + "description": "Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.\n+optional", + "type": "string" + }, + "spec": { + "description": "Spec defines the behavior of a workflow", + "$ref": "#/definitions/v1alpha1.WorkflowSpec" + }, + "status": { + "description": "+optional\nMost recently observed status of the workflow", + "$ref": "#/definitions/v1alpha1.WorkflowStatus" + }, + "uid": { + "description": "UID is the unique in time and space value for this object. It is typically generated by\nthe server on successful creation of a resource and is not allowed to change on PUT\noperations.\n\nPopulated by the system.\nRead-only.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids\n+optional", + "type": "string" + } + } + }, + "v1alpha1.WorkflowCondition": { + "type": "object", + "properties": { + "reason": { + "type": "string" + }, + "startTime": { + "type": "string" + }, + "status": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "v1alpha1.WorkflowSpec": { + "type": "object", + "properties": { + "entry": { + "type": "string" + }, + "templates": { + "type": "array", + "items": { + "$ref": "#/definitions/v1alpha1.Template" + } + } + } + }, + "v1alpha1.WorkflowStatus": { + "type": "object", + "properties": { + "conditions": { + "description": "Represents the latest available observations of a workflow's current state.\n+optional\n+patchMergeKey=type\n+patchStrategy=merge", + "type": "array", + "items": { + "$ref": "#/definitions/v1alpha1.WorkflowCondition" + } + }, + "endTime": { + "description": "+optional", + "type": "string" + }, + "entryNode": { + "description": "+optional", + "type": "string" + }, + "startTime": { + "description": "+optional", + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/pkg/dashboard/swaggerdocs/swagger.yaml b/pkg/dashboard/swaggerdocs/swagger.yaml new file mode 100644 index 0000000000..d6de37df59 --- /dev/null +++ b/pkg/dashboard/swaggerdocs/swagger.yaml @@ -0,0 +1,8034 @@ +basePath: /api +definitions: + config.ChaosDashboardConfig: + properties: + cluster_mode: + default: true + description: ClusterScoped means control Chaos Object in cluster level(all + namespace). + type: boolean + dns_server_create: + default: true + description: After v2.5, the DNS server is created by default. + type: boolean + enableFilterNamespace: + default: false + description: |- + EnableFilterNamespace will filter namespace with annotation. Only the pods/containers in namespace + annotated with `chaos-mesh.org/inject=enabled` will be injected. + type: boolean + gcp_security_mode: + default: false + description: GcpSecurityMode will use the gcloud authentication to login to + GKE user + type: boolean + listen_host: + default: 0.0.0.0 + type: string + listen_port: + default: 2333 + type: integer + root_path: + default: http://localhost:2333 + type: string + security_mode: + default: true + description: SecurityMode will use the token login by the user if set to true + type: boolean + target_namespace: + description: |- + TargetNamespace is the target namespace to injecting chaos. + It only works with ClusterScoped is false. + type: string + version: + type: string + type: object + core.ConditionalBranch: + properties: + expression: + type: string + name: + type: string + template: + type: string + type: object + core.Event: + properties: + created_at: + type: string + id: + type: integer + kind: + type: string + message: + type: string + name: + type: string + namespace: + type: string + object_id: + type: string + reason: + type: string + type: + type: string + type: object + core.KubeObjectDesc: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + +optional + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + +optional + type: string + metadata: + $ref: '#/definitions/core.KubeObjectMeta' + spec: {} + type: object + core.KubeObjectMeta: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + core.Node: + properties: + conditional_branches: + items: + $ref: '#/definitions/core.ConditionalBranch' + type: array + name: + type: string + parallel: + items: + $ref: '#/definitions/core.NodeNameWithTemplate' + type: array + serial: + items: + $ref: '#/definitions/core.NodeNameWithTemplate' + type: array + state: + type: string + template: + type: string + type: + type: string + uid: + type: string + type: object + core.NodeNameWithTemplate: + properties: + name: + type: string + template: + type: string + type: object + core.Topology: + properties: + nodes: + items: + $ref: '#/definitions/core.Node' + type: array + type: object + core.WorkflowDetail: + properties: + created_at: + type: string + end_time: + description: EndTime represents the time when the workflow completed all steps. + type: string + entry: + description: the entry node name + type: string + finish_time: + description: FinishTime represents the time when the workflow was deleted + from Kubernetes. + type: string + id: + type: integer + kube_object: + $ref: '#/definitions/core.KubeObjectDesc' + name: + type: string + namespace: + type: string + status: + type: string + topology: + $ref: '#/definitions/core.Topology' + uid: + type: string + type: object + core.WorkflowMeta: + properties: + created_at: + type: string + end_time: + description: EndTime represents the time when the workflow completed all steps. + type: string + entry: + description: the entry node name + type: string + finish_time: + description: FinishTime represents the time when the workflow was deleted + from Kubernetes. + type: string + id: + type: integer + name: + type: string + namespace: + type: string + status: + type: string + uid: + type: string + type: object + curl.Header: + additionalProperties: + items: + type: string + type: array + type: object + curl.RequestForm: + properties: + body: + type: string + followLocation: + type: boolean + header: + $ref: '#/definitions/curl.Header' + jsonContent: + type: boolean + method: + type: string + name: + type: string + url: + type: string + type: object + http.Header: + additionalProperties: + items: + type: string + type: array + type: object + intstr.IntOrString: + properties: + intVal: + type: integer + strVal: + type: string + type: + type: integer + type: object + resource.Quantity: + properties: + Format: + type: string + type: object + status.AllChaosStatus: + properties: + deleting: + type: integer + finished: + type: integer + injecting: + type: integer + paused: + type: integer + running: + type: integer + type: object + types.Archive: + properties: + created_at: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + uid: + type: string + type: object + types.ArchiveDetail: + properties: + created_at: + type: string + kind: + type: string + kube_object: + $ref: '#/definitions/core.KubeObjectDesc' + name: + type: string + namespace: + type: string + uid: + type: string + type: object + types.Experiment: + properties: + created_at: + type: string + failed_message: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + status: + type: string + uid: + type: string + type: object + types.ExperimentDetail: + properties: + created_at: + type: string + failed_message: + type: string + kind: + type: string + kube_object: + $ref: '#/definitions/core.KubeObjectDesc' + name: + type: string + namespace: + type: string + status: + type: string + uid: + type: string + type: object + types.PhysicalMachine: + properties: + address: + type: string + name: + type: string + namespace: + type: string + type: object + types.Pod: + properties: + ip: + type: string + name: + type: string + namespace: + type: string + state: + type: string + type: object + types.Schedule: + properties: + created_at: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + status: + type: string + uid: + type: string + type: object + types.ScheduleDetail: + properties: + created_at: + type: string + experiment_uids: + items: + type: string + type: array + kind: + type: string + kube_object: + $ref: '#/definitions/core.KubeObjectDesc' + name: + type: string + namespace: + type: string + status: + type: string + uid: + type: string + type: object + types.StatusCheckTemplate: + properties: + description: + type: string + name: + type: string + namespace: + type: string + spec: + $ref: '#/definitions/v1alpha1.StatusCheckTemplate' + type: object + types.StatusCheckTemplateBase: + properties: + created_at: + type: string + description: + type: string + name: + type: string + namespace: + type: string + uid: + type: string + type: object + types.StatusCheckTemplateDetail: + properties: + created_at: + type: string + description: + type: string + name: + type: string + namespace: + type: string + spec: + $ref: '#/definitions/v1alpha1.StatusCheckTemplate' + uid: + type: string + type: object + utils.APIError: + properties: + code: + type: integer + full_text: + type: string + message: + type: string + type: + type: string + type: object + utils.MapStringSliceResponse: + additionalProperties: + items: + type: string + type: array + type: object + utils.Response: + properties: + status: + type: string + type: object + v1.AWSElasticBlockStoreVolumeSource: + properties: + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem from compromising the machine + +optional + type: string + partition: + description: |- + partition is the partition in the volume that you want to mount. + If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition as "1". + Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + +optional + type: integer + readOnly: + description: |- + readOnly value true will force the readOnly setting in VolumeMounts. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + +optional + type: boolean + volumeID: + description: |- + volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + type: string + type: object + v1.AzureDiskVolumeSource: + properties: + cachingMode: + description: |- + cachingMode is the Host Caching mode: None, Read Only, Read Write. + +optional + type: string + diskName: + description: diskName is the Name of the data disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in the blob storage + type: string + fsType: + description: |- + fsType is Filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + +optional + type: string + kind: + description: 'kind expected values are Shared: multiple blob disks per storage + account Dedicated: single blob disk per storage account Managed: azure + managed data disk (only in managed availability set). defaults to shared' + type: string + readOnly: + description: |- + readOnly Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + +optional + type: boolean + type: object + v1.AzureFileVolumeSource: + properties: + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + +optional + type: boolean + secretName: + description: secretName is the name of secret that contains Azure Storage + Account Name and Key + type: string + shareName: + description: shareName is the azure share Name + type: string + type: object + v1.CSIVolumeSource: + properties: + driver: + description: |- + driver is the name of the CSI driver that handles this volume. + Consult with your admin for the correct name as registered in the cluster. + type: string + fsType: + description: |- + fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the associated CSI driver + which will determine the default filesystem to apply. + +optional + type: string + nodePublishSecretRef: + $ref: '#/definitions/v1.LocalObjectReference' + description: |- + nodePublishSecretRef is a reference to the secret object containing + sensitive information to pass to the CSI driver to complete the CSI + NodePublishVolume and NodeUnpublishVolume calls. + This field is optional, and may be empty if no secret is required. If the + secret object contains more than one secret, all secret references are passed. + +optional + readOnly: + description: |- + readOnly specifies a read-only configuration for the volume. + Defaults to false (read/write). + +optional + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: |- + volumeAttributes stores driver-specific properties that are passed to the CSI + driver. Consult your driver's documentation for supported values. + +optional + type: object + type: object + v1.Capabilities: + properties: + add: + description: |- + Added capabilities + +optional + items: + type: string + type: array + drop: + description: |- + Removed capabilities + +optional + items: + type: string + type: array + type: object + v1.CephFSVolumeSource: + properties: + monitors: + description: |- + monitors is Required: Monitors is a collection of Ceph monitors + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + items: + type: string + type: array + path: + description: |- + path is Optional: Used as the mounted root, rather than the full Ceph tree, default is / + +optional + type: string + readOnly: + description: |- + readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + +optional + type: boolean + secretFile: + description: |- + secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + +optional + type: string + secretRef: + $ref: '#/definitions/v1.LocalObjectReference' + description: |- + secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + +optional + user: + description: |- + user is optional: User is the rados user name, default is admin + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + +optional + type: string + type: object + v1.CinderVolumeSource: + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + +optional + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + +optional + type: boolean + secretRef: + $ref: '#/definitions/v1.LocalObjectReference' + description: |- + secretRef is optional: points to a secret object containing parameters used to connect + to OpenStack. + +optional + volumeID: + description: |- + volumeID used to identify the volume in cinder. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + type: string + type: object + v1.ConfigMapEnvSource: + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + +optional + type: string + optional: + description: |- + Specify whether the ConfigMap must be defined + +optional + type: boolean + type: object + v1.ConfigMapKeySelector: + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + +optional + type: string + optional: + description: |- + Specify whether the ConfigMap or its key must be defined + +optional + type: boolean + type: object + v1.ConfigMapProjection: + properties: + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + +optional + items: + $ref: '#/definitions/v1.KeyToPath' + type: array + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + +optional + type: string + optional: + description: |- + optional specify whether the ConfigMap or its keys must be defined + +optional + type: boolean + type: object + v1.ConfigMapVolumeSource: + properties: + defaultMode: + description: |- + defaultMode is optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + +optional + type: integer + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + +optional + items: + $ref: '#/definitions/v1.KeyToPath' + type: array + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + +optional + type: string + optional: + description: |- + optional specify whether the ConfigMap or its keys must be defined + +optional + type: boolean + type: object + v1.Container: + properties: + args: + description: |- + Arguments to the entrypoint. + The container image's CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + +optional + items: + type: string + type: array + command: + description: |- + Entrypoint array. Not executed within a shell. + The container image's ENTRYPOINT is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + +optional + items: + type: string + type: array + env: + description: |- + List of environment variables to set in the container. + Cannot be updated. + +optional + +patchMergeKey=name + +patchStrategy=merge + items: + $ref: '#/definitions/v1.EnvVar' + type: array + envFrom: + description: |- + List of sources to populate environment variables in the container. + The keys defined within a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container is starting. When a key exists in multiple + sources, the value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will take precedence. + Cannot be updated. + +optional + items: + $ref: '#/definitions/v1.EnvFromSource' + type: array + image: + description: |- + Container image name. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + +optional + type: string + imagePullPolicy: + description: |- + Image pull policy. + One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + +optional + type: string + lifecycle: + $ref: '#/definitions/v1.Lifecycle' + description: |- + Actions that the management system should take in response to container lifecycle events. + Cannot be updated. + +optional + livenessProbe: + $ref: '#/definitions/v1.Probe' + description: |- + Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + +optional + name: + description: |- + Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: |- + List of ports to expose from the container. Not specifying a port here + DOES NOT prevent that port from being exposed. Any port which is + listening on the default "0.0.0.0" address inside a container will be + accessible from the network. + Modifying this array with strategic merge patch may corrupt the data. + For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + +optional + +patchMergeKey=containerPort + +patchStrategy=merge + +listType=map + +listMapKey=containerPort + +listMapKey=protocol + items: + $ref: '#/definitions/v1.ContainerPort' + type: array + readinessProbe: + $ref: '#/definitions/v1.Probe' + description: |- + Periodic probe of container service readiness. + Container will be removed from service endpoints if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + +optional + resizePolicy: + description: |- + Resources resize policy for the container. + +featureGate=InPlacePodVerticalScaling + +optional + +listType=atomic + items: + $ref: '#/definitions/v1.ContainerResizePolicy' + type: array + resources: + $ref: '#/definitions/v1.ResourceRequirements' + description: |- + Compute Resources required by this container. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + +optional + restartPolicy: + description: |- + RestartPolicy defines the restart behavior of individual containers in a pod. + This field may only be set for init containers, and the only allowed value is "Always". + For non-init containers or when this field is not specified, + the restart behavior is defined by the Pod's restart policy and the container type. + Setting the RestartPolicy as "Always" for the init container will have the following effect: + this init container will be continually restarted on + exit until all regular containers have terminated. Once all regular + containers have completed, all init containers with restartPolicy "Always" + will be shut down. This lifecycle differs from normal init containers and + is often referred to as a "sidecar" container. Although this init + container still starts in the init container sequence, it does not wait + for the container to complete before proceeding to the next init + container. Instead, the next init container starts immediately after this + init container is started, or after any startupProbe has successfully + completed. + +featureGate=SidecarContainers + +optional + type: string + securityContext: + $ref: '#/definitions/v1.SecurityContext' + description: |- + SecurityContext defines the security options the container should be run with. + If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + +optional + startupProbe: + $ref: '#/definitions/v1.Probe' + description: |- + StartupProbe indicates that the Pod has successfully initialized. + If specified, no other probes are executed until this completes successfully. + If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. + This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, + when it might take a long time to load data or warm a cache, than during steady-state operation. + This cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + +optional + stdin: + description: |- + Whether this container should allocate a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will always result in EOF. + Default is false. + +optional + type: boolean + stdinOnce: + description: |- + Whether the container runtime should close the stdin channel after it has been opened by + a single attach. When stdin is true the stdin stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the + first client attaches to stdin, and then remains open and accepts data until the client disconnects, + at which time stdin is closed and remains closed until the container is restarted. If this + flag is false, a container processes that reads from stdin will never receive an EOF. + Default is false + +optional + type: boolean + terminationMessagePath: + description: |- + Optional: Path at which the file to which the container's termination message + will be written is mounted into the container's filesystem. + Message written is intended to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. The total message length across + all containers will be limited to 12kb. + Defaults to /dev/termination-log. + Cannot be updated. + +optional + type: string + terminationMessagePolicy: + description: |- + Indicate how the termination message should be populated. File will use the contents of + terminationMessagePath to populate the container status message on both success and failure. + FallbackToLogsOnError will use the last chunk of container log output if the termination + message file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, whichever is smaller. + Defaults to File. + Cannot be updated. + +optional + type: string + tty: + description: |- + Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. + Default is false. + +optional + type: boolean + volumeDevices: + description: |- + volumeDevices is the list of block devices to be used by the container. + +patchMergeKey=devicePath + +patchStrategy=merge + +optional + items: + $ref: '#/definitions/v1.VolumeDevice' + type: array + volumeMounts: + description: |- + Pod volumes to mount into the container's filesystem. + Cannot be updated. + +optional + +patchMergeKey=mountPath + +patchStrategy=merge + items: + $ref: '#/definitions/v1.VolumeMount' + type: array + workingDir: + description: |- + Container's working directory. + If not specified, the container runtime's default will be used, which + might be configured in the container image. + Cannot be updated. + +optional + type: string + type: object + v1.ContainerPort: + properties: + containerPort: + description: |- + Number of port to expose on the pod's IP address. + This must be a valid port number, 0 < x < 65536. + type: integer + hostIP: + description: |- + What host IP to bind the external port to. + +optional + type: string + hostPort: + description: |- + Number of port to expose on the host. + If specified, this must be a valid port number, 0 < x < 65536. + If HostNetwork is specified, this must match ContainerPort. + Most containers do not need this. + +optional + type: integer + name: + description: |- + If specified, this must be an IANA_SVC_NAME and unique within the pod. Each + named port in a pod must have a unique name. Name for the port that can be + referred to by services. + +optional + type: string + protocol: + description: |- + Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". + +optional + +default="TCP" + type: string + type: object + v1.ContainerResizePolicy: + properties: + resourceName: + description: |- + Name of the resource to which this resource resize policy applies. + Supported values: cpu, memory. + type: string + restartPolicy: + description: |- + Restart policy to apply when specified resource is resized. + If not specified, it defaults to NotRequired. + type: string + type: object + v1.DownwardAPIProjection: + properties: + items: + description: |- + Items is a list of DownwardAPIVolume file + +optional + items: + $ref: '#/definitions/v1.DownwardAPIVolumeFile' + type: array + type: object + v1.DownwardAPIVolumeFile: + properties: + fieldRef: + $ref: '#/definitions/v1.ObjectFieldSelector' + description: |- + Required: Selects a field of the pod: only annotations, labels, name and namespace are supported. + +optional + mode: + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + +optional + type: integer + path: + description: 'Required: Path is the relative path name of the file to be + created. Must not be absolute or contain the ''..'' path. Must be utf-8 + encoded. The first item of the relative path must not start with ''..''' + type: string + resourceFieldRef: + $ref: '#/definitions/v1.ResourceFieldSelector' + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. + +optional + type: object + v1.DownwardAPIVolumeSource: + properties: + defaultMode: + description: |- + Optional: mode bits to use on created files by default. Must be a + Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + +optional + type: integer + items: + description: |- + Items is a list of downward API volume file + +optional + items: + $ref: '#/definitions/v1.DownwardAPIVolumeFile' + type: array + type: object + v1.EmptyDirVolumeSource: + properties: + medium: + description: |- + medium represents what type of storage medium should back this directory. + The default is "" which means to use the node's default medium. + Must be an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + +optional + type: string + sizeLimit: + $ref: '#/definitions/resource.Quantity' + description: |- + sizeLimit is the total amount of local storage required for this EmptyDir volume. + The size limit is also applicable for memory medium. + The maximum usage on memory medium EmptyDir would be the minimum value between + the SizeLimit specified here and the sum of memory limits of all containers in a pod. + The default is nil which means that the limit is undefined. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + +optional + type: object + v1.EnvFromSource: + properties: + configMapRef: + $ref: '#/definitions/v1.ConfigMapEnvSource' + description: |- + The ConfigMap to select from + +optional + prefix: + description: |- + An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. + +optional + type: string + secretRef: + $ref: '#/definitions/v1.SecretEnvSource' + description: |- + The Secret to select from + +optional + type: object + v1.EnvVar: + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + +optional + type: string + valueFrom: + $ref: '#/definitions/v1.EnvVarSource' + description: |- + Source for the environment variable's value. Cannot be used if value is not empty. + +optional + type: object + v1.EnvVarSource: + properties: + configMapKeyRef: + $ref: '#/definitions/v1.ConfigMapKeySelector' + description: |- + Selects a key of a ConfigMap. + +optional + fieldRef: + $ref: '#/definitions/v1.ObjectFieldSelector' + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + +optional + resourceFieldRef: + $ref: '#/definitions/v1.ResourceFieldSelector' + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + +optional + secretKeyRef: + $ref: '#/definitions/v1.SecretKeySelector' + description: |- + Selects a key of a secret in the pod's namespace + +optional + type: object + v1.EphemeralVolumeSource: + properties: + volumeClaimTemplate: + $ref: '#/definitions/v1.PersistentVolumeClaimTemplate' + description: |- + Will be used to create a stand-alone PVC to provision the volume. + The pod in which this EphemeralVolumeSource is embedded will be the + owner of the PVC, i.e. the PVC will be deleted together with the + pod. The name of the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` array + entry. Pod validation will reject the pod if the concatenated name + is not valid for a PVC (for example, too long). + + An existing PVC with that name that is not owned by the pod + will *not* be used for the pod to avoid using an unrelated + volume by mistake. Starting the pod is then blocked until + the unrelated PVC is removed. If such a pre-created PVC is + meant to be used by the pod, the PVC has to updated with an + owner reference to the pod once the pod exists. Normally + this should not be necessary, but it may be useful when + manually reconstructing a broken cluster. + + This field is read-only and no changes will be made by Kubernetes + to the PVC after it has been created. + + Required, must not be nil. + type: object + v1.ExecAction: + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + +optional + items: + type: string + type: array + type: object + v1.FCVolumeSource: + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + TODO: how do we prevent errors in the filesystem from compromising the machine + +optional + type: string + lun: + description: |- + lun is Optional: FC target lun number + +optional + type: integer + readOnly: + description: |- + readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + +optional + type: boolean + targetWWNs: + description: |- + targetWWNs is Optional: FC target worldwide names (WWNs) + +optional + items: + type: string + type: array + wwids: + description: |- + wwids Optional: FC volume world wide identifiers (wwids) + Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. + +optional + items: + type: string + type: array + type: object + v1.FieldsV1: + type: object + v1.FlexVolumeSource: + properties: + driver: + description: driver is the name of the driver to use for this volume. + type: string + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. + +optional + type: string + options: + additionalProperties: + type: string + description: |- + options is Optional: this field holds extra command options if any. + +optional + type: object + readOnly: + description: |- + readOnly is Optional: defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + +optional + type: boolean + secretRef: + $ref: '#/definitions/v1.LocalObjectReference' + description: |- + secretRef is Optional: secretRef is reference to the secret object containing + sensitive information to pass to the plugin scripts. This may be + empty if no secret object is specified. If the secret object + contains more than one secret, all secrets are passed to the plugin + scripts. + +optional + type: object + v1.FlockerVolumeSource: + properties: + datasetName: + description: |- + datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker + should be considered as deprecated + +optional + type: string + datasetUUID: + description: |- + datasetUUID is the UUID of the dataset. This is unique identifier of a Flocker dataset + +optional + type: string + type: object + v1.GCEPersistentDiskVolumeSource: + properties: + fsType: + description: |- + fsType is filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem from compromising the machine + +optional + type: string + partition: + description: |- + partition is the partition in the volume that you want to mount. + If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition as "1". + Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + +optional + type: integer + pdName: + description: |- + pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + type: string + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + +optional + type: boolean + type: object + v1.GRPCAction: + properties: + port: + description: Port number of the gRPC service. Number must be in the range + 1 to 65535. + type: integer + service: + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + +optional + +default="" + type: string + type: object + v1.GitRepoVolumeSource: + properties: + directory: + description: |- + directory is the target directory name. + Must not contain or start with '..'. If '.' is supplied, the volume directory will be the + git repository. Otherwise, if specified, the volume will contain the git repository in + the subdirectory with the given name. + +optional + type: string + repository: + description: repository is the URL + type: string + revision: + description: |- + revision is the commit hash for the specified revision. + +optional + type: string + type: object + v1.GlusterfsVolumeSource: + properties: + endpoints: + description: |- + endpoints is the endpoint name that details Glusterfs topology. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + type: string + path: + description: |- + path is the Glusterfs volume path. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + type: string + readOnly: + description: |- + readOnly here will force the Glusterfs volume to be mounted with read-only permissions. + Defaults to false. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + +optional + type: boolean + type: object + v1.HTTPGetAction: + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + +optional + type: string + httpHeaders: + description: |- + Custom headers to set in the request. HTTP allows repeated headers. + +optional + items: + $ref: '#/definitions/v1.HTTPHeader' + type: array + path: + description: |- + Path to access on the HTTP server. + +optional + type: string + port: + $ref: '#/definitions/intstr.IntOrString' + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + +optional + type: string + type: object + v1.HTTPHeader: + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + type: object + v1.HostPathVolumeSource: + properties: + path: + description: |- + path of the directory on the host. + If the path is a symlink, it will follow the link to the real path. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + type: string + type: + description: |- + type for HostPath Volume + Defaults to "" + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + +optional + type: string + type: object + v1.ISCSIVolumeSource: + properties: + chapAuthDiscovery: + description: |- + chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication + +optional + type: boolean + chapAuthSession: + description: |- + chapAuthSession defines whether support iSCSI Session CHAP authentication + +optional + type: boolean + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem from compromising the machine + +optional + type: string + initiatorName: + description: |- + initiatorName is the custom iSCSI Initiator Name. + If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface + : will be created for the connection. + +optional + type: string + iqn: + description: iqn is the target iSCSI Qualified Name. + type: string + iscsiInterface: + description: |- + iscsiInterface is the interface Name that uses an iSCSI transport. + Defaults to 'default' (tcp). + +optional + type: string + lun: + description: lun represents iSCSI Target Lun number. + type: integer + portals: + description: |- + portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and 3260). + +optional + items: + type: string + type: array + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + +optional + type: boolean + secretRef: + $ref: '#/definitions/v1.LocalObjectReference' + description: |- + secretRef is the CHAP Secret for iSCSI target and initiator authentication + +optional + targetPortal: + description: |- + targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and 3260). + type: string + type: object + v1.KeyToPath: + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + +optional + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + type: object + v1.LabelSelector: + properties: + matchExpressions: + description: |- + matchExpressions is a list of label selector requirements. The requirements are ANDed. + +optional + items: + $ref: '#/definitions/v1.LabelSelectorRequirement' + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + +optional + type: object + type: object + v1.LabelSelectorRequirement: + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + +optional + items: + type: string + type: array + type: object + v1.Lifecycle: + properties: + postStart: + $ref: '#/definitions/v1.LifecycleHandler' + description: |- + PostStart is called immediately after a container is created. If the handler fails, + the container is terminated and restarted according to its restart policy. + Other management of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + +optional + preStop: + $ref: '#/definitions/v1.LifecycleHandler' + description: |- + PreStop is called immediately before a container is terminated due to an + API request or management event such as liveness/startup probe failure, + preemption, resource contention, etc. The handler is not called if the + container crashes or exits. The Pod's termination grace period countdown begins before the + PreStop hook is executed. Regardless of the outcome of the handler, the + container will eventually terminate within the Pod's termination grace + period (unless delayed by finalizers). Other management of the container blocks until the hook completes + or until the termination grace period is reached. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + +optional + type: object + v1.LifecycleHandler: + properties: + exec: + $ref: '#/definitions/v1.ExecAction' + description: |- + Exec specifies the action to take. + +optional + httpGet: + $ref: '#/definitions/v1.HTTPGetAction' + description: |- + HTTPGet specifies the http request to perform. + +optional + tcpSocket: + $ref: '#/definitions/v1.TCPSocketAction' + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. + +optional + type: object + v1.LocalObjectReference: + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + +optional + type: string + type: object + v1.ManagedFieldsEntry: + properties: + apiVersion: + description: |- + APIVersion defines the version of this resource that this field set + applies to. The format is "group/version" just like the top-level + APIVersion field. It is necessary to track the version of a field + set because it cannot be automatically converted. + type: string + fieldsType: + description: |- + FieldsType is the discriminator for the different fields format and version. + There is currently only one possible value: "FieldsV1" + type: string + fieldsV1: + $ref: '#/definitions/v1.FieldsV1' + description: |- + FieldsV1 holds the first JSON version format as described in the "FieldsV1" type. + +optional + manager: + description: Manager is an identifier of the workflow managing these fields. + type: string + operation: + description: |- + Operation is the type of operation which lead to this ManagedFieldsEntry being created. + The only valid values for this field are 'Apply' and 'Update'. + type: string + subresource: + description: |- + Subresource is the name of the subresource used to update that object, or + empty string if the object was updated through the main resource. The + value of this field is used to distinguish between managers, even if they + share the same name. For example, a status update will be distinct from a + regular update using the same manager name. + Note that the APIVersion field is not related to the Subresource field and + it always corresponds to the version of the main resource. + type: string + time: + description: |- + Time is the timestamp of when the ManagedFields entry was added. The + timestamp will also be updated if a field is added, the manager + changes any of the owned fields value or removes a field. The + timestamp does not update when a field is removed from the entry + because another manager took it over. + +optional + type: string + type: object + v1.NFSVolumeSource: + properties: + path: + description: |- + path that is exported by the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + type: string + readOnly: + description: |- + readOnly here will force the NFS export to be mounted with read-only permissions. + Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + +optional + type: boolean + server: + description: |- + server is the hostname or IP address of the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + type: string + type: object + v1.ObjectFieldSelector: + properties: + apiVersion: + description: |- + Version of the schema the FieldPath is written in terms of, defaults to "v1". + +optional + type: string + fieldPath: + description: Path of the field to select in the specified API version. + type: string + type: object + v1.ObjectReference: + properties: + apiVersion: + description: |- + API version of the referent. + +optional + type: string + fieldPath: + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. + TODO: this design is not final and this field is subject to change in the future. + +optional + type: string + kind: + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + +optional + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + +optional + type: string + namespace: + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + +optional + type: string + resourceVersion: + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + +optional + type: string + uid: + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids + +optional + type: string + type: object + v1.OwnerReference: + properties: + apiVersion: + description: API version of the referent. + type: string + blockOwnerDeletion: + description: |- + If true, AND if the owner has the "foregroundDeletion" finalizer, then + the owner cannot be deleted from the key-value store until this + reference is removed. + See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion + for how the garbage collector interacts with this field and enforces the foreground deletion. + Defaults to false. + To set this field, a user needs "delete" permission of the owner, + otherwise 422 (Unprocessable Entity) will be returned. + +optional + type: boolean + controller: + description: |- + If true, this reference points to the managing controller. + +optional + type: boolean + kind: + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names + type: string + uid: + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids + type: string + type: object + v1.PersistentVolumeClaimSpec: + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + +optional + items: + type: string + type: array + dataSource: + $ref: '#/definitions/v1.TypedLocalObjectReference' + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + +optional + dataSourceRef: + $ref: '#/definitions/v1.TypedObjectReference' + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + +optional + resources: + $ref: '#/definitions/v1.ResourceRequirements' + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + +optional + selector: + $ref: '#/definitions/v1.LabelSelector' + description: |- + selector is a label query over volumes to consider for binding. + +optional + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + +optional + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + +optional + type: string + volumeName: + description: |- + volumeName is the binding reference to the PersistentVolume backing this claim. + +optional + type: string + type: object + v1.PersistentVolumeClaimTemplate: + properties: + annotations: + additionalProperties: + type: string + description: |- + Annotations is an unstructured key value map stored with a resource that may be + set by external tools to store and retrieve arbitrary metadata. They are not + queryable and should be preserved when modifying objects. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations + +optional + type: object + creationTimestamp: + description: |- + CreationTimestamp is a timestamp representing the server time when this object was + created. It is not guaranteed to be set in happens-before order across separate operations. + Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. + Read-only. + Null for lists. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + +optional + type: string + deletionGracePeriodSeconds: + description: |- + Number of seconds allowed for this object to gracefully terminate before + it will be removed from the system. Only set when deletionTimestamp is also set. + May only be shortened. + Read-only. + +optional + type: integer + deletionTimestamp: + description: |- + DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This + field is set by the server when a graceful deletion is requested by the user, and is not + directly settable by a client. The resource is expected to be deleted (no longer visible + from resource lists, and not reachable by name) after the time in this field, once the + finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. + Once the deletionTimestamp is set, this value may not be unset or be set further into the + future, although it may be shortened or the resource may be deleted prior to this time. + For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react + by sending a graceful termination signal to the containers in the pod. After that 30 seconds, + the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, + remove the pod from the API. In the presence of network partitions, this object may still + exist after this timestamp, until an administrator or automated process can determine the + resource is fully terminated. + If not set, graceful deletion of the object has not been requested. + + Populated by the system when a graceful deletion is requested. + Read-only. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + +optional + type: string + finalizers: + description: |- + Must be empty before the object is deleted from the registry. Each entry + is an identifier for the responsible component that will remove the entry + from the list. If the deletionTimestamp of the object is non-nil, entries + in this list can only be removed. + Finalizers may be processed and removed in any order. Order is NOT enforced + because it introduces significant risk of stuck finalizers. + finalizers is a shared field, any actor with permission can reorder it. + If the finalizer list is processed in order, then this can lead to a situation + in which the component responsible for the first finalizer in the list is + waiting for a signal (field value, external system, or other) produced by a + component responsible for a finalizer later in the list, resulting in a deadlock. + Without enforced ordering finalizers are free to order amongst themselves and + are not vulnerable to ordering changes in the list. + +optional + +patchStrategy=merge + items: + type: string + type: array + generateName: + description: |- + GenerateName is an optional prefix, used by the server, to generate a unique + name ONLY IF the Name field has not been provided. + If this field is used, the name returned to the client will be different + than the name passed. This value will also be combined with a unique suffix. + The provided value has the same validation rules as the Name field, + and may be truncated by the length of the suffix required to make the value + unique on the server. + + If this field is specified and the generated name exists, the server will return a 409. + + Applied only if Name is not specified. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency + +optional + type: string + generation: + description: |- + A sequence number representing a specific generation of the desired state. + Populated by the system. Read-only. + +optional + type: integer + labels: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to organize and categorize + (scope and select) objects. May match selectors of replication controllers + and services. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels + +optional + type: object + managedFields: + description: |- + ManagedFields maps workflow-id and version to the set of fields + that are managed by that workflow. This is mostly for internal + housekeeping, and users typically shouldn't need to set or + understand this field. A workflow can be the user's name, a + controller's name, or the name of a specific apply path like + "ci-cd". The set of fields is always in the version that the + workflow used when modifying the object. + + +optional + items: + $ref: '#/definitions/v1.ManagedFieldsEntry' + type: array + name: + description: |- + Name must be unique within a namespace. Is required when creating resources, although + some resources may allow a client to request the generation of an appropriate name + automatically. Name is primarily intended for creation idempotence and configuration + definition. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names + +optional + type: string + namespace: + description: |- + Namespace defines the space within which each name must be unique. An empty namespace is + equivalent to the "default" namespace, but "default" is the canonical representation. + Not all objects are required to be scoped to a namespace - the value of this field for + those objects will be empty. + + Must be a DNS_LABEL. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces + +optional + type: string + ownerReferences: + description: |- + List of objects depended by this object. If ALL objects in the list have + been deleted, this object will be garbage collected. If this object is managed by a controller, + then an entry in this list will point to this controller, with the controller field set to true. + There cannot be more than one managing controller. + +optional + +patchMergeKey=uid + +patchStrategy=merge + items: + $ref: '#/definitions/v1.OwnerReference' + type: array + resourceVersion: + description: |- + An opaque value that represents the internal version of this object that can + be used by clients to determine when objects have changed. May be used for optimistic + concurrency, change detection, and the watch operation on a resource or set of resources. + Clients must treat these values as opaque and passed unmodified back to the server. + They may only be valid for a particular resource or set of resources. + + Populated by the system. + Read-only. + Value must be treated as opaque by clients and . + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + +optional + type: string + selfLink: + description: |- + Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. + +optional + type: string + spec: + $ref: '#/definitions/v1.PersistentVolumeClaimSpec' + description: |- + The specification for the PersistentVolumeClaim. The entire content is + copied unchanged into the PVC that gets created from this + template. The same fields as in a PersistentVolumeClaim + are also valid here. + uid: + description: |- + UID is the unique in time and space value for this object. It is typically generated by + the server on successful creation of a resource and is not allowed to change on PUT + operations. + + Populated by the system. + Read-only. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids + +optional + type: string + type: object + v1.PersistentVolumeClaimVolumeSource: + properties: + claimName: + description: |- + claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + type: string + readOnly: + description: |- + readOnly Will force the ReadOnly setting in VolumeMounts. + Default false. + +optional + type: boolean + type: object + v1.PhotonPersistentDiskVolumeSource: + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon Controller persistent disk + type: string + type: object + v1.PortworxVolumeSource: + properties: + fsType: + description: |- + fSType represents the filesystem type to mount + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + +optional + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx volume + type: string + type: object + v1.Probe: + properties: + exec: + $ref: '#/definitions/v1.ExecAction' + description: |- + Exec specifies the action to take. + +optional + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + +optional + type: integer + grpc: + $ref: '#/definitions/v1.GRPCAction' + description: |- + GRPC specifies an action involving a GRPC port. + +optional + httpGet: + $ref: '#/definitions/v1.HTTPGetAction' + description: |- + HTTPGet specifies the http request to perform. + +optional + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + +optional + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + +optional + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + +optional + type: integer + tcpSocket: + $ref: '#/definitions/v1.TCPSocketAction' + description: |- + TCPSocket specifies an action involving a TCP port. + +optional + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + +optional + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + +optional + type: integer + type: object + v1.ProjectedVolumeSource: + properties: + defaultMode: + description: |- + defaultMode are the mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + +optional + type: integer + sources: + description: |- + sources is the list of volume projections + +optional + items: + $ref: '#/definitions/v1.VolumeProjection' + type: array + type: object + v1.QuobyteVolumeSource: + properties: + group: + description: |- + group to map volume access to + Default is no group + +optional + type: string + readOnly: + description: |- + readOnly here will force the Quobyte volume to be mounted with read-only permissions. + Defaults to false. + +optional + type: boolean + registry: + description: |- + registry represents a single or multiple Quobyte Registry services + specified as a string as host:port pair (multiple entries are separated with commas) + which acts as the central registry for volumes + type: string + tenant: + description: |- + tenant owning the given Quobyte volume in the Backend + Used with dynamically provisioned Quobyte volumes, value is set by the plugin + +optional + type: string + user: + description: |- + user to map volume access to + Defaults to serivceaccount user + +optional + type: string + volume: + description: volume is a string that references an already created Quobyte + volume by name. + type: string + type: object + v1.RBDVolumeSource: + properties: + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem from compromising the machine + +optional + type: string + image: + description: |- + image is the rados image name. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + keyring: + description: |- + keyring is the path to key ring for RBDUser. + Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + +optional + type: string + monitors: + description: |- + monitors is a collection of Ceph monitors. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + items: + type: string + type: array + pool: + description: |- + pool is the rados pool name. + Default is rbd. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + +optional + type: string + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + +optional + type: boolean + secretRef: + $ref: '#/definitions/v1.LocalObjectReference' + description: |- + secretRef is name of the authentication secret for RBDUser. If provided + overrides keyring. + Default is nil. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + +optional + user: + description: |- + user is the rados user name. + Default is admin. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + +optional + type: string + type: object + v1.ResourceClaim: + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + type: object + v1.ResourceFieldSelector: + properties: + containerName: + description: |- + Container name: required for volumes, optional for env vars + +optional + type: string + divisor: + $ref: '#/definitions/resource.Quantity' + description: |- + Specifies the output format of the exposed resources, defaults to "1" + +optional + resource: + description: 'Required: resource to select' + type: string + type: object + v1.ResourceList: + additionalProperties: + $ref: '#/definitions/resource.Quantity' + type: object + v1.ResourceRequirements: + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + + +listType=map + +listMapKey=name + +featureGate=DynamicResourceAllocation + +optional + items: + $ref: '#/definitions/v1.ResourceClaim' + type: array + limits: + $ref: '#/definitions/v1.ResourceList' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + +optional + requests: + $ref: '#/definitions/v1.ResourceList' + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + +optional + type: object + v1.SELinuxOptions: + properties: + level: + description: |- + Level is SELinux level label that applies to the container. + +optional + type: string + role: + description: |- + Role is a SELinux role label that applies to the container. + +optional + type: string + type: + description: |- + Type is a SELinux type label that applies to the container. + +optional + type: string + user: + description: |- + User is a SELinux user label that applies to the container. + +optional + type: string + type: object + v1.ScaleIOVolumeSource: + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". + Default is "xfs". + +optional + type: string + gateway: + description: gateway is the host address of the ScaleIO API Gateway. + type: string + protectionDomain: + description: |- + protectionDomain is the name of the ScaleIO Protection Domain for the configured storage. + +optional + type: string + readOnly: + description: |- + readOnly Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + +optional + type: boolean + secretRef: + $ref: '#/definitions/v1.LocalObjectReference' + description: |- + secretRef references to the secret for ScaleIO user and other + sensitive information. If this is not provided, Login operation will fail. + sslEnabled: + description: |- + sslEnabled Flag enable/disable SSL communication with Gateway, default false + +optional + type: boolean + storageMode: + description: |- + storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. + +optional + type: string + storagePool: + description: |- + storagePool is the ScaleIO Storage Pool associated with the protection domain. + +optional + type: string + system: + description: system is the name of the storage system as configured in ScaleIO. + type: string + volumeName: + description: |- + volumeName is the name of a volume already created in the ScaleIO system + that is associated with this volume source. + type: string + type: object + v1.SeccompProfile: + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + +optional + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + +unionDiscriminator + type: string + type: object + v1.SecretEnvSource: + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + +optional + type: string + optional: + description: |- + Specify whether the Secret must be defined + +optional + type: boolean + type: object + v1.SecretKeySelector: + properties: + key: + description: The key of the secret to select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + +optional + type: string + optional: + description: |- + Specify whether the Secret or its key must be defined + +optional + type: boolean + type: object + v1.SecretProjection: + properties: + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + +optional + items: + $ref: '#/definitions/v1.KeyToPath' + type: array + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + +optional + type: string + optional: + description: |- + optional field specify whether the Secret or its key must be defined + +optional + type: boolean + type: object + v1.SecretVolumeSource: + properties: + defaultMode: + description: |- + defaultMode is Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values + for mode bits. Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + +optional + type: integer + items: + description: |- + items If unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + +optional + items: + $ref: '#/definitions/v1.KeyToPath' + type: array + optional: + description: |- + optional field specify whether the Secret or its keys must be defined + +optional + type: boolean + secretName: + description: |- + secretName is the name of the secret in the pod's namespace to use. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + +optional + type: string + type: object + v1.SecurityContext: + properties: + allowPrivilegeEscalation: + description: |- + AllowPrivilegeEscalation controls whether a process can gain more + privileges than its parent process. This bool directly controls if + the no_new_privs flag will be set on the container process. + AllowPrivilegeEscalation is true always when the container is: + 1) run as Privileged + 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows. + +optional + type: boolean + capabilities: + $ref: '#/definitions/v1.Capabilities' + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. + Note that this field cannot be set when spec.os.name is windows. + +optional + privileged: + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. + Note that this field cannot be set when spec.os.name is windows. + +optional + type: boolean + procMount: + description: |- + procMount denotes the type of proc mount to use for the containers. + The default is DefaultProcMount which uses the container runtime defaults for + readonly paths and masked paths. + This requires the ProcMountType feature flag to be enabled. + Note that this field cannot be set when spec.os.name is windows. + +optional + type: string + readOnlyRootFilesystem: + description: |- + Whether this container has a read-only root filesystem. + Default is false. + Note that this field cannot be set when spec.os.name is windows. + +optional + type: boolean + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + +optional + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + +optional + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + +optional + type: integer + seLinuxOptions: + $ref: '#/definitions/v1.SELinuxOptions' + description: |- + The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + +optional + seccompProfile: + $ref: '#/definitions/v1.SeccompProfile' + description: |- + The seccomp options to use by this container. If seccomp options are + provided at both the pod & container level, the container options + override the pod options. + Note that this field cannot be set when spec.os.name is windows. + +optional + windowsOptions: + $ref: '#/definitions/v1.WindowsSecurityContextOptions' + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + +optional + type: object + v1.ServiceAccountTokenProjection: + properties: + audience: + description: |- + audience is the intended audience of the token. A recipient of a token + must identify itself with an identifier specified in the audience of the + token, and otherwise should reject the token. The audience defaults to the + identifier of the apiserver. + +optional + type: string + expirationSeconds: + description: |- + expirationSeconds is the requested duration of validity of the service + account token. As the token approaches expiration, the kubelet volume + plugin will proactively rotate the service account token. The kubelet will + start trying to rotate the token if the token is older than 80 percent of + its time to live or if the token is older than 24 hours.Defaults to 1 hour + and must be at least 10 minutes. + +optional + type: integer + path: + description: |- + path is the path relative to the mount point of the file to project the + token into. + type: string + type: object + v1.StorageOSVolumeSource: + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + +optional + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + +optional + type: boolean + secretRef: + $ref: '#/definitions/v1.LocalObjectReference' + description: |- + secretRef specifies the secret to use for obtaining the StorageOS API + credentials. If not specified, default values will be attempted. + +optional + volumeName: + description: |- + volumeName is the human-readable name of the StorageOS volume. Volume + names are only unique within a namespace. + type: string + volumeNamespace: + description: |- + volumeNamespace specifies the scope of the volume within StorageOS. If no + namespace is specified then the Pod's namespace will be used. This allows the + Kubernetes name scoping to be mirrored within StorageOS for tighter integration. + Set VolumeName to any name to override the default behaviour. + Set to "default" if you are not using namespaces within StorageOS. + Namespaces that do not pre-exist within StorageOS will be created. + +optional + type: string + type: object + v1.TCPSocketAction: + properties: + host: + description: |- + Optional: Host name to connect to, defaults to the pod IP. + +optional + type: string + port: + $ref: '#/definitions/intstr.IntOrString' + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + type: object + v1.TypedLocalObjectReference: + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + +optional + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + v1.TypedObjectReference: + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + +optional + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + +featureGate=CrossNamespaceVolumeDataSource + +optional + type: string + type: object + v1.Volume: + properties: + awsElasticBlockStore: + $ref: '#/definitions/v1.AWSElasticBlockStoreVolumeSource' + description: |- + awsElasticBlockStore represents an AWS Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + +optional + azureDisk: + $ref: '#/definitions/v1.AzureDiskVolumeSource' + description: |- + azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. + +optional + azureFile: + $ref: '#/definitions/v1.AzureFileVolumeSource' + description: |- + azureFile represents an Azure File Service mount on the host and bind mount to the pod. + +optional + cephfs: + $ref: '#/definitions/v1.CephFSVolumeSource' + description: |- + cephFS represents a Ceph FS mount on the host that shares a pod's lifetime + +optional + cinder: + $ref: '#/definitions/v1.CinderVolumeSource' + description: |- + cinder represents a cinder volume attached and mounted on kubelets host machine. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + +optional + configMap: + $ref: '#/definitions/v1.ConfigMapVolumeSource' + description: |- + configMap represents a configMap that should populate this volume + +optional + csi: + $ref: '#/definitions/v1.CSIVolumeSource' + description: |- + csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature). + +optional + downwardAPI: + $ref: '#/definitions/v1.DownwardAPIVolumeSource' + description: |- + downwardAPI represents downward API about the pod that should populate this volume + +optional + emptyDir: + $ref: '#/definitions/v1.EmptyDirVolumeSource' + description: |- + emptyDir represents a temporary directory that shares a pod's lifetime. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + +optional + ephemeral: + $ref: '#/definitions/v1.EphemeralVolumeSource' + description: |- + ephemeral represents a volume that is handled by a cluster storage driver. + The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, + and deleted when the pod is removed. + + Use this if: + a) the volume is only needed while the pod runs, + b) features of normal volumes like restoring from snapshot or capacity + tracking are needed, + c) the storage driver is specified through a storage class, and + d) the storage driver supports dynamic volume provisioning through + a PersistentVolumeClaim (see EphemeralVolumeSource for more + information on the connection between this volume type + and PersistentVolumeClaim). + + Use PersistentVolumeClaim or one of the vendor-specific + APIs for volumes that persist for longer than the lifecycle + of an individual pod. + + Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to + be used that way - see the documentation of the driver for + more information. + + A pod can use both types of ephemeral volumes and + persistent volumes at the same time. + + +optional + fc: + $ref: '#/definitions/v1.FCVolumeSource' + description: |- + fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. + +optional + flexVolume: + $ref: '#/definitions/v1.FlexVolumeSource' + description: |- + flexVolume represents a generic volume resource that is + provisioned/attached using an exec based plugin. + +optional + flocker: + $ref: '#/definitions/v1.FlockerVolumeSource' + description: |- + flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running + +optional + gcePersistentDisk: + $ref: '#/definitions/v1.GCEPersistentDiskVolumeSource' + description: |- + gcePersistentDisk represents a GCE Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + +optional + gitRepo: + $ref: '#/definitions/v1.GitRepoVolumeSource' + description: |- + gitRepo represents a git repository at a particular revision. + DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an + EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir + into the Pod's container. + +optional + glusterfs: + $ref: '#/definitions/v1.GlusterfsVolumeSource' + description: |- + glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. + More info: https://examples.k8s.io/volumes/glusterfs/README.md + +optional + hostPath: + $ref: '#/definitions/v1.HostPathVolumeSource' + description: |- + hostPath represents a pre-existing file or directory on the host + machine that is directly exposed to the container. This is generally + used for system agents or other privileged things that are allowed + to see the host machine. Most containers will NOT need this. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- + TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not + mount host directories as read/write. + +optional + iscsi: + $ref: '#/definitions/v1.ISCSIVolumeSource' + description: |- + iscsi represents an ISCSI Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://examples.k8s.io/volumes/iscsi/README.md + +optional + name: + description: |- + name of the volume. + Must be a DNS_LABEL and unique within the pod. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + nfs: + $ref: '#/definitions/v1.NFSVolumeSource' + description: |- + nfs represents an NFS mount on the host that shares a pod's lifetime + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + +optional + persistentVolumeClaim: + $ref: '#/definitions/v1.PersistentVolumeClaimVolumeSource' + description: |- + persistentVolumeClaimVolumeSource represents a reference to a + PersistentVolumeClaim in the same namespace. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + +optional + photonPersistentDisk: + $ref: '#/definitions/v1.PhotonPersistentDiskVolumeSource' + description: photonPersistentDisk represents a PhotonController persistent + disk attached and mounted on kubelets host machine + portworxVolume: + $ref: '#/definitions/v1.PortworxVolumeSource' + description: |- + portworxVolume represents a portworx volume attached and mounted on kubelets host machine + +optional + projected: + $ref: '#/definitions/v1.ProjectedVolumeSource' + description: projected items for all in one resources secrets, configmaps, + and downward API + quobyte: + $ref: '#/definitions/v1.QuobyteVolumeSource' + description: |- + quobyte represents a Quobyte mount on the host that shares a pod's lifetime + +optional + rbd: + $ref: '#/definitions/v1.RBDVolumeSource' + description: |- + rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. + More info: https://examples.k8s.io/volumes/rbd/README.md + +optional + scaleIO: + $ref: '#/definitions/v1.ScaleIOVolumeSource' + description: |- + scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. + +optional + secret: + $ref: '#/definitions/v1.SecretVolumeSource' + description: |- + secret represents a secret that should populate this volume. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + +optional + storageos: + $ref: '#/definitions/v1.StorageOSVolumeSource' + description: |- + storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. + +optional + vsphereVolume: + $ref: '#/definitions/v1.VsphereVirtualDiskVolumeSource' + description: |- + vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine + +optional + type: object + v1.VolumeDevice: + properties: + devicePath: + description: devicePath is the path inside of the container that the device + will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim in the pod + type: string + type: object + v1.VolumeMount: + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + +optional + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + +optional + type: boolean + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + +optional + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + +optional + type: string + type: object + v1.VolumeProjection: + properties: + configMap: + $ref: '#/definitions/v1.ConfigMapProjection' + description: |- + configMap information about the configMap data to project + +optional + downwardAPI: + $ref: '#/definitions/v1.DownwardAPIProjection' + description: |- + downwardAPI information about the downwardAPI data to project + +optional + secret: + $ref: '#/definitions/v1.SecretProjection' + description: |- + secret information about the secret data to project + +optional + serviceAccountToken: + $ref: '#/definitions/v1.ServiceAccountTokenProjection' + description: |- + serviceAccountToken is information about the serviceAccountToken data to project + +optional + type: object + v1.VsphereVirtualDiskVolumeSource: + properties: + fsType: + description: |- + fsType is filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + +optional + type: string + storagePolicyID: + description: |- + storagePolicyID is the storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName. + +optional + type: string + storagePolicyName: + description: |- + storagePolicyName is the storage Policy Based Management (SPBM) profile name. + +optional + type: string + volumePath: + description: volumePath is the path that identifies vSphere volume vmdk + type: string + type: object + v1.WindowsSecurityContextOptions: + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + +optional + type: string + gmsaCredentialSpecName: + description: |- + GMSACredentialSpecName is the name of the GMSA credential spec to use. + +optional + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + +optional + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + +optional + type: string + type: object + v1alpha1.AWSChaosSpec: + properties: + action: + description: |- + Action defines the specific aws chaos action. + Supported action: ec2-stop / ec2-restart / detach-volume + Default action: ec2-stop + +kubebuilder:validation:Enum=ec2-stop;ec2-restart;detach-volume + type: string + awsRegion: + description: AWSRegion defines the region of aws. + type: string + deviceName: + description: |- + DeviceName indicates the name of the device. + Needed in detach-volume. + +ui:form:when=action=='detach-volume' + +optional + type: string + duration: + description: |- + Duration represents the duration of the chaos action. + +optional + type: string + ec2Instance: + description: Ec2Instance indicates the ID of the ec2 instance. + type: string + endpoint: + description: |- + Endpoint indicates the endpoint of the aws server. Just used it in test now. + +ui:form:ignore + +optional + type: string + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + secretName: + description: |- + SecretName defines the name of kubernetes secret. + +optional + type: string + volumeID: + description: |- + EbsVolume indicates the ID of the EBS volume. + Needed in detach-volume. + +ui:form:when=action=='detach-volume' + +optional + type: string + type: object + v1alpha1.AttrOverrideSpec: + properties: + atime: + $ref: '#/definitions/v1alpha1.Timespec' + description: +optional + blocks: + description: +optional + type: integer + ctime: + $ref: '#/definitions/v1alpha1.Timespec' + description: +optional + gid: + description: +optional + type: integer + ino: + description: +optional + type: integer + kind: + description: +optional + type: string + mtime: + $ref: '#/definitions/v1alpha1.Timespec' + description: +optional + nlink: + description: +optional + type: integer + perm: + description: +optional + type: integer + rdev: + description: +optional + type: integer + size: + description: +optional + type: integer + uid: + description: +optional + type: integer + type: object + v1alpha1.AzureChaosSpec: + properties: + action: + description: |- + Action defines the specific azure chaos action. + Supported action: vm-stop / vm-restart / disk-detach + Default action: vm-stop + +kubebuilder:validation:Enum=vm-stop;vm-restart;disk-detach + type: string + diskName: + description: |- + DiskName indicates the name of the disk. + Needed in disk-detach. + +optional + type: string + duration: + description: |- + Duration represents the duration of the chaos action. + +optional + type: string + lun: + description: |- + LUN indicates the Logical Unit Number of the data disk. + Needed in disk-detach. + +optional + type: integer + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + resourceGroupName: + description: ResourceGroupName defines the name of ResourceGroup + type: string + secretName: + description: |- + SecretName defines the name of kubernetes secret. It is used for Azure credentials. + +optional + type: string + subscriptionID: + description: SubscriptionID defines the id of Azure subscription. + type: string + vmName: + description: VMName defines the name of Virtual Machine + type: string + type: object + v1alpha1.BandwidthSpec: + properties: + buffer: + description: |- + Buffer is the maximum amount of bytes that tokens can be available for instantaneously. + +kubebuilder:validation:Minimum=1 + type: integer + limit: + description: |- + Limit is the number of bytes that can be queued waiting for tokens to become available. + +kubebuilder:validation:Minimum=1 + type: integer + minburst: + description: |- + Minburst specifies the size of the peakrate bucket. For perfect + accuracy, should be set to the MTU of the interface. If a + peakrate is needed, but some burstiness is acceptable, this + size can be raised. A 3000 byte minburst allows around 3mbit/s + of peakrate, given 1000 byte packets. + +optional + +kubebuilder:validation:Minimum=0 + type: integer + peakrate: + description: |- + Peakrate is the maximum depletion rate of the bucket. + The peakrate does not need to be set, it is only necessary + if perfect millisecond timescale shaping is required. + +optional + +kubebuilder:validation:Minimum=0 + type: integer + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, gbit, tbit, bps, + kbps, mbps, gbps, tbps unit. bps means bytes per second. + type: string + type: object + v1alpha1.BlockChaosSpec: + properties: + action: + description: |- + Action defines the specific block chaos action. + Supported action: delay + +kubebuilder:validation:Enum=delay + type: string + containerNames: + description: |- + ContainerNames indicates list of the name of affected container. + If not set, the first container will be injected + +optional + items: + type: string + type: array + delay: + $ref: '#/definitions/v1alpha1.BlockDelaySpec' + description: |- + Delay defines the delay distribution. + +optional + duration: + description: |- + Duration represents the duration of the chaos action. + +optional + type: string + mode: + description: |- + Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent + +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent + type: string + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + selector: + $ref: '#/definitions/v1alpha1.PodSelectorSpec' + description: Selector is used to select pods that are used to inject chaos + action. + value: + description: |- + Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action + +optional + type: string + volumeName: + type: string + type: object + v1alpha1.BlockDelaySpec: + properties: + correlation: + default: "0" + description: +optional + type: string + jitter: + default: 0ms + description: +optional + type: string + latency: + description: Latency defines the latency of every io request. + type: string + type: object + v1alpha1.CPUStressor: + properties: + load: + description: |- + Load specifies P percent loading per CPU worker. 0 is effectively a sleep (no load) and 100 + is full loading. + +kubebuilder:validation:Minimum=0 + +kubebuilder:validation:Maximum=100 + +optional + type: integer + options: + description: |- + extend stress-ng options + +optional + items: + type: string + type: array + workers: + description: |- + Workers specifies N workers to apply the stressor. + Maximum 8192 workers can run by stress-ng + +kubebuilder:validation:Maximum=8192 + type: integer + type: object + v1alpha1.ChaosOnlyScheduleSpec: + properties: + awsChaos: + $ref: '#/definitions/v1alpha1.AWSChaosSpec' + description: +optional + azureChaos: + $ref: '#/definitions/v1alpha1.AzureChaosSpec' + description: +optional + blockChaos: + $ref: '#/definitions/v1alpha1.BlockChaosSpec' + description: +optional + concurrencyPolicy: + description: |- + +optional + +kubebuilder:validation:Enum=Forbid;Allow + type: string + dnsChaos: + $ref: '#/definitions/v1alpha1.DNSChaosSpec' + description: +optional + gcpChaos: + $ref: '#/definitions/v1alpha1.GCPChaosSpec' + description: +optional + historyLimit: + description: |- + +optional + +kubebuilder:validation:Minimum=1 + type: integer + httpChaos: + $ref: '#/definitions/v1alpha1.HTTPChaosSpec' + description: +optional + ioChaos: + $ref: '#/definitions/v1alpha1.IOChaosSpec' + description: +optional + jvmChaos: + $ref: '#/definitions/v1alpha1.JVMChaosSpec' + description: +optional + kernelChaos: + $ref: '#/definitions/v1alpha1.KernelChaosSpec' + description: +optional + networkChaos: + $ref: '#/definitions/v1alpha1.NetworkChaosSpec' + description: +optional + physicalmachineChaos: + $ref: '#/definitions/v1alpha1.PhysicalMachineChaosSpec' + description: +optional + podChaos: + $ref: '#/definitions/v1alpha1.PodChaosSpec' + description: +optional + schedule: + type: string + startingDeadlineSeconds: + description: |- + +optional + +nullable + +kubebuilder:validation:Minimum=0 + type: integer + stressChaos: + $ref: '#/definitions/v1alpha1.StressChaosSpec' + description: +optional + timeChaos: + $ref: '#/definitions/v1alpha1.TimeChaosSpec' + description: +optional + type: + type: string + type: object + v1alpha1.ClockSpec: + properties: + clock-ids-slice: + description: |- + the identifier of the particular clock on which to act. + More clock description in linux kernel can be found in man page of clock_getres, clock_gettime, clock_settime. + Muti clock ids should be split with "," + type: string + pid: + description: the pid of target program. + type: integer + time-offset: + description: specifies the length of time offset. + type: string + type: object + v1alpha1.ConditionalBranch: + properties: + expression: + description: |- + Expression is the expression for this conditional branch, expected type of result is boolean. If expression is empty, this branch will always be selected/the template will be spawned. + +optional + type: string + target: + description: Target is the name of other template, if expression is evaluated + as true, this template will be spawned. + type: string + type: object + v1alpha1.CorruptSpec: + properties: + correlation: + default: "0" + description: +optional + type: string + corrupt: + type: string + type: object + v1alpha1.DNSChaosSpec: + properties: + action: + description: |- + Action defines the specific DNS chaos action. + Supported action: error, random + Default action: error + +kubebuilder:validation:Enum=error;random + type: string + containerNames: + description: |- + ContainerNames indicates list of the name of affected container. + If not set, the first container will be injected + +optional + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: |- + Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent + +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent + type: string + patterns: + description: "Choose which domain names to take effect, support the placeholder + ? and wildcard *, or the Specified domain name.\nNote:\n 1. The wildcard + * must be at the end of the string. For example, chaos-*.org is invalid.\n + \ 2. if the patterns is empty, will take effect on all the domain names.\nFor + example:\n\t\tThe value is [\"google.com\", \"github.*\", \"chaos-mes?.org\"],\n\t\twill + take effect on \"google.com\", \"github.com\" and \"chaos-mesh.org\"\n+optional" + items: + type: string + type: array + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + selector: + $ref: '#/definitions/v1alpha1.PodSelectorSpec' + description: Selector is used to select pods that are used to inject chaos + action. + value: + description: |- + Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action + +optional + type: string + type: object + v1alpha1.DelaySpec: + properties: + correlation: + default: "0" + description: +optional + type: string + jitter: + default: 0ms + description: +optional + type: string + latency: + type: string + reorder: + $ref: '#/definitions/v1alpha1.ReorderSpec' + description: +optional + type: object + v1alpha1.DiskFillSpec: + properties: + fill-by-fallocate: + description: fill disk by fallocate + type: boolean + path: + description: |- + specifies the location to fill data in. if path not provided, + payload will read/write from/into a temp file, temp file will be deleted after writing + type: string + size: + description: |- + specifies how many units of data will write into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 BYTES. example : 1M | 512kB + type: string + type: object + v1alpha1.DiskPayloadSpec: + properties: + path: + description: |- + specifies the location to fill data in. if path not provided, + payload will read/write from/into a temp file, temp file will be deleted after writing + type: string + payload-process-num: + description: specifies the number of process work on writing, default 1, only + 1-255 is valid value + type: integer + size: + description: |- + specifies how many units of data will write into the file path. support unit: c=1, w=2, b=512, kB=1000, + K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 BYTES. example : 1M | 512kB + type: string + type: object + v1alpha1.DuplicateSpec: + properties: + correlation: + default: "0" + description: +optional + type: string + duplicate: + type: string + type: object + v1alpha1.FailKernRequest: + properties: + callchain: + description: |- + Callchain indicate a special call chain, such as: + ext4_mount + -> mount_subtree + -> ... + -> should_failslab + With an optional set of predicates and an optional set of + parameters, which used with predicates. You can read call chan + and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples + to learn more. + If no special call chain, just keep Callchain empty, which means it will fail at any call chain + with slab alloc (eg: kmalloc). + items: + $ref: '#/definitions/v1alpha1.Frame' + type: array + failtype: + description: |- + FailType indicates what to fail, can be set to '0' / '1' / '2' + If `0`, indicates slab to fail (should_failslab) + If `1`, indicates alloc_page to fail (should_fail_alloc_page) + If `2`, indicates bio to fail (should_fail_bio) + You can read: + 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt + to learn more + +kubebuilder:validation:Maximum=2 + +kubebuilder:validation:Minimum=0 + type: integer + headers: + description: |- + Headers indicates the appropriate kernel headers you need. + Eg: "linux/mmzone.h", "linux/blkdev.h" and so on + items: + type: string + type: array + probability: + description: |- + Probability indicates the fails with probability. + If you want 1%, please set this field with 1. + +kubebuilder:validation:Minimum=0 + +kubebuilder:validation:Maximum=100 + type: integer + times: + description: |- + Times indicates the max times of fails. + +kubebuilder:validation:Minimum=0 + type: integer + type: object + v1alpha1.FileAppendSpec: + properties: + count: + description: Count is the number of times to append the data. + type: integer + data: + description: Data is the data for append. + type: string + file-name: + description: FileName is the name of the file to be created, modified, deleted, + renamed, or appended. + type: string + type: object + v1alpha1.FileCreateSpec: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, modified, deleted, + renamed, or appended. + type: string + type: object + v1alpha1.FileDeleteSpec: + properties: + dir-name: + description: DirName is the directory name to create or delete. + type: string + file-name: + description: FileName is the name of the file to be created, modified, deleted, + renamed, or appended. + type: string + type: object + v1alpha1.FileModifyPrivilegeSpec: + properties: + file-name: + description: FileName is the name of the file to be created, modified, deleted, + renamed, or appended. + type: string + privilege: + description: Privilege is the file privilege to be set. + type: integer + type: object + v1alpha1.FileRenameSpec: + properties: + dest-file: + description: DestFile is the name to be renamed. + type: string + source-file: + description: SourceFile is the name need to be renamed. + type: string + type: object + v1alpha1.FileReplaceSpec: + properties: + dest-string: + description: DestStr is the destination string of the file. + type: string + file-name: + description: FileName is the name of the file to be created, modified, deleted, + renamed, or appended. + type: string + line: + description: Line is the line number of the file to be replaced. + type: integer + origin-string: + description: OriginStr is the origin string of the file. + type: string + type: object + v1alpha1.Frame: + properties: + funcname: + description: Funcname can be find from kernel source or `/proc/kallsyms`, + such as `ext4_mount` + type: string + parameters: + description: |- + Parameters is used with predicate, for example, if you want to inject slab error + in `d_alloc_parallel(struct dentry *parent, const struct qstr *name)` with a special + name `bananas`, you need to set it to `struct dentry *parent, const struct qstr *name` + otherwise omit it. + type: string + predicate: + description: |- + Predicate will access the arguments of this Frame, example with Parameters's, you can + set it to `STRNCMP(name->name, "bananas", 8)` to make inject only with it, or omit it + to inject for all d_alloc_parallel call chain. + type: string + type: object + v1alpha1.GCPChaosSpec: + properties: + action: + description: |- + Action defines the specific gcp chaos action. + Supported action: node-stop / node-reset / disk-loss + Default action: node-stop + +kubebuilder:validation:Enum=node-stop;node-reset;disk-loss + type: string + deviceNames: + description: |- + The device name of disks to detach. + Needed in disk-loss. + +ui:form:when=action=='disk-loss' + +optional + items: + type: string + type: array + duration: + description: |- + Duration represents the duration of the chaos action. + +optional + type: string + instance: + description: Instance defines the name of the instance + type: string + project: + description: Project defines the ID of gcp project. + type: string + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + secretName: + description: |- + SecretName defines the name of kubernetes secret. It is used for GCP credentials. + +optional + type: string + zone: + description: Zone defines the zone of gcp project. + type: string + type: object + v1alpha1.HTTPAbortSpec: + properties: + code: + description: Code is a rule to select target by http status code in response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens on + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, we will only + attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + type: object + v1alpha1.HTTPChaosSpec: + properties: + abort: + description: |- + Abort is a rule to abort a http session. + +optional + type: boolean + code: + description: |- + Code is a rule to select target by http status code in response. + +optional + type: integer + delay: + description: |- + Delay represents the delay of the target request/response. + A duration string is a possibly unsigned sequence of + decimal numbers, each with optional fraction and a unit suffix, + such as "300ms", "2h45m". + Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + +optional + type: string + duration: + description: |- + Duration represents the duration of the chaos action. + +optional + type: string + method: + description: |- + Method is a rule to select target by http method in request. + +optional + type: string + mode: + description: |- + Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent + +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent + type: string + patch: + $ref: '#/definitions/v1alpha1.PodHttpChaosPatchActions' + description: |- + Patch is a rule to patch some contents in target. + +optional + path: + description: |- + Path is a rule to select target by uri path in http request. + +optional + type: string + port: + description: Port represents the target port to be proxy of. + type: integer + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + replace: + $ref: '#/definitions/v1alpha1.PodHttpChaosReplaceActions' + description: |- + Replace is a rule to replace some contents in target. + +optional + request_headers: + additionalProperties: + type: string + description: |- + RequestHeaders is a rule to select target by http headers in request. + The key-value pairs represent header name and header value pairs. + +optional + type: object + response_headers: + additionalProperties: + type: string + description: |- + ResponseHeaders is a rule to select target by http headers in response. + The key-value pairs represent header name and header value pairs. + +optional + type: object + selector: + $ref: '#/definitions/v1alpha1.PodSelectorSpec' + description: Selector is used to select pods that are used to inject chaos + action. + target: + description: |- + Target is the object to be selected and injected. + +kubebuilder:validation:Enum=Request;Response + type: string + tls: + $ref: '#/definitions/v1alpha1.PodHttpChaosTLS' + description: |- + TLS is the tls config, + will override PodHttpChaos if there are multiple HTTPChaos experiments are applied + +optional + value: + description: |- + Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action + +optional + type: string + type: object + v1alpha1.HTTPConfigSpec: + properties: + file_path: + description: The config file path + type: string + type: object + v1alpha1.HTTPCriteria: + properties: + statusCode: + description: |- + StatusCode defines the expected http status code for the request. + A statusCode string could be a single code (e.g. 200), or + an inclusive range (e.g. 200-400, both `200` and `400` are included). + type: string + type: object + v1alpha1.HTTPDelaySpec: + properties: + code: + description: Code is a rule to select target by http status code in response + type: string + delay: + description: Delay represents the delay of the target request/response + type: string + method: + description: HTTP method + type: string + path: + description: Match path of Uri with wildcard matches + type: string + port: + description: The TCP port that the target service listens on + type: integer + proxy_ports: + description: Composed with one of the port of HTTP connection, we will only + attack HTTP connection with port inside proxy_ports + items: + type: integer + type: array + target: + description: 'HTTP target: Request or Response' + type: string + type: object + v1alpha1.HTTPRequestSpec: + properties: + count: + description: The number of requests to send + type: integer + enable-conn-pool: + description: Enable connection pool + type: boolean + url: + description: Request to send" + type: string + type: object + v1alpha1.HTTPStatusCheck: + properties: + body: + description: +optional + type: string + criteria: + $ref: '#/definitions/v1alpha1.HTTPCriteria' + description: Criteria defines how to determine the result of the status check. + headers: + $ref: '#/definitions/http.Header' + description: +optional + method: + description: |- + +optional + +kubebuilder:validation:Enum=GET;POST + +kubebuilder:default=GET + type: string + url: + type: string + type: object + v1alpha1.IOChaosSpec: + properties: + action: + description: |- + Action defines the specific pod chaos action. + Supported action: latency / fault / attrOverride / mistake + +kubebuilder:validation:Enum=latency;fault;attrOverride;mistake + type: string + attr: + $ref: '#/definitions/v1alpha1.AttrOverrideSpec' + description: |- + Attr defines the overrided attribution + +ui:form:when=action=='attrOverride' + +optional + containerNames: + description: |- + ContainerNames indicates list of the name of affected container. + If not set, the first container will be injected + +optional + items: + type: string + type: array + delay: + description: |- + Delay defines the value of I/O chaos action delay. + A delay string is a possibly signed sequence of + decimal numbers, each with optional fraction and a unit suffix, + such as "300ms". + Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + +ui:form:when=action=='latency' + +optional + type: string + duration: + description: |- + Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. + 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". + +optional + type: string + errno: + description: |- + Errno defines the error code that returned by I/O action. + refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html + +ui:form:when=action=='fault' + +optional + type: integer + methods: + description: |- + Methods defines the I/O methods for injecting I/O chaos action. + default: all I/O methods. + +optional + items: + type: string + type: array + mistake: + $ref: '#/definitions/v1alpha1.MistakeSpec' + description: |- + Mistake defines what types of incorrectness are injected to IO operations + +ui:form:when=action=='mistake' + +optional + mode: + description: |- + Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent + +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent + type: string + path: + description: |- + Path defines the path of files for injecting I/O chaos action. + +optional + type: string + percent: + description: |- + Percent defines the percentage of injection errors and provides a number from 0-100. + default: 100. + +optional + +kubebuilder:default=100 + type: integer + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + selector: + $ref: '#/definitions/v1alpha1.PodSelectorSpec' + description: Selector is used to select pods that are used to inject chaos + action. + value: + description: |- + Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action + +optional + type: string + volumePath: + description: VolumePath represents the mount path of injected volume + type: string + type: object + v1alpha1.JVMChaosSpec: + properties: + action: + description: |- + Action defines the specific jvm chaos action. + Supported action: latency;return;exception;stress;gc;ruleData + +kubebuilder:validation:Enum=latency;return;exception;stress;gc;ruleData;mysql + type: string + class: + description: |- + +optional + Java class + type: string + containerNames: + description: |- + ContainerNames indicates list of the name of affected container. + If not set, the first container will be injected + +optional + items: + type: string + type: array + cpuCount: + description: |- + +optional + the CPU core number needs to use, only set it when action is stress + type: integer + database: + description: |- + the match database + default value is "", means match all database + type: string + duration: + description: |- + Duration represents the duration of the chaos action + +optional + type: string + exception: + description: |- + +optional + the exception which needs to throw for action `exception` + or the exception message needs to throw in action `mysql` + type: string + latency: + description: |- + +optional + the latency duration for action 'latency', unit ms + or the latency duration in action `mysql` + type: integer + memType: + description: |- + +optional + the memory type needs to locate, only set it when action is stress, the value can be 'stack' or 'heap' + type: string + method: + description: |- + +optional + the method in Java class + type: string + mode: + description: |- + Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent + +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent + type: string + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support 5.X.X(set to + "5") and 8.X.X(set to "8") now + type: string + name: + description: |- + +optional + byteman rule name, should be unique, and will generate one if not set + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: |- + +optional + the port of agent server, default 9277 + type: integer + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + ruleData: + description: |- + +optional + the byteman rule's data for action 'ruleData' + type: string + selector: + $ref: '#/definitions/v1alpha1.PodSelectorSpec' + description: Selector is used to select pods that are used to inject chaos + action. + sqlType: + description: |- + the match sql type + default value is "", means match all SQL type. + The value can be 'select', 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: |- + the match table + default value is "", means match all table + type: string + value: + description: |- + +optional + the return value for action 'return' + type: string + type: object + v1alpha1.JVMExceptionSpec: + properties: + class: + description: |- + +optional + Java class + type: string + exception: + description: the exception which needs to throw for action `exception` + type: string + method: + description: |- + +optional + the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: |- + +optional + the port of agent server, default 9277 + type: integer + type: object + v1alpha1.JVMGCSpec: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: |- + +optional + the port of agent server, default 9277 + type: integer + type: object + v1alpha1.JVMLatencySpec: + properties: + class: + description: |- + +optional + Java class + type: string + latency: + description: the latency duration for action 'latency', unit ms + type: integer + method: + description: |- + +optional + the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: |- + +optional + the port of agent server, default 9277 + type: integer + type: object + v1alpha1.JVMReturnSpec: + properties: + class: + description: |- + +optional + Java class + type: string + method: + description: |- + +optional + the method in Java class + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: |- + +optional + the port of agent server, default 9277 + type: integer + value: + description: the return value for action 'return' + type: string + type: object + v1alpha1.JVMRuleDataSpec: + properties: + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: |- + +optional + the port of agent server, default 9277 + type: integer + rule-data: + description: RuleData used to save the rule file's data, will use it when + recover + type: string + type: object + v1alpha1.JVMStressSpec: + properties: + cpu-count: + description: the CPU core number need to use, only set it when action is stress + type: integer + mem-type: + description: the memory type need to locate, only set it when action is stress, + the value can be 'stack' or 'heap' + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: |- + +optional + the port of agent server, default 9277 + type: integer + type: object + v1alpha1.KafkaFillSpec: + properties: + host: + description: The host of kafka server + type: string + maxBytes: + description: The max bytes to fill + type: integer + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + reloadCommand: + description: The command to reload kafka config + type: string + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + v1alpha1.KafkaFloodSpec: + properties: + host: + description: The host of kafka server + type: string + messageSize: + description: The size of each message + type: integer + password: + description: The password of kafka client + type: string + port: + description: The port of kafka server + type: integer + threads: + description: The number of worker threads + type: integer + topic: + description: The topic to attack + type: string + username: + description: The username of kafka client + type: string + type: object + v1alpha1.KafkaIOSpec: + properties: + configFile: + description: The path of server config + type: string + nonReadable: + description: Make kafka cluster non-readable + type: boolean + nonWritable: + description: Make kafka cluster non-writable + type: boolean + topic: + description: The topic to attack + type: string + type: object + v1alpha1.KernelChaosSpec: + properties: + containerNames: + description: |- + ContainerNames indicates list of the name of affected container. + If not set, the first container will be injected + +optional + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + failKernRequest: + $ref: '#/definitions/v1alpha1.FailKernRequest' + description: FailKernRequest defines the request of kernel injection + mode: + description: |- + Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent + +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent + type: string + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + selector: + $ref: '#/definitions/v1alpha1.PodSelectorSpec' + description: Selector is used to select pods that are used to inject chaos + action. + value: + description: |- + Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action + +optional + type: string + type: object + v1alpha1.LossSpec: + properties: + correlation: + default: "0" + description: +optional + type: string + loss: + type: string + type: object + v1alpha1.MemoryStressor: + properties: + oomScoreAdj: + description: |- + OOMScoreAdj sets the oom_score_adj of the stress process. See `man 5 proc` to know more + about this option. + +kubebuilder:validation:Minimum=-1000 + +kubebuilder:validation:Maximum=1000 + +kubebuilder:default=0 + +optional + type: integer + options: + description: |- + extend stress-ng options + +optional + items: + type: string + type: array + size: + description: |- + Size specifies N bytes consumed per vm worker, default is the total available memory. + One can specify the size as % of total available memory or in units of B, KB/KiB, + MB/MiB, GB/GiB, TB/TiB. + +optional + type: string + workers: + description: |- + Workers specifies N workers to apply the stressor. + Maximum 8192 workers can run by stress-ng + +kubebuilder:validation:Maximum=8192 + type: integer + type: object + v1alpha1.MistakeSpec: + properties: + filling: + description: |- + Filling determines what is filled in the mistake data. + +optional + +kubebuilder:validation:Enum=zero;random + type: string + maxLength: + description: |- + Max length of each wrong data segment in bytes + +optional + +kubebuilder:validation:Minimum=1 + type: integer + maxOccurrences: + description: |- + There will be [1, MaxOccurrences] segments of wrong data. + +optional + +kubebuilder:validation:Minimum=1 + type: integer + type: object + v1alpha1.NetworkBandwidthSpec: + properties: + buffer: + description: +kubebuilder:validation:Minimum=1 + type: integer + device: + type: string + hostname: + type: string + ip-address: + type: string + limit: + description: +kubebuilder:validation:Minimum=1 + type: integer + minburst: + type: integer + peakrate: + type: integer + rate: + type: string + type: object + v1alpha1.NetworkChaosSpec: + properties: + action: + description: |- + Action defines the specific network chaos action. + Supported action: partition, netem, delay, loss, duplicate, corrupt + Default action: delay + +kubebuilder:validation:Enum=netem;delay;loss;duplicate;corrupt;partition;bandwidth + type: string + bandwidth: + $ref: '#/definitions/v1alpha1.BandwidthSpec' + description: |- + Bandwidth represents the detail about bandwidth control action + +ui:form:when=action=='bandwidth' + +optional + corrupt: + $ref: '#/definitions/v1alpha1.CorruptSpec' + description: |- + Corrupt represents the detail about corrupt action + +ui:form:when=action=='corrupt' + +optional + delay: + $ref: '#/definitions/v1alpha1.DelaySpec' + description: |- + Delay represents the detail about delay action + +ui:form:when=action=='delay' + +optional + device: + description: |- + Device represents the network device to be affected. + +optional + type: string + direction: + description: |- + Direction represents the direction, this applies on netem and network partition action + +optional + +kubebuilder:validation:Enum=to;from;both + +kubebuilder:default=to + type: string + duplicate: + $ref: '#/definitions/v1alpha1.DuplicateSpec' + description: |- + DuplicateSpec represents the detail about loss action + +ui:form:when=action=='duplicate' + +optional + duration: + description: Duration represents the duration of the chaos action + type: string + externalTargets: + description: |- + ExternalTargets represents network targets outside k8s + +optional + items: + type: string + type: array + loss: + $ref: '#/definitions/v1alpha1.LossSpec' + description: |- + Loss represents the detail about loss action + +ui:form:when=action=='loss' + +optional + mode: + description: |- + Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent + +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent + type: string + rate: + $ref: '#/definitions/v1alpha1.RateSpec' + description: |- + Rate represents the detail about rate control action + +ui:form:when=action=='rate' + +optional + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + selector: + $ref: '#/definitions/v1alpha1.PodSelectorSpec' + description: Selector is used to select pods that are used to inject chaos + action. + target: + $ref: '#/definitions/v1alpha1.PodSelector' + description: |- + Target represents network target, this applies on netem and network partition action + +optional + targetDevice: + description: |- + TargetDevice represents the network device to be affected in target scope. + +optional + type: string + value: + description: |- + Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action + +optional + type: string + type: object + v1alpha1.NetworkCorruptSpec: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: |- + only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: tcp, + udp, icmp, all' + type: string + percent: + description: percentage of packets to corrupt (10 is 10%) + type: string + source-port: + description: |- + only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p tcp or -p udp + type: string + type: object + v1alpha1.NetworkDNSSpec: + properties: + dns-domain-name: + description: map this host to specified IP + type: string + dns-ip: + description: map specified host to this IP address + type: string + dns-server: + description: update the DNS server in /etc/resolv.conf with this value + type: string + type: object + v1alpha1.NetworkDelaySpec: + properties: + accept-tcp-flags: + description: |- + only the packet which match the tcp flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used for partition. + type: string + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: |- + only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: tcp, + udp, icmp, all' + type: string + jitter: + description: 'jitter time, time units: ns, us (or µs), ms, s, m, h.' + type: string + latency: + description: 'delay egress time, time units: ns, us (or µs), ms, s, m, h.' + type: string + source-port: + description: |- + only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p tcp or -p udp + type: string + type: object + v1alpha1.NetworkDownSpec: + properties: + device: + description: The network interface to impact + type: string + duration: + description: 'NIC down time, time units: ns, us (or µs), ms, s, m, h.' + type: string + type: object + v1alpha1.NetworkDuplicateSpec: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: |- + only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: tcp, + udp, icmp, all' + type: string + percent: + description: percentage of packets to duplicate (10 is 10%) + type: string + source-port: + description: |- + only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p tcp or -p udp + type: string + type: object + v1alpha1.NetworkFloodSpec: + properties: + duration: + description: The number of seconds to run the iperf test + type: string + ip-address: + description: Generate traffic to this IP address + type: string + parallel: + description: The number of iperf parallel client threads to run + type: integer + port: + description: Generate traffic to this port on the IP address + type: string + rate: + description: The speed of network traffic, allows bps, kbps, mbps, gbps, tbps + unit. bps means bytes per second + type: string + type: object + v1alpha1.NetworkLossSpec: + properties: + correlation: + description: correlation is percentage (10 is 10%) + type: string + device: + description: the network interface to impact + type: string + egress-port: + description: |- + only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p tcp or -p udp + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: 'only impact traffic using this IP protocol, supported: tcp, + udp, icmp, all' + type: string + percent: + description: percentage of packets to loss (10 is 10%) + type: string + source-port: + description: |- + only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. + it can only be used in conjunction with -p tcp or -p udp + type: string + type: object + v1alpha1.NetworkPartitionSpec: + properties: + accept-tcp-flags: + description: |- + only the packet which match the tcp flag can be accepted, others will be dropped. + only set when the IPProtocol is tcp, used for partition. + type: string + device: + description: the network interface to impact + type: string + direction: + description: |- + specifies the partition direction, values can be 'from', 'to'. + 'from' means packets coming from the 'IPAddress' or 'Hostname' and going to your server, + 'to' means packets originating from your server and going to the 'IPAddress' or 'Hostname'. + type: string + hostname: + description: only impact traffic to these hostnames + type: string + ip-address: + description: only impact egress traffic to these IP addresses + type: string + ip-protocol: + description: only impact egress traffic to these IP addresses + type: string + type: object + v1alpha1.PMJVMMySQLSpec: + properties: + database: + description: |- + the match database + default value is "", means match all database + type: string + exception: + description: |- + The exception which needs to throw for action `exception` + or the exception message needs to throw in action `mysql` + type: string + latency: + description: |- + The latency duration for action 'latency' + or the latency duration in action `mysql` + type: integer + mysqlConnectorVersion: + description: the version of mysql-connector-java, only support 5.X.X(set to + "5") and 8.X.X(set to "8") now + type: string + pid: + description: the pid of Java process which needs to attach + type: integer + port: + description: |- + +optional + the port of agent server, default 9277 + type: integer + sqlType: + description: |- + the match sql type + default value is "", means match all SQL type. + The value can be 'select', 'insert', 'update', 'delete', 'replace'. + type: string + table: + description: |- + the match table + default value is "", means match all table + type: string + type: object + v1alpha1.PhysicalMachineChaosSpec: + properties: + action: + description: +kubebuilder:validation:Enum=stress-cpu;stress-mem;disk-read-payload;disk-write-payload;disk-fill;network-corrupt;network-duplicate;network-loss;network-delay;network-partition;network-dns;network-bandwidth;network-flood;network-down;process;jvm-exception;jvm-gc;jvm-latency;jvm-return;jvm-stress;jvm-rule-data;jvm-mysql;clock;redis-expiration;redis-penetration;redis-cacheLimit;redis-restart;redis-stop;kafka-fill;kafka-flood;kafka-io;file-create;file-modify;file-delete;file-rename;file-append;file-replace;vm;user_defined + type: string + address: + description: |- + DEPRECATED: Use Selector instead. + Only one of Address and Selector could be specified. + +optional + items: + type: string + type: array + clock: + $ref: '#/definitions/v1alpha1.ClockSpec' + description: |- + +ui:form:when=action=='clock' + +optional + disk-fill: + $ref: '#/definitions/v1alpha1.DiskFillSpec' + description: |- + +ui:form:when=action=='disk-fill' + +optional + disk-read-payload: + $ref: '#/definitions/v1alpha1.DiskPayloadSpec' + description: |- + +ui:form:when=action=='disk-read-payload' + +optional + disk-write-payload: + $ref: '#/definitions/v1alpha1.DiskPayloadSpec' + description: |- + +ui:form:when=action=='disk-write-payload' + +optional + duration: + description: |- + Duration represents the duration of the chaos action + +optional + type: string + file-append: + $ref: '#/definitions/v1alpha1.FileAppendSpec' + description: |- + +ui:form:when=action=='file-append' + +optional + file-create: + $ref: '#/definitions/v1alpha1.FileCreateSpec' + description: |- + +ui:form:when=action=='file-create' + +optional + file-delete: + $ref: '#/definitions/v1alpha1.FileDeleteSpec' + description: |- + +ui:form:when=action=='file-delete' + +optional + file-modify: + $ref: '#/definitions/v1alpha1.FileModifyPrivilegeSpec' + description: |- + +ui:form:when=action=='file-modify' + +optional + file-rename: + $ref: '#/definitions/v1alpha1.FileRenameSpec' + description: |- + +ui:form:when=action=='file-create' + +optional + file-replace: + $ref: '#/definitions/v1alpha1.FileReplaceSpec' + description: |- + +ui:form:when=action=='file-replace' + +optional + http-abort: + $ref: '#/definitions/v1alpha1.HTTPAbortSpec' + description: |- + +ui:form:when=action=='http-abort' + +optional + http-config: + $ref: '#/definitions/v1alpha1.HTTPConfigSpec' + description: |- + +ui:form:when=action=='http-config' + +optional + http-delay: + $ref: '#/definitions/v1alpha1.HTTPDelaySpec' + description: |- + +ui:form:when=action=='http-delay' + +optional + http-request: + $ref: '#/definitions/v1alpha1.HTTPRequestSpec' + description: |- + +ui:form:when=action=='http-request' + +optional + jvm-exception: + $ref: '#/definitions/v1alpha1.JVMExceptionSpec' + description: |- + +ui:form:when=action=='jvm-exception' + +optional + jvm-gc: + $ref: '#/definitions/v1alpha1.JVMGCSpec' + description: |- + +ui:form:when=action=='jvm-gc' + +optional + jvm-latency: + $ref: '#/definitions/v1alpha1.JVMLatencySpec' + description: |- + +ui:form:when=action=='jvm-latency' + +optional + jvm-mysql: + $ref: '#/definitions/v1alpha1.PMJVMMySQLSpec' + description: |- + +ui:form:when=action=='jvm-mysql' + +optional + jvm-return: + $ref: '#/definitions/v1alpha1.JVMReturnSpec' + description: |- + +ui:form:when=action=='jvm-return' + +optional + jvm-rule-data: + $ref: '#/definitions/v1alpha1.JVMRuleDataSpec' + description: |- + +ui:form:when=action=='jvm-rule-data' + +optional + jvm-stress: + $ref: '#/definitions/v1alpha1.JVMStressSpec' + description: |- + +ui:form:when=action=='jvm-stress' + +optional + kafka-fill: + $ref: '#/definitions/v1alpha1.KafkaFillSpec' + description: |- + +ui:form:when=action=='kafka-fill' + +optional + kafka-flood: + $ref: '#/definitions/v1alpha1.KafkaFloodSpec' + description: |- + +ui:form:when=action=='kafka-flood' + +optional + kafka-io: + $ref: '#/definitions/v1alpha1.KafkaIOSpec' + description: |- + +ui:form:when=action=='kafka-io' + +optional + mode: + description: |- + Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent + +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent + type: string + network-bandwidth: + $ref: '#/definitions/v1alpha1.NetworkBandwidthSpec' + description: |- + +ui:form:when=action=='network-bandwidth' + +optional + network-corrupt: + $ref: '#/definitions/v1alpha1.NetworkCorruptSpec' + description: |- + +ui:form:when=action=='network-corrupt' + +optional + network-delay: + $ref: '#/definitions/v1alpha1.NetworkDelaySpec' + description: |- + +ui:form:when=action=='network-delay' + +optional + network-dns: + $ref: '#/definitions/v1alpha1.NetworkDNSSpec' + description: |- + +ui:form:when=action=='network-dns' + +optional + network-down: + $ref: '#/definitions/v1alpha1.NetworkDownSpec' + description: |- + +ui:form:when=action=='network-down' + +optional + network-duplicate: + $ref: '#/definitions/v1alpha1.NetworkDuplicateSpec' + description: |- + +ui:form:when=action=='network-duplicate' + +optional + network-flood: + $ref: '#/definitions/v1alpha1.NetworkFloodSpec' + description: |- + +ui:form:when=action=='network-flood' + +optional + network-loss: + $ref: '#/definitions/v1alpha1.NetworkLossSpec' + description: |- + +ui:form:when=action=='network-loss' + +optional + network-partition: + $ref: '#/definitions/v1alpha1.NetworkPartitionSpec' + description: |- + +ui:form:when=action=='network-partition' + +optional + process: + $ref: '#/definitions/v1alpha1.ProcessSpec' + description: |- + +ui:form:when=action=='process' + +optional + redis-cacheLimit: + $ref: '#/definitions/v1alpha1.RedisCacheLimitSpec' + description: |- + +ui:form:when=action=='redis-cacheLimit' + +optional + redis-expiration: + $ref: '#/definitions/v1alpha1.RedisExpirationSpec' + description: |- + +ui:form:when=action=='redis-expiration' + +optional + redis-penetration: + $ref: '#/definitions/v1alpha1.RedisPenetrationSpec' + description: |- + +ui:form:when=action=='redis-penetration' + +optional + redis-restart: + $ref: '#/definitions/v1alpha1.RedisSentinelRestartSpec' + description: |- + +ui:form:when=action=='redis-restart' + +optional + redis-stop: + $ref: '#/definitions/v1alpha1.RedisSentinelStopSpec' + description: |- + +ui:form:when=action=='redis-stop' + +optional + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + selector: + $ref: '#/definitions/v1alpha1.PhysicalMachineSelectorSpec' + description: |- + Selector is used to select physical machines that are used to inject chaos action. + +optional + stress-cpu: + $ref: '#/definitions/v1alpha1.StressCPUSpec' + description: |- + +ui:form:when=action=='stress-cpu' + +optional + stress-mem: + $ref: '#/definitions/v1alpha1.StressMemorySpec' + description: |- + +ui:form:when=action=='stress-mem' + +optional + user_defined: + $ref: '#/definitions/v1alpha1.UserDefinedSpec' + description: |- + +ui:form:when=action=='user_defined' + +optional + value: + description: |- + Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of physical machines to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify the percent of physical machines the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action + +optional + type: string + vm: + $ref: '#/definitions/v1alpha1.VMSpec' + description: |- + +ui:form:when=action=='vm' + +optional + type: object + v1alpha1.PhysicalMachineSelectorSpec: + properties: + annotationSelectors: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to select objects. + A selector based on annotations. + +optional + type: object + fieldSelectors: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to select objects. + A selector based on fields. + +optional + type: object + labelSelectors: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to select objects. + A selector based on labels. + +optional + type: object + namespaces: + description: |- + Namespaces is a set of namespace to which objects belong. + +optional + items: + type: string + type: array + physicalMachines: + additionalProperties: + items: + type: string + type: array + description: |- + PhysicalMachines is a map of string keys and a set values that used to select physical machines. + The key defines the namespace which physical machine belong, + and each value is a set of physical machine names. + +optional + type: object + type: object + v1alpha1.PodChaosSpec: + properties: + action: + description: |- + Action defines the specific pod chaos action. + Supported action: pod-kill / pod-failure / container-kill + Default action: pod-kill + +kubebuilder:validation:Enum=pod-kill;pod-failure;container-kill + type: string + containerNames: + description: |- + ContainerNames indicates list of the name of affected container. + If not set, the first container will be injected + +optional + items: + type: string + type: array + duration: + description: |- + Duration represents the duration of the chaos action. + It is required when the action is `PodFailureAction`. + 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". + +optional + type: string + gracePeriod: + description: |- + GracePeriod is used in pod-kill action. It represents the duration in seconds before the pod should be deleted. + Value must be non-negative integer. The default value is zero that indicates delete immediately. + +optional + +kubebuilder:validation:Minimum=0 + type: integer + mode: + description: |- + Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent + +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent + type: string + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + selector: + $ref: '#/definitions/v1alpha1.PodSelectorSpec' + description: Selector is used to select pods that are used to inject chaos + action. + value: + description: |- + Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action + +optional + type: string + type: object + v1alpha1.PodHttpChaosPatchActions: + properties: + body: + $ref: '#/definitions/v1alpha1.PodHttpChaosPatchBodyAction' + description: |- + Body is a rule to patch message body of target. + +optional + headers: + description: |- + Headers is a rule to append http headers of target. + For example: `[["Set-Cookie", ""], ["Set-Cookie", ""]]`. + +optional + items: + items: + type: string + type: array + type: array + queries: + description: |- + Queries is a rule to append uri queries of target(Request only). + For example: `[["foo", "bar"], ["foo", "unknown"]]`. + +optional + items: + items: + type: string + type: array + type: array + type: object + v1alpha1.PodHttpChaosPatchBodyAction: + properties: + type: + description: Type represents the patch type, only support `JSON` as [merge + patch json](https://tools.ietf.org/html/rfc7396) currently. + type: string + value: + description: Value is the patch contents. + type: string + type: object + v1alpha1.PodHttpChaosReplaceActions: + properties: + body: + description: |- + Body is a rule to replace http message body in target. + +optional + items: + type: integer + type: array + code: + description: |- + Code is a rule to replace http status code in response. + +optional + type: integer + headers: + additionalProperties: + type: string + description: |- + Headers is a rule to replace http headers of target. + The key-value pairs represent header name and header value pairs. + +optional + type: object + method: + description: |- + Method is a rule to replace http method in request. + +optional + type: string + path: + description: |- + Path is rule to to replace uri path in http request. + +optional + type: string + queries: + additionalProperties: + type: string + description: |- + Queries is a rule to replace uri queries in http request. + For example, with value `{ "foo": "unknown" }`, the `/?foo=bar` will be altered to `/?foo=unknown`, + +optional + type: object + type: object + v1alpha1.PodHttpChaosTLS: + properties: + caName: + description: |- + CAName represents the data name of ca file in secret, `ca.crt` for example + +optional + type: string + certName: + description: CertName represents the data name of cert file in secret, `tls.crt` + for example + type: string + keyName: + description: KeyName represents the data name of key file in secret, `tls.key` + for example + type: string + secretName: + description: SecretName represents the name of required secret resource + type: string + secretNamespace: + description: SecretNamespace represents the namespace of required secret resource + type: string + type: object + v1alpha1.PodSelector: + properties: + mode: + description: |- + Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent + +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent + type: string + selector: + $ref: '#/definitions/v1alpha1.PodSelectorSpec' + description: Selector is used to select pods that are used to inject chaos + action. + value: + description: |- + Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action + +optional + type: string + type: object + v1alpha1.PodSelectorSpec: + properties: + annotationSelectors: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to select objects. + A selector based on annotations. + +optional + type: object + fieldSelectors: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to select objects. + A selector based on fields. + +optional + type: object + labelSelectors: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to select objects. + A selector based on labels. + +optional + type: object + namespaces: + description: |- + Namespaces is a set of namespace to which objects belong. + +optional + items: + type: string + type: array + nodeSelectors: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to select nodes. + Selector which must match a node's labels, + and objects must belong to these selected nodes. + +optional + type: object + nodes: + description: |- + Nodes is a set of node name and objects must belong to these nodes. + +optional + items: + type: string + type: array + podPhaseSelectors: + description: |- + PodPhaseSelectors is a set of condition of a pod at the current time. + supported value: Pending / Running / Succeeded / Failed / Unknown + +optional + items: + type: string + type: array + pods: + additionalProperties: + items: + type: string + type: array + description: |- + Pods is a map of string keys and a set values that used to select pods. + The key defines the namespace which pods belong, + and the each values is a set of pod names. + +optional + type: object + type: object + v1alpha1.ProcessSpec: + properties: + process: + description: the process name or the process ID + type: string + recoverCmd: + description: the command to be run when recovering experiment + type: string + signal: + description: the signal number to send + type: integer + type: object + v1alpha1.RateSpec: + properties: + rate: + description: Rate is the speed knob. Allows bit, kbit, mbit, gbit, tbit, bps, + kbps, mbps, gbps, tbps unit. bps means bytes per second. + type: string + type: object + v1alpha1.RedisCacheLimitSpec: + properties: + addr: + description: The adress of Redis server + type: string + cacheSize: + description: The size of `maxmemory` + type: string + password: + description: The password of Redis server + type: string + percent: + description: Specifies maxmemory as a percentage of the original value + type: string + type: object + v1alpha1.RedisExpirationSpec: + properties: + addr: + description: The adress of Redis server + type: string + expiration: + description: The expiration of the keys + type: string + key: + description: The keys to be expired + type: string + option: + description: Additional options for `expiration` + type: string + password: + description: The password of Redis server + type: string + type: object + v1alpha1.RedisPenetrationSpec: + properties: + addr: + description: The adress of Redis server + type: string + password: + description: The password of Redis server + type: string + requestNum: + description: The number of requests to be sent + type: integer + type: object + v1alpha1.RedisSentinelRestartSpec: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + v1alpha1.RedisSentinelStopSpec: + properties: + addr: + description: The adress of Redis server + type: string + conf: + description: The path of Sentinel conf + type: string + flushConfig: + description: The control flag determines whether to flush config + type: boolean + password: + description: The password of Redis server + type: string + redisPath: + description: The path of `redis-server` command-line tool + type: boolean + type: object + v1alpha1.ReorderSpec: + properties: + correlation: + default: "0" + description: +optional + type: string + gap: + type: integer + reorder: + type: string + type: object + v1alpha1.Schedule: + properties: + annotations: + additionalProperties: + type: string + description: |- + Annotations is an unstructured key value map stored with a resource that may be + set by external tools to store and retrieve arbitrary metadata. They are not + queryable and should be preserved when modifying objects. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations + +optional + type: object + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + +optional + type: string + creationTimestamp: + description: |- + CreationTimestamp is a timestamp representing the server time when this object was + created. It is not guaranteed to be set in happens-before order across separate operations. + Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. + Read-only. + Null for lists. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + +optional + type: string + deletionGracePeriodSeconds: + description: |- + Number of seconds allowed for this object to gracefully terminate before + it will be removed from the system. Only set when deletionTimestamp is also set. + May only be shortened. + Read-only. + +optional + type: integer + deletionTimestamp: + description: |- + DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This + field is set by the server when a graceful deletion is requested by the user, and is not + directly settable by a client. The resource is expected to be deleted (no longer visible + from resource lists, and not reachable by name) after the time in this field, once the + finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. + Once the deletionTimestamp is set, this value may not be unset or be set further into the + future, although it may be shortened or the resource may be deleted prior to this time. + For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react + by sending a graceful termination signal to the containers in the pod. After that 30 seconds, + the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, + remove the pod from the API. In the presence of network partitions, this object may still + exist after this timestamp, until an administrator or automated process can determine the + resource is fully terminated. + If not set, graceful deletion of the object has not been requested. + + Populated by the system when a graceful deletion is requested. + Read-only. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + +optional + type: string + finalizers: + description: |- + Must be empty before the object is deleted from the registry. Each entry + is an identifier for the responsible component that will remove the entry + from the list. If the deletionTimestamp of the object is non-nil, entries + in this list can only be removed. + Finalizers may be processed and removed in any order. Order is NOT enforced + because it introduces significant risk of stuck finalizers. + finalizers is a shared field, any actor with permission can reorder it. + If the finalizer list is processed in order, then this can lead to a situation + in which the component responsible for the first finalizer in the list is + waiting for a signal (field value, external system, or other) produced by a + component responsible for a finalizer later in the list, resulting in a deadlock. + Without enforced ordering finalizers are free to order amongst themselves and + are not vulnerable to ordering changes in the list. + +optional + +patchStrategy=merge + items: + type: string + type: array + generateName: + description: |- + GenerateName is an optional prefix, used by the server, to generate a unique + name ONLY IF the Name field has not been provided. + If this field is used, the name returned to the client will be different + than the name passed. This value will also be combined with a unique suffix. + The provided value has the same validation rules as the Name field, + and may be truncated by the length of the suffix required to make the value + unique on the server. + + If this field is specified and the generated name exists, the server will return a 409. + + Applied only if Name is not specified. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency + +optional + type: string + generation: + description: |- + A sequence number representing a specific generation of the desired state. + Populated by the system. Read-only. + +optional + type: integer + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + +optional + type: string + labels: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to organize and categorize + (scope and select) objects. May match selectors of replication controllers + and services. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels + +optional + type: object + managedFields: + description: |- + ManagedFields maps workflow-id and version to the set of fields + that are managed by that workflow. This is mostly for internal + housekeeping, and users typically shouldn't need to set or + understand this field. A workflow can be the user's name, a + controller's name, or the name of a specific apply path like + "ci-cd". The set of fields is always in the version that the + workflow used when modifying the object. + + +optional + items: + $ref: '#/definitions/v1.ManagedFieldsEntry' + type: array + name: + description: |- + Name must be unique within a namespace. Is required when creating resources, although + some resources may allow a client to request the generation of an appropriate name + automatically. Name is primarily intended for creation idempotence and configuration + definition. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names + +optional + type: string + namespace: + description: |- + Namespace defines the space within which each name must be unique. An empty namespace is + equivalent to the "default" namespace, but "default" is the canonical representation. + Not all objects are required to be scoped to a namespace - the value of this field for + those objects will be empty. + + Must be a DNS_LABEL. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces + +optional + type: string + ownerReferences: + description: |- + List of objects depended by this object. If ALL objects in the list have + been deleted, this object will be garbage collected. If this object is managed by a controller, + then an entry in this list will point to this controller, with the controller field set to true. + There cannot be more than one managing controller. + +optional + +patchMergeKey=uid + +patchStrategy=merge + items: + $ref: '#/definitions/v1.OwnerReference' + type: array + resourceVersion: + description: |- + An opaque value that represents the internal version of this object that can + be used by clients to determine when objects have changed. May be used for optimistic + concurrency, change detection, and the watch operation on a resource or set of resources. + Clients must treat these values as opaque and passed unmodified back to the server. + They may only be valid for a particular resource or set of resources. + + Populated by the system. + Read-only. + Value must be treated as opaque by clients and . + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + +optional + type: string + selfLink: + description: |- + Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. + +optional + type: string + spec: + $ref: '#/definitions/v1alpha1.ScheduleSpec' + status: + $ref: '#/definitions/v1alpha1.ScheduleStatus' + description: +optional + uid: + description: |- + UID is the unique in time and space value for this object. It is typically generated by + the server on successful creation of a resource and is not allowed to change on PUT + operations. + + Populated by the system. + Read-only. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids + +optional + type: string + type: object + v1alpha1.ScheduleSpec: + properties: + awsChaos: + $ref: '#/definitions/v1alpha1.AWSChaosSpec' + description: +optional + azureChaos: + $ref: '#/definitions/v1alpha1.AzureChaosSpec' + description: +optional + blockChaos: + $ref: '#/definitions/v1alpha1.BlockChaosSpec' + description: +optional + concurrencyPolicy: + description: |- + +optional + +kubebuilder:default=Forbid + +kubebuilder:validation:Enum=Forbid;Allow + type: string + dnsChaos: + $ref: '#/definitions/v1alpha1.DNSChaosSpec' + description: +optional + gcpChaos: + $ref: '#/definitions/v1alpha1.GCPChaosSpec' + description: +optional + historyLimit: + description: |- + +optional + +kubebuilder:validation:Minimum=1 + type: integer + httpChaos: + $ref: '#/definitions/v1alpha1.HTTPChaosSpec' + description: +optional + ioChaos: + $ref: '#/definitions/v1alpha1.IOChaosSpec' + description: +optional + jvmChaos: + $ref: '#/definitions/v1alpha1.JVMChaosSpec' + description: +optional + kernelChaos: + $ref: '#/definitions/v1alpha1.KernelChaosSpec' + description: +optional + networkChaos: + $ref: '#/definitions/v1alpha1.NetworkChaosSpec' + description: +optional + physicalmachineChaos: + $ref: '#/definitions/v1alpha1.PhysicalMachineChaosSpec' + description: +optional + podChaos: + $ref: '#/definitions/v1alpha1.PodChaosSpec' + description: +optional + schedule: + type: string + startingDeadlineSeconds: + description: |- + +optional + +nullable + +kubebuilder:validation:Minimum=0 + +kubebuilder:validation:ExclusiveMinimum=true + type: integer + stressChaos: + $ref: '#/definitions/v1alpha1.StressChaosSpec' + description: +optional + timeChaos: + $ref: '#/definitions/v1alpha1.TimeChaosSpec' + description: +optional + type: + type: string + workflow: + $ref: '#/definitions/v1alpha1.WorkflowSpec' + description: +optional + type: object + v1alpha1.ScheduleStatus: + properties: + active: + description: +optional + items: + $ref: '#/definitions/v1.ObjectReference' + type: array + time: + description: |- + +optional + +nullable + type: string + type: object + v1alpha1.StatusCheckSpec: + properties: + duration: + description: |- + Duration defines the duration of the whole status check if the + number of failed execution does not exceed the failure threshold. + Duration is available to both `Synchronous` and `Continuous` mode. + 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". + +optional + type: string + failureThreshold: + description: |- + FailureThreshold defines the minimum consecutive failure + for the status check to be considered failed. + +optional + +kubebuilder:default=3 + +kubebuilder:validation:Minimum=1 + type: integer + http: + $ref: '#/definitions/v1alpha1.HTTPStatusCheck' + description: +optional + intervalSeconds: + description: |- + IntervalSeconds defines how often (in seconds) to perform + an execution of status check. + +optional + +kubebuilder:default=10 + +kubebuilder:validation:Minimum=1 + type: integer + mode: + description: |- + Mode defines the execution mode of the status check. + Support type: Synchronous / Continuous + +optional + +kubebuilder:validation:Enum=Synchronous;Continuous + type: string + recordsHistoryLimit: + description: |- + RecordsHistoryLimit defines the number of record to retain. + +optional + +kubebuilder:default=100 + +kubebuilder:validation:Minimum=1 + +kubebuilder:validation:Maximum=1000 + type: integer + successThreshold: + description: |- + SuccessThreshold defines the minimum consecutive successes + for the status check to be considered successful. + SuccessThreshold only works for `Synchronous` mode. + +optional + +kubebuilder:default=1 + +kubebuilder:validation:Minimum=1 + type: integer + timeoutSeconds: + description: |- + TimeoutSeconds defines the number of seconds after which + an execution of status check times out. + +optional + +kubebuilder:default=1 + +kubebuilder:validation:Minimum=1 + type: integer + type: + description: |- + Type defines the specific status check type. + Support type: HTTP + +kubebuilder:default=HTTP + +kubebuilder:validation:Enum=HTTP + type: string + type: object + v1alpha1.StatusCheckTemplate: + properties: + duration: + description: |- + Duration defines the duration of the whole status check if the + number of failed execution does not exceed the failure threshold. + Duration is available to both `Synchronous` and `Continuous` mode. + 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". + +optional + type: string + failureThreshold: + description: |- + FailureThreshold defines the minimum consecutive failure + for the status check to be considered failed. + +optional + +kubebuilder:default=3 + +kubebuilder:validation:Minimum=1 + type: integer + http: + $ref: '#/definitions/v1alpha1.HTTPStatusCheck' + description: +optional + intervalSeconds: + description: |- + IntervalSeconds defines how often (in seconds) to perform + an execution of status check. + +optional + +kubebuilder:default=10 + +kubebuilder:validation:Minimum=1 + type: integer + mode: + description: |- + Mode defines the execution mode of the status check. + Support type: Synchronous / Continuous + +optional + +kubebuilder:validation:Enum=Synchronous;Continuous + type: string + recordsHistoryLimit: + description: |- + RecordsHistoryLimit defines the number of record to retain. + +optional + +kubebuilder:default=100 + +kubebuilder:validation:Minimum=1 + +kubebuilder:validation:Maximum=1000 + type: integer + successThreshold: + description: |- + SuccessThreshold defines the minimum consecutive successes + for the status check to be considered successful. + SuccessThreshold only works for `Synchronous` mode. + +optional + +kubebuilder:default=1 + +kubebuilder:validation:Minimum=1 + type: integer + timeoutSeconds: + description: |- + TimeoutSeconds defines the number of seconds after which + an execution of status check times out. + +optional + +kubebuilder:default=1 + +kubebuilder:validation:Minimum=1 + type: integer + type: + description: |- + Type defines the specific status check type. + Support type: HTTP + +kubebuilder:default=HTTP + +kubebuilder:validation:Enum=HTTP + type: string + type: object + v1alpha1.StressCPUSpec: + properties: + load: + description: specifies P percent loading per CPU worker. 0 is effectively + a sleep (no load) and 100 is full loading. + type: integer + options: + description: extend stress-ng options + items: + type: string + type: array + workers: + description: specifies N workers to apply the stressor. + type: integer + type: object + v1alpha1.StressChaosSpec: + properties: + containerNames: + description: |- + ContainerNames indicates list of the name of affected container. + If not set, the first container will be injected + +optional + items: + type: string + type: array + duration: + description: |- + Duration represents the duration of the chaos action + +optional + type: string + mode: + description: |- + Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent + +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent + type: string + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + selector: + $ref: '#/definitions/v1alpha1.PodSelectorSpec' + description: Selector is used to select pods that are used to inject chaos + action. + stressngStressors: + description: |- + StressngStressors defines plenty of stressors just like `Stressors` except that it's an experimental + feature and more powerful. You can define stressors in `stress-ng` (see also `man stress-ng`) dialect, + however not all of the supported stressors are well tested. It maybe retired in later releases. You + should always use `Stressors` to define the stressors and use this only when you want more stressors + unsupported by `Stressors`. When both `StressngStressors` and `Stressors` are defined, `StressngStressors` + wins. + +optional + type: string + stressors: + $ref: '#/definitions/v1alpha1.Stressors' + description: |- + Stressors defines plenty of stressors supported to stress system components out. + You can use one or more of them to make up various kinds of stresses. At least + one of the stressors should be specified. + +optional + value: + description: |- + Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action + +optional + type: string + type: object + v1alpha1.StressMemorySpec: + properties: + options: + description: extend stress-ng options + items: + type: string + type: array + size: + description: |- + specifies N bytes consumed per vm worker, default is the total available memory. + One can specify the size as % of total available memory or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. + type: string + type: object + v1alpha1.Stressors: + properties: + cpu: + $ref: '#/definitions/v1alpha1.CPUStressor' + description: |- + CPUStressor stresses CPU out + +optional + memory: + $ref: '#/definitions/v1alpha1.MemoryStressor' + description: |- + MemoryStressor stresses virtual memory out + +optional + type: object + v1alpha1.Task: + properties: + container: + $ref: '#/definitions/v1.Container' + description: Container is the main container image to run in the pod + volumes: + description: |- + Volumes is a list of volumes that can be mounted by containers in a template. + +patchStrategy=merge + +patchMergeKey=name + items: + $ref: '#/definitions/v1.Volume' + type: array + type: object + v1alpha1.Template: + properties: + abortWithStatusCheck: + description: |- + AbortWithStatusCheck describe whether to abort the workflow when the failure threshold of StatusCheck is exceeded. + Only used when Type is TypeStatusCheck. + +optional + type: boolean + awsChaos: + $ref: '#/definitions/v1alpha1.AWSChaosSpec' + description: +optional + azureChaos: + $ref: '#/definitions/v1alpha1.AzureChaosSpec' + description: +optional + blockChaos: + $ref: '#/definitions/v1alpha1.BlockChaosSpec' + description: +optional + children: + description: |- + Children describes the children steps of serial or parallel node. Only used when Type is TypeSerial or TypeParallel. + +optional + items: + type: string + type: array + conditionalBranches: + description: |- + ConditionalBranches describes the conditional branches of custom tasks. Only used when Type is TypeTask. + +optional + items: + $ref: '#/definitions/v1alpha1.ConditionalBranch' + type: array + deadline: + description: +optional + type: string + dnsChaos: + $ref: '#/definitions/v1alpha1.DNSChaosSpec' + description: +optional + gcpChaos: + $ref: '#/definitions/v1alpha1.GCPChaosSpec' + description: +optional + httpChaos: + $ref: '#/definitions/v1alpha1.HTTPChaosSpec' + description: +optional + ioChaos: + $ref: '#/definitions/v1alpha1.IOChaosSpec' + description: +optional + jvmChaos: + $ref: '#/definitions/v1alpha1.JVMChaosSpec' + description: +optional + kernelChaos: + $ref: '#/definitions/v1alpha1.KernelChaosSpec' + description: +optional + name: + type: string + networkChaos: + $ref: '#/definitions/v1alpha1.NetworkChaosSpec' + description: +optional + physicalmachineChaos: + $ref: '#/definitions/v1alpha1.PhysicalMachineChaosSpec' + description: +optional + podChaos: + $ref: '#/definitions/v1alpha1.PodChaosSpec' + description: +optional + schedule: + $ref: '#/definitions/v1alpha1.ChaosOnlyScheduleSpec' + description: |- + Schedule describe the Schedule(describing scheduled chaos) to be injected with chaos nodes. Only used when Type is TypeSchedule. + +optional + statusCheck: + $ref: '#/definitions/v1alpha1.StatusCheckSpec' + description: |- + StatusCheck describe the behavior of StatusCheck. Only used when Type is TypeStatusCheck. + +optional + stressChaos: + $ref: '#/definitions/v1alpha1.StressChaosSpec' + description: +optional + task: + $ref: '#/definitions/v1alpha1.Task' + description: |- + Task describes the behavior of the custom task. Only used when Type is TypeTask. + +optional + templateType: + type: string + timeChaos: + $ref: '#/definitions/v1alpha1.TimeChaosSpec' + description: +optional + type: object + v1alpha1.TimeChaosSpec: + properties: + clockIds: + description: |- + ClockIds defines all affected clock id + All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM"] + Default value is ["CLOCK_REALTIME"] + items: + type: string + type: array + containerNames: + description: |- + ContainerNames indicates list of the name of affected container. + If not set, the first container will be injected + +optional + items: + type: string + type: array + duration: + description: Duration represents the duration of the chaos action + type: string + mode: + description: |- + Mode defines the mode to run chaos action. + Supported mode: one / all / fixed / fixed-percent / random-max-percent + +kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent + type: string + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + selector: + $ref: '#/definitions/v1alpha1.PodSelectorSpec' + description: Selector is used to select pods that are used to inject chaos + action. + timeOffset: + description: |- + TimeOffset defines the delta time of injected program. It's a possibly signed sequence of decimal numbers, such as + "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + type: string + value: + description: |- + Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. + If `FixedMode`, provide an integer of pods to do chaos action. + If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. + IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action + +optional + type: string + type: object + v1alpha1.Timespec: + properties: + nsec: + type: integer + sec: + type: integer + type: object + v1alpha1.UserDefinedSpec: + properties: + attackCmd: + description: The command to be executed when attack + type: string + recoverCmd: + description: The command to be executed when recover + type: string + type: object + v1alpha1.VMSpec: + properties: + vm-name: + description: The name of the VM to be injected + type: string + type: object + v1alpha1.Workflow: + properties: + annotations: + additionalProperties: + type: string + description: |- + Annotations is an unstructured key value map stored with a resource that may be + set by external tools to store and retrieve arbitrary metadata. They are not + queryable and should be preserved when modifying objects. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations + +optional + type: object + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + +optional + type: string + creationTimestamp: + description: |- + CreationTimestamp is a timestamp representing the server time when this object was + created. It is not guaranteed to be set in happens-before order across separate operations. + Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. + Read-only. + Null for lists. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + +optional + type: string + deletionGracePeriodSeconds: + description: |- + Number of seconds allowed for this object to gracefully terminate before + it will be removed from the system. Only set when deletionTimestamp is also set. + May only be shortened. + Read-only. + +optional + type: integer + deletionTimestamp: + description: |- + DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This + field is set by the server when a graceful deletion is requested by the user, and is not + directly settable by a client. The resource is expected to be deleted (no longer visible + from resource lists, and not reachable by name) after the time in this field, once the + finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. + Once the deletionTimestamp is set, this value may not be unset or be set further into the + future, although it may be shortened or the resource may be deleted prior to this time. + For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react + by sending a graceful termination signal to the containers in the pod. After that 30 seconds, + the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, + remove the pod from the API. In the presence of network partitions, this object may still + exist after this timestamp, until an administrator or automated process can determine the + resource is fully terminated. + If not set, graceful deletion of the object has not been requested. + + Populated by the system when a graceful deletion is requested. + Read-only. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + +optional + type: string + finalizers: + description: |- + Must be empty before the object is deleted from the registry. Each entry + is an identifier for the responsible component that will remove the entry + from the list. If the deletionTimestamp of the object is non-nil, entries + in this list can only be removed. + Finalizers may be processed and removed in any order. Order is NOT enforced + because it introduces significant risk of stuck finalizers. + finalizers is a shared field, any actor with permission can reorder it. + If the finalizer list is processed in order, then this can lead to a situation + in which the component responsible for the first finalizer in the list is + waiting for a signal (field value, external system, or other) produced by a + component responsible for a finalizer later in the list, resulting in a deadlock. + Without enforced ordering finalizers are free to order amongst themselves and + are not vulnerable to ordering changes in the list. + +optional + +patchStrategy=merge + items: + type: string + type: array + generateName: + description: |- + GenerateName is an optional prefix, used by the server, to generate a unique + name ONLY IF the Name field has not been provided. + If this field is used, the name returned to the client will be different + than the name passed. This value will also be combined with a unique suffix. + The provided value has the same validation rules as the Name field, + and may be truncated by the length of the suffix required to make the value + unique on the server. + + If this field is specified and the generated name exists, the server will return a 409. + + Applied only if Name is not specified. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency + +optional + type: string + generation: + description: |- + A sequence number representing a specific generation of the desired state. + Populated by the system. Read-only. + +optional + type: integer + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + +optional + type: string + labels: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to organize and categorize + (scope and select) objects. May match selectors of replication controllers + and services. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels + +optional + type: object + managedFields: + description: |- + ManagedFields maps workflow-id and version to the set of fields + that are managed by that workflow. This is mostly for internal + housekeeping, and users typically shouldn't need to set or + understand this field. A workflow can be the user's name, a + controller's name, or the name of a specific apply path like + "ci-cd". The set of fields is always in the version that the + workflow used when modifying the object. + + +optional + items: + $ref: '#/definitions/v1.ManagedFieldsEntry' + type: array + name: + description: |- + Name must be unique within a namespace. Is required when creating resources, although + some resources may allow a client to request the generation of an appropriate name + automatically. Name is primarily intended for creation idempotence and configuration + definition. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names + +optional + type: string + namespace: + description: |- + Namespace defines the space within which each name must be unique. An empty namespace is + equivalent to the "default" namespace, but "default" is the canonical representation. + Not all objects are required to be scoped to a namespace - the value of this field for + those objects will be empty. + + Must be a DNS_LABEL. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces + +optional + type: string + ownerReferences: + description: |- + List of objects depended by this object. If ALL objects in the list have + been deleted, this object will be garbage collected. If this object is managed by a controller, + then an entry in this list will point to this controller, with the controller field set to true. + There cannot be more than one managing controller. + +optional + +patchMergeKey=uid + +patchStrategy=merge + items: + $ref: '#/definitions/v1.OwnerReference' + type: array + resourceVersion: + description: |- + An opaque value that represents the internal version of this object that can + be used by clients to determine when objects have changed. May be used for optimistic + concurrency, change detection, and the watch operation on a resource or set of resources. + Clients must treat these values as opaque and passed unmodified back to the server. + They may only be valid for a particular resource or set of resources. + + Populated by the system. + Read-only. + Value must be treated as opaque by clients and . + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + +optional + type: string + selfLink: + description: |- + Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. + +optional + type: string + spec: + $ref: '#/definitions/v1alpha1.WorkflowSpec' + description: Spec defines the behavior of a workflow + status: + $ref: '#/definitions/v1alpha1.WorkflowStatus' + description: |- + +optional + Most recently observed status of the workflow + uid: + description: |- + UID is the unique in time and space value for this object. It is typically generated by + the server on successful creation of a resource and is not allowed to change on PUT + operations. + + Populated by the system. + Read-only. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids + +optional + type: string + type: object + v1alpha1.WorkflowCondition: + properties: + reason: + type: string + startTime: + type: string + status: + type: string + type: + type: string + type: object + v1alpha1.WorkflowSpec: + properties: + entry: + type: string + templates: + items: + $ref: '#/definitions/v1alpha1.Template' + type: array + type: object + v1alpha1.WorkflowStatus: + properties: + conditions: + description: |- + Represents the latest available observations of a workflow's current state. + +optional + +patchMergeKey=type + +patchStrategy=merge + items: + $ref: '#/definitions/v1alpha1.WorkflowCondition' + type: array + endTime: + description: +optional + type: string + entryNode: + description: +optional + type: string + startTime: + description: +optional + type: string + type: object +info: + contact: + name: GitHub Issues + url: https://github.com/chaos-mesh/chaos-mesh/issues + description: Swagger for Chaos Mesh Dashboard. If you encounter any problems with + API, please click on the issues link below to report. + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + title: Chaos Mesh Dashboard API + version: "2.5" +paths: + /archives: + delete: + description: Delete the specified archived experiment. + parameters: + - description: uids + in: query + name: uids + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Delete the specified archived experiment. + tags: + - archives + get: + description: Get archived chaos experiments. + parameters: + - description: namespace + in: query + name: namespace + type: string + - description: name + in: query + name: name + type: string + - description: kind + enum: + - PodChaos + - IOChaos + - NetworkChaos + - TimeChaos + - KernelChaos + - StressChaos + in: query + name: kind + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/types.Archive' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get archived chaos experiments. + tags: + - archives + /archives/{uid}: + delete: + description: Delete the specified archived experiment. + parameters: + - description: uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Delete the specified archived experiment. + tags: + - archives + get: + description: Get the archived chaos experiment's detail by uid. + parameters: + - description: the archive uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/types.ArchiveDetail' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get an archived chaos experiment. + tags: + - archives + /archives/schedules: + delete: + description: Delete the specified archived schedule. + parameters: + - description: uids + in: query + name: uids + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Delete the specified archived schedule. + tags: + - archives + get: + description: Get archived schedule experiments. + parameters: + - description: namespace + in: query + name: namespace + type: string + - description: name + in: query + name: name + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/types.Archive' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get archived schedule experiments. + tags: + - archives + /archives/schedules/{uid}: + delete: + description: Delete the specified archived schedule. + parameters: + - description: uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Delete the specified archived schedule. + tags: + - archives + get: + description: Get the detail of an archived schedule experiment. + parameters: + - description: uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/types.ArchiveDetail' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get the detail of an archived schedule experiment. + tags: + - archives + /archives/workflows: + delete: + description: Delete the specified archived workflows. + parameters: + - description: uids + in: query + name: uids + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Delete the specified archived workflows. + tags: + - archives + get: + description: Get archived workflow. + parameters: + - description: namespace + in: query + name: namespace + type: string + - description: name + in: query + name: name + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/types.Archive' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get archived workflow. + tags: + - archives + /archives/workflows/{uid}: + delete: + description: Delete the specified archived workflow. + parameters: + - description: uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Delete the specified archived workflow. + tags: + - archives + get: + description: Get the detail of an archived workflow. + parameters: + - description: uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/types.ArchiveDetail' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get the detail of an archived workflow. + tags: + - archives + /common/annotations: + get: + description: Get the annotations of the pods in the specified namespace from + Kubernetes cluster. + parameters: + - description: The pod's namespace list, split by , + in: query + name: podNamespaceList + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.MapStringSliceResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get the annotations of the pods in the specified namespace from Kubernetes + cluster. + tags: + - common + /common/chaos-available-namespaces: + get: + description: Get all namespaces which could inject chaos(explosion scope) from + Kubernetes cluster. + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + type: string + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get all namespaces which could inject chaos(explosion scope) from Kubernetes + cluster. + tags: + - common + /common/config: + get: + description: Get the config of Dashboard. + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/config.ChaosDashboardConfig' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get the config of Dashboard. + tags: + - common + /common/kinds: + get: + description: Get all chaos kinds from Kubernetes cluster. + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + type: string + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get all chaos kinds from Kubernetes cluster. + tags: + - common + /common/labels: + get: + description: Get the labels of the pods in the specified namespace from Kubernetes + cluster. + parameters: + - description: The pod's namespace list, split by , + in: query + name: podNamespaceList + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.MapStringSliceResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get the labels of the pods in the specified namespace from Kubernetes + cluster. + tags: + - common + /common/namespaces: + get: + deprecated: true + description: Get all from Kubernetes cluster. + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + type: string + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get all namespaces from Kubernetes cluster. + tags: + - common + /common/physicalmachine-annotations: + get: + description: Get the annotations of the physicalMachines in the specified namespace + from Kubernetes cluster. + parameters: + - description: The physicalMachine's namespace list, split by , + in: query + name: physicalMachineNamespaceList + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.MapStringSliceResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get the annotations of the physicalMachines in the specified namespace + from Kubernetes cluster. + tags: + - common + /common/physicalmachine-labels: + get: + description: Get the labels of the physicalMachines in the specified namespace + from Kubernetes cluster. + parameters: + - description: The physicalMachine's namespace list, split by , + in: query + name: physicalMachineNamespaceList + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.MapStringSliceResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get the labels of the physicalMachines in the specified namespace from + Kubernetes cluster. + tags: + - common + /common/physicalmachines: + post: + description: Get physicalMachines from Kubernetes cluster. + parameters: + - description: Request body + in: body + name: request + required: true + schema: + $ref: '#/definitions/v1alpha1.PhysicalMachineSelectorSpec' + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/types.PhysicalMachine' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get physicalMachines from Kubernetes cluster. + tags: + - common + /common/pods: + post: + description: Get pods from Kubernetes cluster. + parameters: + - description: Request body + in: body + name: request + required: true + schema: + $ref: '#/definitions/v1alpha1.PodSelectorSpec' + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/types.Pod' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get pods from Kubernetes cluster. + tags: + - common + /common/rbac-config: + get: + description: Get the rbac config according to the user's choice. + parameters: + - description: The namespace of RBAC + in: query + name: namespace + type: string + - description: The role of RBAC + in: query + name: role + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + additionalProperties: + type: string + type: object + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get the rbac config according to the user's choice. + tags: + - common + /events: + get: + description: Get events from db. + parameters: + - description: The create time of events + in: query + name: created_at + type: string + - description: The name of the object + in: query + name: name + type: string + - description: The namespace of the object + in: query + name: namespace + type: string + - description: The UID of the object + in: query + name: object_id + type: string + - description: kind + enum: + - PodChaos + - IOChaos + - NetworkChaos + - TimeChaos + - KernelChaos + - StressChaos + - AWSChaos + - GCPChaos + - DNSChaos + - Schedule + in: query + name: kind + type: string + - description: The max length of events list + in: query + name: limit + type: number + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/core.Event' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: list events. + tags: + - events + /events/{id}: + get: + description: Get the event from db by ID. + parameters: + - description: The event ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/core.Event' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get an event. + tags: + - events + /events/workflow/{uid}: + get: + description: list all events for Workflow and related WorkflowNode. + parameters: + - description: The UID of the Workflow + in: path + name: uid + required: true + type: string + - description: The namespace of the object + in: query + name: namespace + type: string + - description: The max length of events list + in: query + name: limit + type: number + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/core.Event' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: cascadeFetchEventsForWorkflow list all events for Workflow and related + WorkflowNode. + tags: + - events + /experiments: + delete: + description: Batch delete chaos experiments by uids. + parameters: + - description: 'the experiment uids, split with comma. Example: ?uids=uid1,uid2' + in: query + name: uids + required: true + type: string + - description: force + enum: + - "true" + - "false" + in: query + name: force + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Batch delete chaos experiments. + tags: + - experiments + get: + description: Get chaos experiments from k8s clusters in real time. + parameters: + - description: filter exps by namespace + in: query + name: namespace + type: string + - description: filter exps by name + in: query + name: name + type: string + - description: filter exps by kind + enum: + - PodChaos + - NetworkChaos + - IOChaos + - StressChaos + - KernelChaos + - TimeChaos + - DNSChaos + - AWSChaos + - GCPChaos + - JVMChaos + - HTTPChaos + in: query + name: kind + type: string + - description: filter exps by status + enum: + - Injecting + - Running + - Finished + - Paused + in: query + name: status + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/types.Experiment' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: List chaos experiments. + tags: + - experiments + post: + consumes: + - application/json + description: Pass a JSON object to create a new chaos experiment. The schema + for JSON is the same as the YAML schema for the Kubernetes object. + parameters: + - description: the chaos definition + in: body + name: chaos + required: true + schema: + additionalProperties: true + type: object + produces: + - application/json + responses: + "200": + description: OK + schema: + additionalProperties: true + type: object + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Create a new chaos experiment. + tags: + - experiments + /experiments/{uid}: + delete: + description: Delete the chaos experiment by uid. + parameters: + - description: the experiment uid + in: path + name: uid + required: true + type: string + - description: force + enum: + - "true" + - "false" + in: query + name: force + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Delete a chaos experiment. + tags: + - experiments + get: + description: Get the chaos experiment's detail by uid. + parameters: + - description: the experiment uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/types.ExperimentDetail' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get a chaos experiment. + tags: + - experiments + /experiments/pause/{uid}: + put: + description: Pause a chaos experiment. + parameters: + - description: the experiment uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Pause a chaos experiment. + tags: + - experiments + /experiments/start/{uid}: + put: + description: Start a chaos experiment. + parameters: + - description: the experiment uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Start a chaos experiment. + tags: + - experiments + /experiments/state: + get: + description: Get the status of all experiments. + parameters: + - description: namespace + in: query + name: namespace + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/status.AllChaosStatus' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get the status of all experiments. + tags: + - experiments + /schedules: + delete: + description: Batch delete schedules by uids. + parameters: + - description: 'the schedule uids, split with comma. Example: ?uids=uid1,uid2' + in: query + name: uids + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Batch delete schedules. + tags: + - schedules + get: + description: Get chaos schedules from k8s cluster in real time. + parameters: + - description: filter schedules by namespace + in: query + name: namespace + type: string + - description: filter schedules by name + in: query + name: name + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/types.Schedule' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: List chaos schedules. + tags: + - schedules + post: + consumes: + - application/json + description: Pass a JSON object to create a new schedule. The schema for JSON + is the same as the YAML schema for the Kubernetes object. + parameters: + - description: the schedule definition + in: body + name: schedule + required: true + schema: + $ref: '#/definitions/v1alpha1.Schedule' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/v1alpha1.Schedule' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Create a new schedule. + tags: + - schedules + /schedules/{uid}: + delete: + description: Delete the schedule by uid. + parameters: + - description: the schedule uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Delete a schedule. + tags: + - schedules + get: + description: Get the schedule's detail by uid. + parameters: + - description: the schedule uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/types.ScheduleDetail' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get a schedule. + tags: + - schedules + /schedules/pause/{uid}: + put: + description: Pause a schedule. + parameters: + - description: the schedule uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Pause a schedule. + tags: + - schedules + /schedules/start/{uid}: + put: + description: Start a schedule. + parameters: + - description: the schedule uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Start a schedule. + tags: + - schedules + /templates/statuschecks: + get: + description: Get status check templates from k8s cluster in real time. + parameters: + - description: filter status check templates by namespace + in: query + name: namespace + type: string + - description: filter status check templates by name + in: query + name: name + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/types.StatusCheckTemplateBase' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: List status check templates. + tags: + - template + post: + consumes: + - application/json + description: Pass a JSON object to create a new status check template. + parameters: + - description: the status check definition + in: body + name: statuscheck + required: true + schema: + $ref: '#/definitions/types.StatusCheckTemplate' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/types.StatusCheckTemplate' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Create a new status check template. + tags: + - templates + /templates/statuschecks/statuscheck: + delete: + description: Delete the status check template by namespaced name. + parameters: + - description: the namespace of status check templates + in: query + name: namespace + required: true + type: string + - description: the name of status check templates + in: query + name: name + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Delete a status check template. + tags: + - templates + get: + description: Get the status check template's detail by namespaced name. + parameters: + - description: the namespace of status check templates + in: query + name: namespace + required: true + type: string + - description: the name of status check templates + in: query + name: name + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/types.StatusCheckTemplateDetail' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get a status check template. + tags: + - templates + put: + description: Update a status check template by namespaced name. + parameters: + - description: Request body + in: body + name: request + required: true + schema: + $ref: '#/definitions/types.StatusCheckTemplate' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/types.StatusCheckTemplate' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Update a status check template. + tags: + - templates + /workflows: + get: + description: List workflows from Kubernetes cluster. + parameters: + - description: namespace, given empty string means list from all namespace + in: query + name: namespace + type: string + - description: status + enum: + - Initializing + - Running + - Errored + - Finished + in: query + name: status + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/core.WorkflowMeta' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: List workflows from Kubernetes cluster. + tags: + - workflows + post: + description: Create a new workflow. + parameters: + - description: Request body + in: body + name: request + required: true + schema: + $ref: '#/definitions/v1alpha1.Workflow' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/core.WorkflowDetail' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Create a new workflow. + tags: + - workflows + /workflows/{uid}: + delete: + description: Delete the specified workflow. + parameters: + - description: uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "404": + description: Not Found + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Delete the specified workflow. + tags: + - workflows + get: + description: Get detailed information about the specified workflow. If that + object is not existed in kubernetes, it will only return ths persisted data + in the database. + parameters: + - description: uid + in: path + name: uid + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/core.WorkflowDetail' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Get detailed information about the specified workflow. + tags: + - workflows + put: + description: Update a workflow. + parameters: + - description: uid + in: path + name: uid + required: true + type: string + - description: Request body + in: body + name: request + required: true + schema: + $ref: '#/definitions/v1alpha1.Workflow' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/core.WorkflowDetail' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Update a workflow. + tags: + - workflows + /workflows/parse-task/http: + post: + description: Parse the rendered task back to the original request + parameters: + - description: Rendered Task + in: body + name: request + required: true + schema: + $ref: '#/definitions/v1alpha1.Template' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/curl.RequestForm' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Parse the rendered task back to the original request + tags: + - workflows + /workflows/render-task/http: + post: + description: Render a task which sends HTTP request + parameters: + - description: Origin HTTP Request + in: body + name: request + required: true + schema: + $ref: '#/definitions/curl.RequestForm' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/v1alpha1.Template' + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Render a task which sends HTTP request + tags: + - workflows + /workflows/validate-task/http: + post: + description: Validate the given template is a valid rendered HTTP Task + parameters: + - description: Rendered Task + in: body + name: request + required: true + schema: + $ref: '#/definitions/v1alpha1.Template' + produces: + - application/json + responses: + "200": + description: OK + schema: + type: boolean + "400": + description: Bad Request + schema: + $ref: '#/definitions/utils.APIError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/utils.APIError' + summary: Validate the given template is a valid rendered HTTP Task + tags: + - workflows +swagger: "2.0" diff --git a/pkg/dashboard/swaggerserver/handler.go b/pkg/dashboard/swaggerserver/handler.go new file mode 100644 index 0000000000..19b3d432b8 --- /dev/null +++ b/pkg/dashboard/swaggerserver/handler.go @@ -0,0 +1,33 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package swaggerserver + +import ( + "github.com/gin-gonic/gin" + swaggerFiles "github.com/swaggo/files" + ginSwagger "github.com/swaggo/gin-swagger" + + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/swaggerdocs" +) + +func Handler(c *gin.Context) { + swaggerdocs.SwaggerInfo.Host = c.Request.Host + + ginSwagger.CustomWrapHandler( + &ginSwagger.Config{URL: "/api/swagger/doc.json"}, + swaggerFiles.Handler, + )(c) +} diff --git a/pkg/dashboard/ttlcontroller/fx.go b/pkg/dashboard/ttlcontroller/fx.go new file mode 100644 index 0000000000..0c602f931f --- /dev/null +++ b/pkg/dashboard/ttlcontroller/fx.go @@ -0,0 +1,26 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ttlcontroller + +import ( + "github.com/go-logr/logr" + + "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +func Bootstrap(event core.EventStore, experiment core.ExperimentStore, schedule core.ScheduleStore, workflow core.WorkflowStore, ttlc *config.TTLConfig, logger logr.Logger) *Controller { + return NewController(event, experiment, schedule, workflow, ttlc, logger.WithName("ttlcontroller")) +} diff --git a/pkg/dashboard/ttlcontroller/ttlcontroller.go b/pkg/dashboard/ttlcontroller/ttlcontroller.go new file mode 100644 index 0000000000..71e80e2149 --- /dev/null +++ b/pkg/dashboard/ttlcontroller/ttlcontroller.go @@ -0,0 +1,78 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package ttlcontroller provides a TTL (time to live) mechanism to clear old objects +// in the database. +package ttlcontroller + +import ( + "context" + + "github.com/go-logr/logr" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/wait" + + "github.com/chaos-mesh/chaos-mesh/pkg/config" + "github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core" +) + +type Controller struct { + logger logr.Logger + event core.EventStore + experiment core.ExperimentStore + schedule core.ScheduleStore + workflow core.WorkflowStore + ttlconfig *config.TTLConfig +} + +// NewController returns a new database ttl controller +func NewController( + event core.EventStore, + experiment core.ExperimentStore, + schedule core.ScheduleStore, + workflow core.WorkflowStore, + ttlconfig *config.TTLConfig, + logger logr.Logger, +) *Controller { + return &Controller{ + experiment: experiment, + event: event, + schedule: schedule, + workflow: workflow, + ttlconfig: ttlconfig, + logger: logger, + } +} + +// Register periodically calls function runWorker to delete the data. +func Register(ctx context.Context, c *Controller) { + defer utilruntime.HandleCrash() + + c.logger.Info("Starting database TTL controller") + + go wait.Until(c.runWorker, c.ttlconfig.ResyncPeriod, ctx.Done()) +} + +// runWorker is a long-running function that will be called in order to delete the events, archives, schedule, and workflow. +func (c *Controller) runWorker() { + c.logger.Info("Deleting expired data from the database") + + ctx := context.Background() + + _ = c.event.DeleteByDuration(ctx, c.ttlconfig.EventTTL) + c.experiment.DeleteByFinishTime(ctx, c.ttlconfig.ExperimentTTL) + c.schedule.DeleteByFinishTime(ctx, c.ttlconfig.ScheduleTTL) + c.workflow.DeleteByFinishTime(ctx, c.ttlconfig.WorkflowTTL) +} diff --git a/pkg/dashboard/uiserver/empty_assets_handler.go b/pkg/dashboard/uiserver/empty_assets_handler.go new file mode 100644 index 0000000000..680d3a0572 --- /dev/null +++ b/pkg/dashboard/uiserver/empty_assets_handler.go @@ -0,0 +1,21 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//go:build !ui_server + +package uiserver + +import "net/http" + +var assets http.FileSystem diff --git a/pkg/dashboard/uiserver/server.go b/pkg/dashboard/uiserver/server.go new file mode 100644 index 0000000000..3da361a285 --- /dev/null +++ b/pkg/dashboard/uiserver/server.go @@ -0,0 +1,23 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package uiserver + +import "net/http" + +// AssetsFS returns assets. +func AssetsFS() http.FileSystem { + return assets +} diff --git a/pkg/events/events.go b/pkg/events/events.go index f31d9d4fd4..9eb594a2b8 100644 --- a/pkg/events/events.go +++ b/pkg/events/events.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package events diff --git a/pkg/expr/expr.go b/pkg/expr/expr.go new file mode 100644 index 0000000000..4fd9169215 --- /dev/null +++ b/pkg/expr/expr.go @@ -0,0 +1,33 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package expr + +import ( + "github.com/antonmedv/expr" + "github.com/pkg/errors" +) + +func EvalBool(expression string, env map[string]interface{}) (bool, error) { + eval, err := expr.Eval(expression, env) + if err != nil { + return false, err + } + result, ok := eval.(bool) + if !ok { + return false, errors.New("expression result is not boolean") + } + return result, nil +} diff --git a/pkg/expr/expr_test.go b/pkg/expr/expr_test.go new file mode 100644 index 0000000000..eacd5667d5 --- /dev/null +++ b/pkg/expr/expr_test.go @@ -0,0 +1,101 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package expr + +import "testing" + +func TestEvalBool(t *testing.T) { + type args struct { + expression string + env map[string]interface{} + } + tests := []struct { + name string + args args + want bool + wantErr bool + }{ + { + name: "expect true", + args: args{ + expression: "0 == 0", + env: nil, + }, + want: true, + wantErr: false, + }, { + name: "expect false", + args: args{ + expression: "0 != 0", + env: nil, + }, + want: false, + wantErr: false, + }, { + name: "exitCode is 0", + args: args{ + expression: "exitCode == 0", + env: map[string]interface{}{ + "exitCode": 0, + }, + }, + want: true, + wantErr: false, + }, { + name: "stdout is empty", + args: args{ + expression: "len(stdout) == 0 && stdout == \"\"", + env: map[string]interface{}{ + "stdout": "", + }, + }, + want: true, + wantErr: false, + }, { + name: "embedded value assertion", + args: args{ + expression: "obj.name == \"foo\"", + env: map[string]interface{}{ + "obj": map[string]interface{}{ + "name": "foo", + }, + }, + }, + want: true, + wantErr: false, + }, { + name: "not a bool expression", + args: args{ + expression: "0", + env: nil, + }, + want: false, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := EvalBool(tt.args.expression, tt.args.env) + if (err != nil) != tt.wantErr { + t.Errorf("EvalBool() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("EvalBool() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/fakeclockgettime/fake_clock_gettime.c b/pkg/fakeclockgettime/fake_clock_gettime.c deleted file mode 100644 index 2e14418ced..0000000000 --- a/pkg/fakeclockgettime/fake_clock_gettime.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include - -int64_t TV_SEC_DELTA = 0; -int64_t TV_NSEC_DELTA = 0; -uint64_t CLOCK_IDS_MASK = 0; - -long syscall(long number, ...); - -int clock_gettime(clockid_t clk_id, struct timespec *tp) { - int ret; - asm volatile - ( - "syscall" - : "=a" (ret) - : "0"(228), "D"(clk_id), "S"(tp) - : "rcx", "r11", "memory" - ); - - int64_t sec_delta = TV_SEC_DELTA; - int64_t nsec_delta = TV_NSEC_DELTA; - uint64_t clock_ids_mask = CLOCK_IDS_MASK; - - int64_t billion = 1000000000; - - uint64_t clk_id_mask = 1 << clk_id; - if((clk_id_mask & clock_ids_mask) != 0) { - while (nsec_delta + tp->tv_nsec > billion) { - sec_delta += 1; - nsec_delta -= billion; - } - - while (nsec_delta + tp->tv_nsec < 0) { - sec_delta -= 1; - nsec_delta += billion; - } - - tp->tv_sec += sec_delta; - tp->tv_nsec += nsec_delta; - } - - return ret; -} \ No newline at end of file diff --git a/pkg/finalizer/finalizer_test.go b/pkg/finalizer/finalizer_test.go index 46b8346565..7bb0304397 100644 --- a/pkg/finalizer/finalizer_test.go +++ b/pkg/finalizer/finalizer_test.go @@ -1,15 +1,17 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package finalizer @@ -38,7 +40,12 @@ func TestInsertFinalizer(t *testing.T) { g := NewGomegaWithT(t) finalizers := []string{"1"} - InsertFinalizer(finalizers, "1") + finalizers = InsertFinalizer(finalizers, "1") g.Expect(finalizers).Should(Equal([]string{"1"})) + + finalizers = []string{"1", "2"} + finalizers = InsertFinalizer(finalizers, "3") + + g.Expect(finalizers).Should(Equal([]string{"1", "2", "3"})) } diff --git a/pkg/finalizer/utils.go b/pkg/finalizer/utils.go index f634b2a145..275dd6fbc6 100644 --- a/pkg/finalizer/utils.go +++ b/pkg/finalizer/utils.go @@ -1,15 +1,17 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package finalizer @@ -25,16 +27,11 @@ func RemoveFromFinalizer(finalizers []string, key string) []string { } func InsertFinalizer(finalizers []string, finalizer string) []string { - exist := false - for _, f := range finalizers { if f == finalizer { - exist = true + return finalizers } } - if exist { - return finalizers - } return append(finalizers, finalizer) } diff --git a/pkg/flags/flags.go b/pkg/flags/flags.go index 8ef61565f1..a71cf6c935 100644 --- a/pkg/flags/flags.go +++ b/pkg/flags/flags.go @@ -1,21 +1,25 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package flags import ( "fmt" "strings" + + "github.com/pkg/errors" ) // MapStringStringFlag is a flag struct for key=value pairs @@ -40,7 +44,7 @@ func (s *MapStringStringFlag) Set(value string) error { for _, p := range strings.Split(value, ",") { fields := strings.Split(p, "=") if len(fields) != 2 { - return fmt.Errorf("%s is incorrectly formatted! should be key=value[,key2=value2]", p) + return errors.Errorf("%s is incorrectly formatted! should be key=value[,key2=value2]", p) } s.Values[fields[0]] = fields[1] } diff --git a/pkg/flags/flags_test.go b/pkg/flags/flags_test.go index c2736c88ed..8f07cedf77 100644 --- a/pkg/flags/flags_test.go +++ b/pkg/flags/flags_test.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package flags diff --git a/pkg/fusedev/fusedev_darwin.go b/pkg/fusedev/fusedev_darwin.go index c7d89cdb3c..8a8ae26acd 100644 --- a/pkg/fusedev/fusedev_darwin.go +++ b/pkg/fusedev/fusedev_darwin.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package fusedev diff --git a/pkg/fusedev/fusedev_linux.go b/pkg/fusedev/fusedev_linux.go index 4c8b9d680f..644acccaf7 100644 --- a/pkg/fusedev/fusedev_linux.go +++ b/pkg/fusedev/fusedev_linux.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package fusedev @@ -55,10 +57,11 @@ func GrantAccess() error { } if len(deviceCgroupPath) == 0 { - return errors.Errorf("fail to find device cgroup") + return errors.New("fail to find device cgroup") } - deviceCgroupPath = "/sys/fs/cgroup/devices" + deviceCgroupPath + "/devices.allow" + // It's hard to use /pkg/chaosdaemon/cgroups to wrap this logic. + deviceCgroupPath = "/host-sys/fs/cgroup/devices" + deviceCgroupPath + "/devices.allow" f, err := os.OpenFile(deviceCgroupPath, os.O_WRONLY, 0) if err != nil { return err @@ -68,9 +71,5 @@ func GrantAccess() error { // 10, 229 according to https://www.kernel.org/doc/Documentation/admin-guide/devices.txt content := "c 10:229 rwm" _, err = f.WriteString(content) - if err != nil { - return err - } - - return nil + return err } diff --git a/pkg/grpc/utils.go b/pkg/grpc/utils.go index c02dd821ce..fa7b5cbc51 100644 --- a/pkg/grpc/utils.go +++ b/pkg/grpc/utils.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package grpc @@ -17,14 +19,18 @@ import ( "context" "crypto/tls" "crypto/x509" - "fmt" - "io/ioutil" + "net" + "os" + "strconv" "time" + "github.com/pkg/errors" + "google.golang.org/grpc" "google.golang.org/grpc/credentials" + "google.golang.org/grpc/metadata" + "k8s.io/apimachinery/pkg/types" - "google.golang.org/grpc" - ctrl "sigs.k8s.io/controller-runtime" + "github.com/chaos-mesh/chaos-mesh/pkg/log" ) // DefaultRPCTimeout specifies default timeout of RPC between controller and chaos-operator @@ -33,44 +39,61 @@ const DefaultRPCTimeout = 60 * time.Second // RPCTimeout specifies timeout of RPC between controller and chaos-operator var RPCTimeout = DefaultRPCTimeout -var log = ctrl.Log.WithName("util") - -// CreateGrpcConnection create a grpc connection with given port and address -func CreateGrpcConnection(address string, port int, caCertPath string, certPath string, keyPath string) (*grpc.ClientConn, error) { - if caCertPath != "" && certPath != "" && keyPath != "" { - var caCert, cert, key []byte - var err error - caCert, err = ioutil.ReadFile(caCertPath) - if err != nil { - return nil, err - } - cert, err = ioutil.ReadFile(certPath) - if err != nil { - return nil, err - } - key, err = ioutil.ReadFile(keyPath) - if err != nil { - return nil, err - } - return CreateGrpcConnectionFromRaw(address, port, caCert, cert, key) +const ChaosDaemonServerName = "chaos-daemon.chaos-mesh.org" + +type TLSRaw struct { + CaCert []byte + Cert []byte + Key []byte +} + +type TLSFile struct { + CaCert string + Cert string + Key string +} + +type FileProvider struct { + file TLSFile +} + +type RawProvider struct { + raw TLSRaw +} + +type InsecureProvider struct { +} + +type CredentialProvider interface { + getCredentialOption() (grpc.DialOption, error) +} + +func (it *FileProvider) getCredentialOption() (grpc.DialOption, error) { + caCert, err := os.ReadFile(it.file.CaCert) + if err != nil { + return nil, err } - options := []grpc.DialOption{grpc.WithUnaryInterceptor(TimeoutClientInterceptor)} - options = append(options, grpc.WithInsecure()) - conn, err := grpc.Dial(fmt.Sprintf("%s:%d", address, port), options...) + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + + clientCert, err := tls.LoadX509KeyPair(it.file.Cert, it.file.Key) if err != nil { return nil, err } - return conn, nil -} -// CreateGrpcConnectionFromRaw create a grpc connection with given port and address, and use raw data instead of file path -func CreateGrpcConnectionFromRaw(address string, port int, caCert []byte, cert []byte, key []byte) (*grpc.ClientConn, error) { - options := []grpc.DialOption{grpc.WithUnaryInterceptor(TimeoutClientInterceptor)} + creds := credentials.NewTLS(&tls.Config{ + Certificates: []tls.Certificate{clientCert}, + RootCAs: caCertPool, + ServerName: ChaosDaemonServerName, + }) + return grpc.WithTransportCredentials(creds), nil +} +func (it *RawProvider) getCredentialOption() (grpc.DialOption, error) { caCertPool := x509.NewCertPool() - caCertPool.AppendCertsFromPEM(caCert) + caCertPool.AppendCertsFromPEM(it.raw.CaCert) - clientCert, err := tls.X509KeyPair(cert, key) + clientCert, err := tls.X509KeyPair(it.raw.Cert, it.raw.Key) if err != nil { return nil, err } @@ -78,24 +101,98 @@ func CreateGrpcConnectionFromRaw(address string, port int, caCert []byte, cert [ creds := credentials.NewTLS(&tls.Config{ Certificates: []tls.Certificate{clientCert}, RootCAs: caCertPool, - ServerName: "chaos-daemon.chaos-mesh.org", + ServerName: ChaosDaemonServerName, }) - options = append(options, grpc.WithTransportCredentials(creds)) + return grpc.WithTransportCredentials(creds), nil +} + +func (it *InsecureProvider) getCredentialOption() (grpc.DialOption, error) { + return grpc.WithInsecure(), nil +} + +type GrpcBuilder struct { + options []grpc.DialOption + credentialProvider CredentialProvider + address string + port int +} + +func Builder(address string, port int) *GrpcBuilder { + return &GrpcBuilder{options: []grpc.DialOption{}, address: address, port: port} +} + +func (it *GrpcBuilder) WithDefaultTimeout() *GrpcBuilder { + it.options = append(it.options, grpc.WithUnaryInterceptor(TimeoutClientInterceptor(DefaultRPCTimeout))) + return it +} + +func (it *GrpcBuilder) WithTimeout(timeout time.Duration) *GrpcBuilder { + it.options = append(it.options, grpc.WithUnaryInterceptor(TimeoutClientInterceptor(timeout))) + return it +} + +func namespacedNameInterceptor(id types.NamespacedName) grpc.UnaryClientInterceptor { + return func(ctx context.Context, method string, req, reply interface{}, conn *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + ctx = metadata.AppendToOutgoingContext(ctx, string(log.MetaNamespacedName), id.String()) + + return invoker(ctx, method, req, reply, conn, opts...) + } +} + +func (it *GrpcBuilder) WithNamespacedName(id types.NamespacedName) *GrpcBuilder { + it.options = append(it.options, grpc.WithUnaryInterceptor(namespacedNameInterceptor(id))) + return it +} + +func (it *GrpcBuilder) Insecure() *GrpcBuilder { + it.credentialProvider = &InsecureProvider{} + return it +} + +func (it *GrpcBuilder) TLSFromRaw(caCert []byte, cert []byte, key []byte) *GrpcBuilder { + it.credentialProvider = &RawProvider{ + raw: TLSRaw{ + CaCert: caCert, + Cert: cert, + Key: key, + }, + } - conn, err := grpc.Dial(fmt.Sprintf("%s:%d", address, port), - options...) + return it +} + +func (it *GrpcBuilder) TLSFromFile(caCertPath string, certPath string, keyPath string) *GrpcBuilder { + it.credentialProvider = &FileProvider{ + file: TLSFile{ + CaCert: caCertPath, + Cert: certPath, + Key: keyPath, + }, + } + return it +} + +func (it *GrpcBuilder) Build() (*grpc.ClientConn, error) { + if it.credentialProvider == nil { + return nil, errors.New("an authorization method must be specified") + } + credentialOption, err := it.credentialProvider.getCredentialOption() if err != nil { return nil, err } - return conn, nil + it.options = append(it.options, credentialOption) + return grpc.Dial(net.JoinHostPort(it.address, strconv.Itoa(it.port)), it.options...) } // TimeoutClientInterceptor wraps the RPC with a timeout. -func TimeoutClientInterceptor(ctx context.Context, method string, req, reply interface{}, - cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { - ctx, cancel := context.WithTimeout(ctx, RPCTimeout) - defer cancel() - return invoker(ctx, method, req, reply, cc, opts...) +func TimeoutClientInterceptor(timeout time.Duration) func(context.Context, string, interface{}, interface{}, + *grpc.ClientConn, grpc.UnaryInvoker, ...grpc.CallOption) error { + return func(ctx context.Context, method string, req, reply interface{}, + cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + return invoker(ctx, method, req, reply, cc, opts...) + } } // TimeoutServerInterceptor ensures the context is intact before handling over the diff --git a/pkg/helm/chart.go b/pkg/helm/chart.go new file mode 100644 index 0000000000..fdfd2fdb6c --- /dev/null +++ b/pkg/helm/chart.go @@ -0,0 +1,92 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package helm + +import ( + "context" + "fmt" + "io" + "net/http" + "os" + + "github.com/pkg/errors" + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chart/loader" +) + +const ChaosMeshHelmRepo = "https://charts.chaos-mesh.org" + +func FetchChaosMeshChart(ctx context.Context, version, local string) (*chart.Chart, error) { + var ( + tgzPath string + err error + ) + if local != "" { + if tgzPath, err = GetChaosMeshChartTgzPath(ctx, version, local); err != nil { + return nil, err + } + } else { + if tgzPath, err = DownloadChaosMeshChartTgz(ctx, version); err != nil { + return nil, err + } + } + + requestedChart, err := loader.Load(tgzPath) + if err != nil { + return nil, errors.Wrapf(err, "load helm chart from %s", tgzPath) + } + return requestedChart, nil +} + +func GetChaosMeshChartTgzPath(ctx context.Context, version, local string) (string, error) { + fileName := fmt.Sprintf("chaos-mesh-%s.tgz", version) + tgzPath := fmt.Sprintf("%s/%s", os.TempDir(), fileName) + if local != "" { + tgzPath = fmt.Sprintf("%s/%s", local, fileName) + } + + if _, err := os.Stat(tgzPath); err != nil { + return "", err + } + return tgzPath, nil +} + +func DownloadChaosMeshChartTgz(ctx context.Context, version string) (string, error) { + url := fmt.Sprintf("%s/chaos-mesh-%s.tgz", ChaosMeshHelmRepo, version) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return "", errors.Wrapf(err, "failed to generate http request for url %s", url) + } + response, err := http.DefaultClient.Do(req) + if err != nil { + return "", errors.Wrapf(err, "download helm chart from %s", url) + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return "", errors.Wrapf(err, "download helm chart from %s", url) + } + target, err := os.CreateTemp("", fmt.Sprintf("chaos-mesh-%s-*.tgz", version)) + if err != nil { + return "", errors.Wrapf(err, "download helm chart as temp file") + } + defer target.Close() + _, err = io.Copy(target, response.Body) + if err != nil { + return "", errors.Wrapf(err, "download helm chart content") + } + return target.Name(), nil +} diff --git a/pkg/helm/chart_test.go b/pkg/helm/chart_test.go new file mode 100644 index 0000000000..a1425df8c3 --- /dev/null +++ b/pkg/helm/chart_test.go @@ -0,0 +1,42 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package helm + +import ( + "context" + "fmt" + "os" +) + +func ExampleDownloadChaosMeshChartTgz() { + path, err := DownloadChaosMeshChartTgz(context.Background(), "2.2.0") + if err != nil { + panic(err) + } + fmt.Fprintln(os.Stderr, path) + // Output: +} + +func ExampleFetchChaosMeshChart() { + chart, err := FetchChaosMeshChart(context.Background(), "2.2.0", "") + if err != nil { + panic(err) + } + fmt.Fprintln(os.Stderr, chart.Name()) + fmt.Fprintln(os.Stderr, chart.Metadata.Version) + fmt.Fprintln(os.Stderr, chart.AppVersion()) + // Output: +} diff --git a/pkg/helm/doc.go b/pkg/helm/doc.go new file mode 100644 index 0000000000..3a8b61fe0e --- /dev/null +++ b/pkg/helm/doc.go @@ -0,0 +1,18 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package helm introduces the integration with helm, for example: +// install / upgrade Chaos Mesh on remote cluster +package helm diff --git a/pkg/helm/helm_client.go b/pkg/helm/helm_client.go new file mode 100644 index 0000000000..be2ce1cddf --- /dev/null +++ b/pkg/helm/helm_client.go @@ -0,0 +1,124 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package helm + +import ( + "fmt" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chartutil" + "helm.sh/helm/v3/pkg/kube" + "helm.sh/helm/v3/pkg/registry" + "helm.sh/helm/v3/pkg/release" + "helm.sh/helm/v3/pkg/storage" + "helm.sh/helm/v3/pkg/storage/driver" + "k8s.io/cli-runtime/pkg/genericclioptions" +) + +type HelmClient struct { + restClientGetter genericclioptions.RESTClientGetter + logger logr.Logger +} + +func NewHelmClient(restClientGetter genericclioptions.RESTClientGetter, logger logr.Logger) (*HelmClient, error) { + return &HelmClient{restClientGetter: restClientGetter, logger: logger}, nil +} + +func (h HelmClient) spawnConfigurationWithNamespace(namespace string) (*action.Configuration, error) { + registryClient, err := registry.NewClient() + if err != nil { + return nil, errors.Wrap(err, "create helm registry client") + } + kubeclient := kube.New(h.restClientGetter) + if err != nil { + return nil, errors.Wrap(err, "create kubernetes client set") + } + clientset, err := kubeclient.Factory.KubernetesClientSet() + if err != nil { + return nil, errors.Wrap(err, "create kubernetes client set") + } + secretInterface := clientset.CoreV1().Secrets(namespace) + helmConfiguration := action.Configuration{ + Releases: storage.Init(driver.NewSecrets(secretInterface)), + KubeClient: kubeclient, + Capabilities: chartutil.DefaultCapabilities, + RegistryClient: registryClient, + RESTClientGetter: h.restClientGetter, + Log: func(format string, v ...interface{}) { + h.logger.Info(fmt.Sprintf(format, v...)) + }, + } + return &helmConfiguration, nil +} + +func (h *HelmClient) GetRelease(namespace string, releaseName string) (*release.Release, error) { + configurationWithNamespace, err := h.spawnConfigurationWithNamespace(namespace) + if err != nil { + return nil, errors.Wrap(err, "create helm configuration") + } + getAction := action.NewGet(configurationWithNamespace) + result, err := getAction.Run(releaseName) + if err != nil { + return nil, errors.Wrapf(err, "get release %s, in namespace %s", releaseName, namespace) + } + return result, nil +} + +func (h *HelmClient) InstallRelease(namespace string, releaseName string, chart *chart.Chart, values map[string]interface{}) (*release.Release, error) { + configurationWithNamespace, err := h.spawnConfigurationWithNamespace(namespace) + if err != nil { + return nil, errors.Wrap(err, "create helm configuration") + } + actionInstall := action.NewInstall(configurationWithNamespace) + actionInstall.ReleaseName = releaseName + actionInstall.Namespace = namespace + actionInstall.CreateNamespace = true + result, err := actionInstall.Run(chart, values) + if err != nil { + return nil, errors.Wrapf(err, "install release %s, with chart %s, with values %v", releaseName, chart.Metadata.Name, values) + } + return result, nil +} + +func (h *HelmClient) UpgradeRelease(namespace string, releaseName string, chart *chart.Chart, values map[string]interface{}) (*release.Release, error) { + configurationWithNamespace, err := h.spawnConfigurationWithNamespace(namespace) + if err != nil { + return nil, errors.Wrap(err, "create helm configuration") + } + actionUpgrade := action.NewUpgrade(configurationWithNamespace) + actionUpgrade.Namespace = namespace + result, err := actionUpgrade.Run(releaseName, chart, values) + if err != nil { + return nil, errors.Wrapf(err, "upgrade release %s, with chart %s, with values %v", releaseName, chart.Metadata.Name, values) + } + return result, nil +} + +func (h *HelmClient) UninstallRelease(namespace string, releaseName string) (*release.UninstallReleaseResponse, error) { + configurationWithNamespace, err := h.spawnConfigurationWithNamespace(namespace) + if err != nil { + return nil, errors.Wrap(err, "create helm configuration") + } + uninstallAction := action.NewUninstall(configurationWithNamespace) + response, err := uninstallAction.Run(releaseName) + if err != nil { + return nil, errors.Wrapf(err, "uninstall release %s, in namespace %s", releaseName, namespace) + } + return response, nil +} diff --git a/pkg/helm/helm_client_test.go b/pkg/helm/helm_client_test.go new file mode 100644 index 0000000000..57493b080e --- /dev/null +++ b/pkg/helm/helm_client_test.go @@ -0,0 +1,127 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +//go:build integration + +package helm + +import ( + "context" + "fmt" + "os" + + "helm.sh/helm/v3/pkg/cli" + + "github.com/chaos-mesh/chaos-mesh/pkg/log" +) + +func ExampleHelmClient_InstallRelease() { + chart, err := FetchChaosMeshChart(context.Background(), "2.2.0") + if err != nil { + panic(err) + } + + settings := cli.New() + restClientGetter := settings.RESTClientGetter() + logger, err := log.NewDefaultZapLogger() + if err != nil { + panic(err) + } + client, err := NewHelmClient(restClientGetter, logger) + if err != nil { + panic(err) + } + _, err = client.InstallRelease( + "chaos-mesh", + "chaos-mesh-in-remote-cluster", + chart, + nil, + ) + if err != nil { + panic(err) + } + // Output: +} + +func ExampleHelmClient_UpgradeRelease() { + chart, err := FetchChaosMeshChart(context.Background(), "2.5.0") + if err != nil { + panic(err) + } + + settings := cli.New() + restClientGetter := settings.RESTClientGetter() + logger, err := log.NewDefaultZapLogger() + if err != nil { + panic(err) + } + client, err := NewHelmClient(restClientGetter, logger) + if err != nil { + panic(err) + } + _, err = client.UpgradeRelease( + "chaos-mesh", + "chaos-mesh-in-remote-cluster", + chart, + nil, + ) + if err != nil { + panic(err) + } + // Output: +} + +func ExampleHelmClient_GetRelease() { + settings := cli.New() + restClientGetter := settings.RESTClientGetter() + logger, err := log.NewDefaultZapLogger() + if err != nil { + panic(err) + } + client, err := NewHelmClient(restClientGetter, logger) + if err != nil { + panic(err) + } + release, err := client.GetRelease( + "chaos-mesh", + "chaos-mesh-in-remote-cluster", + ) + if err != nil { + panic(err) + } + fmt.Fprintln(os.Stderr, release.Name) + // Output: +} + +func ExampleHelmClient_UninstallRelease() { + settings := cli.New() + restClientGetter := settings.RESTClientGetter() + logger, err := log.NewDefaultZapLogger() + if err != nil { + panic(err) + } + client, err := NewHelmClient(restClientGetter, logger) + if err != nil { + panic(err) + } + _, err = client.UninstallRelease( + "chaos-mesh", + "chaos-mesh-in-remote-cluster", + ) + if err != nil { + panic(err) + } + // Output: +} diff --git a/pkg/helm/interfaces.go b/pkg/helm/interfaces.go new file mode 100644 index 0000000000..b62edf3f37 --- /dev/null +++ b/pkg/helm/interfaces.go @@ -0,0 +1,39 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package helm + +import ( + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/release" +) + +// ReleaseService introduces all the operations about Helm Release +type ReleaseService interface { + /*GetRelease would fetch the installed release. + */ + GetRelease(namespace string, releaseName string) (*release.Release, error) + + /*UpgradeOrInstall would upgrade the existed release or install a new one. + namespace is the namespace of the release, it should be an existed namespace. + releaseName introduces the name of the release. + chart is the chart with certain version to be installed. + values is the values to be used in the chart, it is also so-called Config in helm's codes. + It will return the installed/upgraded release and error if any. + */ + UpgradeOrInstall(namespace string, releaseName string, chart *chart.Chart, values map[string]interface{}) (*release.Release, error) + + UninstallRelease(namespace string, releaseName string) (*release.UninstallReleaseResponse, error) +} diff --git a/pkg/helm/restclientgetter.go b/pkg/helm/restclientgetter.go new file mode 100644 index 0000000000..489a0400dc --- /dev/null +++ b/pkg/helm/restclientgetter.go @@ -0,0 +1,71 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package helm + +import ( + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/client-go/discovery" + "k8s.io/client-go/discovery/cached/memory" + "k8s.io/client-go/rest" + "k8s.io/client-go/restmapper" + "k8s.io/client-go/tools/clientcmd" +) + +var _ genericclioptions.RESTClientGetter = &restClientGetter{} + +type restClientGetter struct { + clientConfig clientcmd.ClientConfig +} + +func NewRESTClientGetter(clientConfig clientcmd.ClientConfig) genericclioptions.RESTClientGetter { + return &restClientGetter{ + clientConfig, + } +} + +func (getter *restClientGetter) ToRESTConfig() (*rest.Config, error) { + return getter.clientConfig.ClientConfig() +} + +func (getter *restClientGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { + restConfig, err := getter.clientConfig.ClientConfig() + if err != nil { + return nil, errors.Wrap(err, "get rest config from client config") + } + + client, err := discovery.NewDiscoveryClientForConfig(restConfig) + if err != nil { + return nil, errors.Wrap(err, "create discovery client") + } + return memory.NewMemCacheClient(client), nil +} + +func (getter *restClientGetter) ToRESTMapper() (meta.RESTMapper, error) { + discoveryClient, err := getter.ToDiscoveryClient() + if err != nil { + return nil, err + } + + mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) + expander := restmapper.NewShortcutExpander(mapper, discoveryClient) + return expander, nil +} + +func (getter *restClientGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig { + return getter.clientConfig +} diff --git a/pkg/jvm/action.go b/pkg/jvm/action.go deleted file mode 100644 index 82cfba96bb..0000000000 --- a/pkg/jvm/action.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package jvm - -import ( - "encoding/json" - "fmt" - "strconv" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -const ( - SUID string = "suid" - ACTION string = "action" - TARGET string = "target" -) - -// ToSandboxAction convertes chaos to sandbox action -func ToSandboxAction(suid string, chaos *v1alpha1.JVMChaos) ([]byte, error) { - if _, ok := v1alpha1.JvmSpec[chaos.Spec.Target]; !ok { - return nil, fmt.Errorf("unknown JVM chaos target:%s", - chaos.Spec.Target) - } - - if _, ok := v1alpha1.JvmSpec[chaos.Spec.Target][chaos.Spec.Action]; !ok { - return nil, fmt.Errorf("JVM target: %s does not supported action: %s", - chaos.Spec.Target, chaos.Spec.Action) - } - - kv := make(map[string]string) - flags := v1alpha1.JvmSpec[chaos.Spec.Target][chaos.Spec.Action].Flags - if flags != nil { - for k, v := range chaos.Spec.Flags { - for _, rule := range flags { - if rule.Name != k { - continue - } - - if rule.ParameterType != v1alpha1.BoolType { - kv[k] = v - } else { - f, err := strconv.ParseBool(v) - if err != nil { - return nil, fmt.Errorf("can not parse Spec.Flags.%s's value:%s as boolean", k, v) - } - // if f is false, should not send key-value to sandbox server. - if f { - kv[k] = v - } - } - } - } - } - - matchers := v1alpha1.JvmSpec[chaos.Spec.Target][chaos.Spec.Action].Matchers - if matchers != nil { - for k, v := range chaos.Spec.Matchers { - for _, rule := range matchers { - if rule.Name != k { - continue - } - - if rule.ParameterType != v1alpha1.BoolType { - kv[k] = v - } else { - f, err := strconv.ParseBool(v) - if err != nil { - return nil, fmt.Errorf("can not parse Spec.Matchers.%s's value:%s as boolean", k, v) - } - // if f is false, should not send key-value to sandbox server. - if f { - kv[k] = v - } - } - } - } - } - - kv[SUID] = suid - kv[ACTION] = fmt.Sprint(chaos.Spec.Action) - kv[TARGET] = fmt.Sprint(chaos.Spec.Target) - return json.Marshal(kv) -} diff --git a/pkg/jvm/sandbox.go b/pkg/jvm/sandbox.go deleted file mode 100644 index fb92f9ea8b..0000000000 --- a/pkg/jvm/sandbox.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package jvm - -import ( - "bytes" - "fmt" - "io/ioutil" - "net/http" -) - -const ( - BaseURL = "http://%s:%d/sandbox/default/module/http/" - ActiveURL = BaseURL + "sandbox-module-mgr/active?ids=chaosblade" - InjectURL = BaseURL + "chaosblade/create" - RecoverURL = BaseURL + "chaosblade/destroy" -) - -// ActiveSandbox activates sandboxes -func ActiveSandbox(host string, port int) error { - url := fmt.Sprintf(ActiveURL, host, port) - - _, err := http.Get(url) - if err != nil { - return err - } - return nil -} - -// InjectChaos injects jvm chaos to a java process -func InjectChaos(host string, port int, body []byte) error { - url := fmt.Sprintf(InjectURL, host, port) - return httpPost(url, body) -} - -// RecoverChaos recovers jvm chaos from a java process -func RecoverChaos(host string, port int, body []byte) error { - url := fmt.Sprintf(RecoverURL, host, port) - return httpPost(url, body) -} - -func httpPost(url string, body []byte) error { - client := &http.Client{} - reqBody := bytes.NewBuffer([]byte(body)) - request, err := http.NewRequest("POST", url, reqBody) - if err != nil { - return err - } - - request.Header.Set("Content-type", "application/json") - response, err := client.Do(request) - if err != nil { - return err - } - - if response.StatusCode != 200 { - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - return fmt.Errorf("jvm sandbox error response:%s", data) - } - return nil -} diff --git a/pkg/label/label.go b/pkg/label/label.go index 9ff6582ce1..ee4e59d4dc 100644 --- a/pkg/label/label.go +++ b/pkg/label/label.go @@ -1,21 +1,25 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package label import ( "fmt" "strings" + + "github.com/pkg/errors" ) // Label is the label field in metadata @@ -35,3 +39,19 @@ func (l Label) String() string { return strings.Join(arr, ",") } + +func ParseLabel(data string) (Label, error) { + if len(data) == 0 { + return Label{}, nil + } + + labels := make(map[string]string) + for _, tok := range strings.Split(data, ",") { + kv := strings.Split(tok, "=") + if len(kv) != 2 { + return nil, errors.Errorf("invalid labels: %s", data) + } + labels[kv[0]] = kv[1] + } + return labels, nil +} diff --git a/pkg/label/label_test.go b/pkg/label/label_test.go index 4dfc3ba9c8..9487615069 100644 --- a/pkg/label/label_test.go +++ b/pkg/label/label_test.go @@ -1,19 +1,22 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package label import ( + "reflect" "strings" "testing" @@ -37,3 +40,30 @@ func TestLabelString(t *testing.T) { g.Expect(len(la.String())).To(Equal(len("test-label-1=t1,test-label-2=t2"))) g.Expect(strings.Contains(la.String(), "t3")).To(Equal(false)) } + +func TestParseLabel(t *testing.T) { + g := NewGomegaWithT(t) + + label1 := "k1=v1" + labelMap1 := Label{"k1": "v1"} + result, err := ParseLabel(label1) + + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(reflect.DeepEqual(labelMap1, result)).To(Equal(true)) + + label2 := "k1=v1,k2=v2" + labelMap2 := Label{"k1": "v1", "k2": "v2"} + result, err = ParseLabel(label2) + + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(reflect.DeepEqual(labelMap2, result)).To(Equal(true)) + + label3 := "" + _, err = ParseLabel(label3) + g.Expect(err).ToNot(HaveOccurred()) + + label4 := "k1=v2,," + _, err = ParseLabel(label4) + g.Expect(err).To(HaveOccurred()) + g.Expect(strings.Contains(err.Error(), "invalid labels")).To(BeTrue()) +} diff --git a/pkg/log/doc.go b/pkg/log/doc.go new file mode 100644 index 0000000000..e2b9869759 --- /dev/null +++ b/pkg/log/doc.go @@ -0,0 +1,20 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package log contains series of utilities for setting up and accessing logger. +// We use logr.Logger as the facade of each logger. +// +// See https://github.com/chaos-mesh/rfcs/blob/main/text/2021-12-09-logging.md for more details. +package log diff --git a/pkg/log/global_logger.go b/pkg/log/global_logger.go new file mode 100644 index 0000000000..60060c8bd4 --- /dev/null +++ b/pkg/log/global_logger.go @@ -0,0 +1,55 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package log + +import ( + "sync" + + "github.com/go-logr/logr" +) + +// the way for management and access global logger is referenced from zap. +var ( + globalMu sync.RWMutex + globalLogger = logr.Discard() +) + +// L is the way to access the global logger. You could use it if there are no logger in your code context. Please notice +// that the default value of "global logger" is a "discard logger" which means that all logs will be ignored. Make sure +// that initialize the global logger by ReplaceGlobals before using it, for example, calling ReplaceGlobals at the beginning +// of your main function. +// +// Do NOT save the global logger to a variable for long-term using, because it is possible that the global logger is +// replaced by another. Keep calling L at each time. +// +// Deprecated: Do not use global logger anymore. For more detail, see +// https://github.com/chaos-mesh/rfcs/blob/main/text/2021-12-09-logging.md#global-logger +func L() logr.Logger { + globalMu.RLock() + result := globalLogger + globalMu.RUnlock() + return result +} + +// ReplaceGlobals would replace the global logger with the given logger. It should be used when your application starting. +// +// Deprecated: Do not use global logger anymore. For more detail, see +// https://github.com/chaos-mesh/rfcs/blob/main/text/2021-12-09-logging.md#global-logger +func ReplaceGlobals(logger logr.Logger) { + globalMu.Lock() + globalLogger = logger + globalMu.Unlock() +} diff --git a/pkg/log/metadata.go b/pkg/log/metadata.go new file mode 100644 index 0000000000..74704227f8 --- /dev/null +++ b/pkg/log/metadata.go @@ -0,0 +1,38 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package log + +import ( + "context" + + "github.com/go-logr/logr" +) + +type Metadatkey string + +const ( + MetaNamespacedName Metadatkey = "namespaced-name" +) + +func EnrichLoggerWithContext(ctx context.Context, logger logr.Logger) logr.Logger { + newLogger := logger + if ctx != nil { + if namespacedName, ok := ctx.Value(MetaNamespacedName).(string); ok { + newLogger = newLogger.WithValues("namespacedName", namespacedName) + } + } + return newLogger +} diff --git a/pkg/log/zap.go b/pkg/log/zap.go new file mode 100644 index 0000000000..ee39fedeba --- /dev/null +++ b/pkg/log/zap.go @@ -0,0 +1,50 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package log + +import ( + "io" + + "github.com/go-logr/logr" + "github.com/go-logr/zapr" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// NewDefaultZapLogger is the recommended way to create a new logger, you could call this function to initialize the root +// logger of your application, and provide it to your components, by fx or manually. +func NewDefaultZapLogger() (logr.Logger, error) { + // change the configuration in the future if needed. + zapLogger, err := zap.NewDevelopment() + if err != nil { + return logr.Discard(), err + } + logger := zapr.NewLogger(zapLogger) + return logger, nil +} + +// NewZapLoggerWithWriter creates a new logger with io.writer +// The provided encoder presets NewDevelopmentEncoderConfig used by NewDevelopmentConfig do not enable function name logging. +// To enable function name, a non-empty value for config.EncoderConfig.FunctionKey. +func NewZapLoggerWithWriter(out io.Writer) logr.Logger { + bWriter := out + config := zap.NewDevelopmentConfig() + config.EncoderConfig.FunctionKey = "function" + core := zapcore.NewCore(zapcore.NewJSONEncoder(config.EncoderConfig), zapcore.AddSync(bWriter), config.Level) + zapLogger := zap.New(core) + logger := zapr.NewLogger(zapLogger) + return logger +} diff --git a/pkg/mapreader/reader.go b/pkg/mapreader/reader.go index 85b6355bfc..7cdf586292 100644 --- a/pkg/mapreader/reader.go +++ b/pkg/mapreader/reader.go @@ -1,21 +1,23 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package mapreader import ( "fmt" - "io/ioutil" + "os" "strconv" "strings" @@ -34,7 +36,7 @@ type Entry struct { // Read parse /proc/[pid]/maps and return a list of entry // The format of /proc/[pid]/maps can be found in `man proc`. func Read(pid int) ([]Entry, error) { - data, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/maps", pid)) + data, err := os.ReadFile(fmt.Sprintf("/proc/%d/maps", pid)) if err != nil { return nil, errors.WithStack(err) } diff --git a/pkg/metrics/chaos-controller-manager.go b/pkg/metrics/chaos-controller-manager.go new file mode 100644 index 0000000000..33d6873487 --- /dev/null +++ b/pkg/metrics/chaos-controller-manager.go @@ -0,0 +1,219 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package metrics + +import ( + "context" + "reflect" + + "github.com/go-logr/logr" + "github.com/prometheus/client_golang/prometheus" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cache" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/status" +) + +// ChaosControllerManagerMetricsCollector implements prometheus.Collector interface +type ChaosControllerManagerMetricsCollector struct { + logger logr.Logger + store cache.Cache + chaosExperiments *prometheus.GaugeVec + SidecarTemplates prometheus.Gauge + ConfigTemplates *prometheus.GaugeVec + InjectionConfigs *prometheus.GaugeVec + TemplateNotExist *prometheus.CounterVec + TemplateLoadError prometheus.Counter + ConfigNameDuplicate *prometheus.CounterVec + InjectRequired *prometheus.CounterVec + Injections *prometheus.CounterVec + chaosSchedules *prometheus.GaugeVec + chaosWorkflows *prometheus.GaugeVec + EmittedEvents *prometheus.CounterVec +} + +// NewChaosControllerManagerMetricsCollector initializes metrics and collector +func NewChaosControllerManagerMetricsCollector(manager ctrl.Manager, registerer *prometheus.Registry, logger logr.Logger) *ChaosControllerManagerMetricsCollector { + var store cache.Cache + if manager != nil { + store = manager.GetCache() + } + + c := &ChaosControllerManagerMetricsCollector{ + logger: logger, + store: store, + chaosExperiments: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "chaos_controller_manager_chaos_experiments", + Help: "Total number of chaos experiments and their phases", + }, []string{"namespace", "kind", "phase"}), + SidecarTemplates: prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "chaos_mesh_templates", + Help: "Total number of injection templates", + }), + ConfigTemplates: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "chaos_mesh_config_templates", + Help: "Total number of config templates", + }, []string{"namespace", "template"}), + InjectionConfigs: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "chaos_mesh_injection_configs", + Help: "Total number of injection configs", + }, []string{"namespace", "template"}), + TemplateNotExist: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "chaos_mesh_template_not_exist_total", + Help: "Total number of template not exist error", + }, []string{"namespace", "template"}), + ConfigNameDuplicate: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "chaos_mesh_config_name_duplicate_total", + Help: "Total number of config name duplication error", + }, []string{"namespace", "config"}), + TemplateLoadError: prometheus.NewCounter(prometheus.CounterOpts{ + Name: "chaos_mesh_template_load_failed_total", + Help: "Total number of failures when rendering config args to template", + }), + InjectRequired: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "chaos_mesh_inject_required_total", + Help: "Total number of injections required", + }, []string{"namespace", "config"}), + Injections: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "chaos_mesh_injections_total", + Help: "Total number of sidecar injections performed on the webhook", + }, []string{"namespace", "config"}), + chaosSchedules: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "chaos_controller_manager_chaos_schedules", + Help: "Total number of chaos schedules", + }, []string{"namespace"}), + chaosWorkflows: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "chaos_controller_manager_chaos_workflows", + Help: "Total number of chaos workflows", + }, []string{"namespace"}), + EmittedEvents: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "chaos_controller_manager_emitted_event_total", + Help: "Total number of the emitted event by chaos-controller-manager", + }, []string{"type", "reason", "namespace"}), + } + + if registerer != nil { + registerer.MustRegister(c) + } + return c +} + +// Describe implements the prometheus.Collector interface. +func (collector *ChaosControllerManagerMetricsCollector) Describe(ch chan<- *prometheus.Desc) { + collector.chaosExperiments.Describe(ch) + collector.SidecarTemplates.Describe(ch) + collector.ConfigTemplates.Describe(ch) + collector.InjectionConfigs.Describe(ch) + collector.TemplateNotExist.Describe(ch) + collector.ConfigNameDuplicate.Describe(ch) + collector.TemplateLoadError.Describe(ch) + collector.InjectRequired.Describe(ch) + collector.Injections.Describe(ch) + collector.EmittedEvents.Describe(ch) + collector.chaosSchedules.Describe(ch) + collector.chaosWorkflows.Describe(ch) +} + +// Collect implements the prometheus.Collector interface. +func (collector *ChaosControllerManagerMetricsCollector) Collect(ch chan<- prometheus.Metric) { + collector.collectChaosExperiments() + collector.collectChaosSchedules() + collector.collectChaosWorkflows() + collector.SidecarTemplates.Collect(ch) + collector.ConfigTemplates.Collect(ch) + collector.InjectionConfigs.Collect(ch) + collector.TemplateNotExist.Collect(ch) + collector.ConfigNameDuplicate.Collect(ch) + collector.TemplateLoadError.Collect(ch) + collector.InjectRequired.Collect(ch) + collector.Injections.Collect(ch) + collector.chaosExperiments.Collect(ch) + collector.chaosSchedules.Collect(ch) + collector.chaosWorkflows.Collect(ch) + collector.EmittedEvents.Collect(ch) +} + +func (collector *ChaosControllerManagerMetricsCollector) collectChaosExperiments() { + // TODO(yeya24) if there is an error in List + // the experiment status will be lost + collector.chaosExperiments.Reset() + + for kind, obj := range v1alpha1.AllKinds() { + expCache := map[string]map[string]int{} + chaosList := obj.SpawnList() + if err := collector.store.List(context.TODO(), chaosList); err != nil { + collector.logger.Error(err, "failed to list chaos", "kind", kind) + return + } + + items := chaosList.GetItems() + for _, item := range items { + if _, ok := expCache[item.GetNamespace()]; !ok { + // There is only 4 supported phases + expCache[item.GetNamespace()] = make(map[string]int, 4) + } + innerObject := reflect.ValueOf(item).Interface().(v1alpha1.InnerObject) + expCache[item.GetNamespace()][string(status.GetChaosStatus(innerObject))]++ + } + + for ns, v := range expCache { + for phase, count := range v { + collector.chaosExperiments.WithLabelValues(ns, kind, phase).Set(float64(count)) + } + } + } +} + +func (collector *ChaosControllerManagerMetricsCollector) collectChaosSchedules() { + collector.chaosSchedules.Reset() + + schedules := &v1alpha1.ScheduleList{} + if err := collector.store.List(context.TODO(), schedules); err != nil { + collector.logger.Error(err, "failed to list schedules") + return + } + + countByNamespace := make(map[string]int) + items := schedules.GetItems() + for _, item := range items { + countByNamespace[item.GetNamespace()]++ + } + + for namespace, count := range countByNamespace { + collector.chaosSchedules.WithLabelValues(namespace).Set(float64(count)) + } +} + +func (collector *ChaosControllerManagerMetricsCollector) collectChaosWorkflows() { + collector.chaosWorkflows.Reset() + + workflows := &v1alpha1.WorkflowList{} + if err := collector.store.List(context.TODO(), workflows); err != nil { + collector.logger.Error(err, "failed to list workflows") + return + } + + countByNamespace := make(map[string]int) + items := workflows.GetItems() + for _, item := range items { + countByNamespace[item.GetNamespace()]++ + } + + for namespace, count := range countByNamespace { + collector.chaosWorkflows.WithLabelValues(namespace).Set(float64(count)) + } +} diff --git a/pkg/metrics/chaos-daemon.go b/pkg/metrics/chaos-daemon.go new file mode 100644 index 0000000000..fd08f406e6 --- /dev/null +++ b/pkg/metrics/chaos-daemon.go @@ -0,0 +1,171 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package metrics + +import ( + "context" + + "github.com/go-logr/logr" + grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" + "github.com/prometheus/client_golang/prometheus" + + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients" + "github.com/chaos-mesh/chaos-mesh/pkg/log" + "github.com/chaos-mesh/chaos-mesh/pkg/metrics/utils" +) + +var ( + // DefaultChaosDaemonMetricsCollector is the default metrics collector for chaos daemon + DefaultChaosDaemonMetricsCollector = NewChaosDaemonMetricsCollector(log.L().WithName("chaos-daemon").WithName("metrics")) + + // ChaosDaemonGrpcServerBuckets is the buckets for gRPC server handling histogram metrics + ChaosDaemonGrpcServerBuckets = []float64{0.001, 0.01, 0.1, 0.3, 0.6, 1, 3, 6, 10} +) + +const ( + // kubernetesPodNameLabel, kubernetesPodNamespaceLabel and kubernetesContainerNameLabel are the label keys + // indicating the kubernetes information of the container under `k8s.io/kubernetes` package + // And it is best not to set `k8s.io/kubernetes` as dependency, see more: https://github.com/kubernetes/kubernetes/issues/90358#issuecomment-617859364. + kubernetesPodNameLabel = "io.kubernetes.pod.name" + kubernetesPodNamespaceLabel = "io.kubernetes.pod.namespace" + kubernetesContainerNameLabel = "io.kubernetes.container.name" +) + +func WithHistogramName(name string) grpcprometheus.HistogramOption { + return func(opts *prometheus.HistogramOpts) { + opts.Name = name + } +} + +type ChaosDaemonMetricsCollector struct { + crClient crclients.ContainerRuntimeInfoClient + logger logr.Logger + iptablesPackets *prometheus.GaugeVec + iptablesPacketBytes *prometheus.GaugeVec + ipsetMembers *prometheus.GaugeVec + tcRules *prometheus.GaugeVec +} + +// NewChaosDaemonMetricsCollector initializes metrics for each chaos daemon +func NewChaosDaemonMetricsCollector(logger logr.Logger) *ChaosDaemonMetricsCollector { + return &ChaosDaemonMetricsCollector{ + logger: logger, + iptablesPackets: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "chaos_daemon_iptables_packets", + Help: "Total number of iptables packets", + }, []string{"namespace", "pod", "container", "table", "chain", "policy", "rule"}), + iptablesPacketBytes: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "chaos_daemon_iptables_packet_bytes", + Help: "Total bytes of iptables packets", + }, []string{"namespace", "pod", "container", "table", "chain", "policy", "rule"}), + ipsetMembers: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "chaos_daemon_ipset_members", + Help: "Total number of ipset members", + }, []string{"namespace", "pod", "container"}), + tcRules: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "chaos_daemon_tcs", + Help: "Total number of tc rules", + }, []string{"namespace", "pod", "container"}), + } +} + +func (collector *ChaosDaemonMetricsCollector) Describe(ch chan<- *prometheus.Desc) { + collector.iptablesPackets.Describe(ch) + collector.iptablesPacketBytes.Describe(ch) + collector.ipsetMembers.Describe(ch) + collector.tcRules.Describe(ch) +} + +func (collector *ChaosDaemonMetricsCollector) Collect(ch chan<- prometheus.Metric) { + collector.collectNetworkMetrics() + collector.iptablesPackets.Collect(ch) + collector.iptablesPacketBytes.Collect(ch) + collector.ipsetMembers.Collect(ch) + collector.tcRules.Collect(ch) +} + +func (collector *ChaosDaemonMetricsCollector) InjectCrClient(client crclients.ContainerRuntimeInfoClient) *ChaosDaemonMetricsCollector { + collector.crClient = client + return collector +} + +func (collector *ChaosDaemonMetricsCollector) collectNetworkMetrics() { + collector.iptablesPackets.Reset() + collector.iptablesPacketBytes.Reset() + collector.ipsetMembers.Reset() + collector.tcRules.Reset() + + containerIDs, err := collector.crClient.ListContainerIDs(context.Background()) + if err != nil { + collector.logger.Error(err, "fail to list all container process IDs") + return + } + + for _, containerID := range containerIDs { + pid, err := collector.crClient.GetPidFromContainerID(context.Background(), containerID) + if err != nil { + collector.logger.Error(err, "fail to get pid from container ID") + continue + } + + labels, err := collector.crClient.GetLabelsFromContainerID(context.Background(), containerID) + if err != nil { + collector.logger.Error(err, "fail to get container labels", "containerID", containerID) + continue + } + + namespace, podName, containerName := labels[kubernetesPodNamespaceLabel], + labels[kubernetesPodNameLabel], labels[kubernetesContainerNameLabel] + + labelValues := []string{namespace, podName, containerName} + log := collector.logger.WithValues( + "namespace", namespace, + "podName", podName, + "containerName", containerName, + "containerID", containerID, + ) + + tables, err := utils.GetIptablesContentByNetNS(pid) + if err != nil { + log.Error(err, "fail to collect iptables metrics") + } + for tableName, table := range tables { + for chainName, chain := range table { + for _, rule := range chain.Rules { + collector.iptablesPackets. + WithLabelValues(namespace, podName, containerName, tableName, chainName, chain.Policy, rule.Rule). + Set(float64(rule.Packets)) + + collector.iptablesPacketBytes. + WithLabelValues(namespace, podName, containerName, tableName, chainName, chain.Policy, rule.Rule). + Set(float64(rule.Bytes)) + } + } + } + + members, err := utils.GetIPSetRulesNumberByNetNS(pid) + if err != nil { + log.Error(err, "fail to collect ipset member metric") + } + collector.ipsetMembers.WithLabelValues(labelValues...).Set(float64(members)) + + tcRules, err := utils.GetTcRulesNumberByNetNS(pid) + if err != nil { + log.Error(err, "fail to collect tc rules metric") + } + collector.tcRules.WithLabelValues(labelValues...).Set(float64(tcRules)) + } +} diff --git a/pkg/metrics/chaos-dashboard.go b/pkg/metrics/chaos-dashboard.go new file mode 100644 index 0000000000..e505c7ed7f --- /dev/null +++ b/pkg/metrics/chaos-dashboard.go @@ -0,0 +1,68 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package metrics + +import ( + "strconv" + "time" + + "github.com/gin-gonic/gin" + "github.com/prometheus/client_golang/prometheus" +) + +const chaosDashboardSubsystem = "chaos_dashboard" + +// ChaosDashboardMetricsCollector implements prometheus.Collector interface +type ChaosDashboardMetricsCollector struct { + httpRequestDuration *prometheus.HistogramVec +} + +// NewChaosDashboardMetricsCollector initializes metrics and collector +func NewChaosDashboardMetricsCollector(engine *gin.Engine, registry *prometheus.Registry) *ChaosDashboardMetricsCollector { + collector := &ChaosDashboardMetricsCollector{ + httpRequestDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Subsystem: chaosDashboardSubsystem, + Name: "http_request_duration_seconds", + Help: "Time histogram for each HTTP query", + }, []string{"path", "method", "status"}), + } + + engine.Use(collector.ginMetricsCollector()) + registry.MustRegister(collector) + + return collector +} + +// Describe implements the prometheus.Collector interface. +func (collector *ChaosDashboardMetricsCollector) Describe(ch chan<- *prometheus.Desc) { + collector.httpRequestDuration.Describe(ch) +} + +// Collect implements the prometheus.Collector interface. +func (collector *ChaosDashboardMetricsCollector) Collect(ch chan<- prometheus.Metric) { + collector.httpRequestDuration.Collect(ch) +} + +func (collector *ChaosDashboardMetricsCollector) ginMetricsCollector() gin.HandlerFunc { + return func(ctx *gin.Context) { + begin := time.Now() + + ctx.Next() + + collector.httpRequestDuration.WithLabelValues(ctx.FullPath(), ctx.Request.Method, strconv.Itoa(ctx.Writer.Status())). + Observe(time.Since(begin).Seconds()) + } +} diff --git a/pkg/metrics/utils/ipset.go b/pkg/metrics/utils/ipset.go new file mode 100644 index 0000000000..4e6eaad520 --- /dev/null +++ b/pkg/metrics/utils/ipset.go @@ -0,0 +1,52 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package utils + +import ( + "context" + "encoding/xml" + + "github.com/romana/ipset" + + "github.com/chaos-mesh/chaos-mesh/pkg/bpm" +) + +func GetIPSetRulesNumberByNetNS(pid uint32) (int, error) { + return getIPSetRulesNumber(true, pid) +} + +func getIPSetRulesNumber(enterNS bool, pid uint32) (int, error) { + builder := bpm.DefaultProcessBuilder("ipset", "save", "-o", "xml") + if enterNS { + builder = builder.SetNS(pid, bpm.NetNS) + } + + out, err := builder.Build(context.TODO()).CombinedOutput() + if err != nil { + return 0, err + } + + var sets ipset.Ipset + if err = xml.Unmarshal(out, &sets); err != nil { + return 0, err + } + + var members int + for _, set := range sets.Sets { + members += len(set.Members) + } + return members, nil +} diff --git a/pkg/metrics/utils/iptables.go b/pkg/metrics/utils/iptables.go new file mode 100644 index 0000000000..04a0a5efe4 --- /dev/null +++ b/pkg/metrics/utils/iptables.go @@ -0,0 +1,43 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package utils + +import ( + "bytes" + "context" + + "github.com/retailnext/iptables_exporter/iptables" + + "github.com/chaos-mesh/chaos-mesh/pkg/bpm" +) + +func GetIptablesContentByNetNS(pid uint32) (tables iptables.Tables, err error) { + return getIptablesContent(true, pid) +} + +func getIptablesContent(enterNS bool, pid uint32) (tables iptables.Tables, err error) { + builder := bpm.DefaultProcessBuilder("iptables-save", "-c") + if enterNS { + builder = builder.SetNS(pid, bpm.NetNS) + } + + out, err := builder.Build(context.TODO()).CombinedOutput() + if err != nil { + return nil, err + } + + return iptables.ParseIptablesSave(bytes.NewReader(out)) +} diff --git a/pkg/metrics/utils/tc.go b/pkg/metrics/utils/tc.go new file mode 100644 index 0000000000..52a60978e6 --- /dev/null +++ b/pkg/metrics/utils/tc.go @@ -0,0 +1,49 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package utils + +import ( + "bufio" + "bytes" + "context" + + "github.com/chaos-mesh/chaos-mesh/pkg/bpm" +) + +func GetTcRulesNumberByNetNS(pid uint32) (int, error) { + return getTcRulesNumber(true, pid) +} + +func getTcRulesNumber(enterNS bool, pid uint32) (int, error) { + builder := bpm.DefaultProcessBuilder("tc", "qdisc") + if enterNS { + builder = builder.SetNS(pid, bpm.NetNS) + } + + out, err := builder.Build(context.TODO()).CombinedOutput() + if err != nil { + return 0, err + } + + var lines int + scanner := bufio.NewScanner(bytes.NewReader(out)) + scanner.Split(bufio.ScanLines) + for scanner.Scan() { + lines++ + } + + return lines, nil +} diff --git a/pkg/mock/mock.go b/pkg/mock/mock.go index f69243fb9e..5721dbd3b3 100755 --- a/pkg/mock/mock.go +++ b/pkg/mock/mock.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package mock diff --git a/pkg/netem/convert.go b/pkg/netem/convert.go index b36d549a0a..2a391b4000 100644 --- a/pkg/netem/convert.go +++ b/pkg/netem/convert.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package netem @@ -116,20 +118,21 @@ func FromCorrupt(in *v1alpha1.CorruptSpec) (*chaosdaemonpb.Netem, error) { }, nil } +// FromRate convert RateSpec to netem +func FromRate(in *v1alpha1.RateSpec) (*chaosdaemonpb.Netem, error) { + return &chaosdaemonpb.Netem{ + Rate: in.Rate, + }, nil +} + // FromBandwidth converts BandwidthSpec to *chaosdaemonpb.Tbf // Bandwidth action use TBF under the hood. // TBF stands for Token Bucket Filter, is a classful queueing discipline available // for traffic control with the tc command. // http://man7.org/linux/man-pages/man8/tc-tbf.8.html func FromBandwidth(in *v1alpha1.BandwidthSpec) (*chaosdaemonpb.Tbf, error) { - rate, err := v1alpha1.ConvertUnitToBytes(in.Rate) - - if err != nil { - return nil, err - } - tbf := &chaosdaemonpb.Tbf{ - Rate: rate, + Rate: in.Rate, Limit: in.Limit, Buffer: in.Buffer, } diff --git a/pkg/pidfile/pidfile.go b/pkg/pidfile/pidfile.go index e3712a2d69..832f025bcb 100644 --- a/pkg/pidfile/pidfile.go +++ b/pkg/pidfile/pidfile.go @@ -1,15 +1,17 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// // Package pidfile provides structure and helper functions to create and remove // PID file. A PID file is usually a file used to store the process ID of a @@ -21,11 +23,12 @@ package pidfile import ( "fmt" - "io/ioutil" "os" "path/filepath" "strconv" "strings" + + "github.com/pkg/errors" ) // PIDFile is a file used to store the process ID of a running process. @@ -41,11 +44,11 @@ func processExists(pid int) bool { } func checkPIDFileAlreadyExists(path string) error { - if pidByte, err := ioutil.ReadFile(path); err == nil { + if pidByte, err := os.ReadFile(path); err == nil { pidString := strings.TrimSpace(string(pidByte)) if pid, err := strconv.Atoi(pidString); err == nil { if processExists(pid) { - return fmt.Errorf("pid file found, ensure docker is not running or delete %s", path) + return errors.Errorf("pid file found, ensure docker is not running or delete %s", path) } } } @@ -61,7 +64,7 @@ func New(path string) (*PIDFile, error) { if err := os.MkdirAll(filepath.Dir(path), os.FileMode(0755)); err != nil { return nil, err } - if err := ioutil.WriteFile(path, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil { + if err := os.WriteFile(path, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil { return nil, err } diff --git a/pkg/portforward/portforward.go b/pkg/portforward/portforward.go index fac6531d79..58b4ca7146 100644 --- a/pkg/portforward/portforward.go +++ b/pkg/portforward/portforward.go @@ -1,28 +1,31 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package portforward import ( "bufio" "context" - "errors" "fmt" "io" "net/http" "net/url" "time" + "github.com/go-logr/logr" + "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/cli-runtime/pkg/genericclioptions" @@ -32,7 +35,6 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/tools/portforward" "k8s.io/client-go/transport/spdy" - "k8s.io/klog" "k8s.io/kubectl/pkg/polymorphichelpers" ) @@ -53,6 +55,7 @@ type portForwarder struct { config *rest.Config client kubernetes.Interface enableLog bool + logger logr.Logger } var _ PortForward = &portForwarder{} @@ -68,6 +71,7 @@ func (f *portForwarder) forwardPorts(podKey, method string, url *url.URL, addres readyChan := make(chan struct{}) fw, err := portforward.NewOnAddresses(dialer, addresses, ports, ctx.Done(), readyChan, w, w) if err != nil { + cancel() return nil, nil, err } @@ -82,13 +86,13 @@ func (f *portForwarder) forwardPorts(podKey, method string, url *url.URL, addres lineScanner := bufio.NewScanner(r) for lineScanner.Scan() { if f.enableLog { - klog.Infof("log from port forwarding %q: %s", podKey, lineScanner.Text()) + f.logger.Info(fmt.Sprintf("log from port forwarding %q: %s", podKey, lineScanner.Text())) } } }() // run port forwarding - errChan := make(chan error) + errChan := make(chan error, 1) go func() { errChan <- fw.ForwardPorts() }() @@ -130,7 +134,8 @@ func (f *portForwarder) Forward(namespace, resourceName string, addresses []stri return nil, nil, err } - pod, err := f.client.CoreV1().Pods(namespace).Get(forwardablePod.Name, metav1.GetOptions{}) + // FIXME: get context from parameter + pod, err := f.client.CoreV1().Pods(namespace).Get(context.TODO(), forwardablePod.Name, metav1.GetOptions{}) if err != nil { return nil, nil, err } @@ -140,7 +145,7 @@ func (f *portForwarder) Forward(namespace, resourceName string, addresses []stri // ForwardPod would port-forward target Pod func (f *portForwarder) ForwardPod(pod *corev1.Pod, addresses []string, ports []string) (forwardedPorts []portforward.ForwardedPort, cancel context.CancelFunc, err error) { if pod.Status.Phase != corev1.PodRunning { - return nil, nil, fmt.Errorf("unable to forward port because pod is not running. Current status=%v", pod.Status.Phase) + return nil, nil, errors.Errorf("unable to forward port because pod is not running. Current status=%v", pod.Status.Phase) } req := f.client.CoreV1().RESTClient().Post(). @@ -153,7 +158,7 @@ func (f *portForwarder) ForwardPod(pod *corev1.Pod, addresses []string, ports [] } // NewPortForwarder would create a new port-forward -func NewPortForwarder(ctx context.Context, restClientGetter genericclioptions.RESTClientGetter, enableLog bool) (PortForward, error) { +func NewPortForwarder(ctx context.Context, restClientGetter genericclioptions.RESTClientGetter, enableLog bool, logger logr.Logger) (PortForward, error) { config, err := restClientGetter.ToRESTConfig() if err != nil { return nil, err @@ -168,6 +173,7 @@ func NewPortForwarder(ctx context.Context, restClientGetter genericclioptions.RE config: config, client: client, enableLog: enableLog, + logger: logger, } return f, nil } diff --git a/pkg/ptrace/cwrapper_linux.go b/pkg/ptrace/cwrapper_linux.go index 1b76e31435..d6db9b3a39 100644 --- a/pkg/ptrace/cwrapper_linux.go +++ b/pkg/ptrace/cwrapper_linux.go @@ -1,15 +1,18 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// +//go:build cgo package ptrace diff --git a/pkg/ptrace/ptrace_linux.go b/pkg/ptrace/ptrace_linux.go new file mode 100644 index 0000000000..45d8ad6ea5 --- /dev/null +++ b/pkg/ptrace/ptrace_linux.go @@ -0,0 +1,415 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//go:build cgo + +package ptrace + +/* +#include +struct iovec { + intptr_t iov_base; + size_t iov_len; +}; +*/ +import "C" + +import ( + "bytes" + "debug/elf" + "fmt" + "os" + "strconv" + "strings" + "syscall" + "unsafe" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/pkg/mapreader" +) + +const waitPidErrorMessage = "waitpid ret value: %d" + +// If it's on 64-bit platform, `^uintptr(0)` will get a 64-bit number full of one. +// After shifting right for 63-bit, only 1 will be left. Than we got 8 here. +// If it's on 32-bit platform, After shifting nothing will be left. Than we got 4 here. +const ptrSize = 4 << uintptr(^uintptr(0)>>63) + +var threadRetryLimit = 10 + +// TracedProgram is a program traced by ptrace +type TracedProgram struct { + pid int + tids []int + Entries []mapreader.Entry + + backupRegs *syscall.PtraceRegs + backupCode []byte + + logger logr.Logger +} + +// Pid return the pid of traced program +func (p *TracedProgram) Pid() int { + return p.pid +} + +func waitPid(pid int) error { + ret := waitpid(pid) + if ret == pid { + return nil + } + + return errors.Errorf(waitPidErrorMessage, ret) +} + +// Trace ptrace all threads of a process +func Trace(pid int, logger logr.Logger) (*TracedProgram, error) { + traceSuccess := false + + tidMap := make(map[int]bool) + retryCount := make(map[int]int) + + // iterate over the thread group, until it doens't change + // + // we have tried several ways to ensure that we have stopped all the tasks: + // 1. iterating over and over again to make sure all of them are tracee + // 2. send `SIGSTOP` signal + // ... + // only the first way finally worked for every situations + for { + threads, err := os.ReadDir(fmt.Sprintf("/proc/%d/task", pid)) + if err != nil { + return nil, errors.WithStack(err) + } + + // judge whether `threads` is a subset of `tidMap` + subset := true + + tids := make(map[int]bool) + for _, thread := range threads { + tid64, err := strconv.ParseInt(thread.Name(), 10, 32) + if err != nil { + return nil, errors.WithStack(err) + } + tid := int(tid64) + + _, ok := tidMap[tid] + if ok { + tids[tid] = true + continue + } + subset = false + + err = syscall.PtraceAttach(tid) + if err != nil { + _, ok := retryCount[tid] + if !ok { + retryCount[tid] = 1 + } else { + retryCount[tid]++ + } + if retryCount[tid] < threadRetryLimit { + logger.Info("retry attaching thread", "tid", tid, "retryCount", retryCount[tid], "limit", threadRetryLimit) + continue + } + + if !strings.Contains(err.Error(), "no such process") { + return nil, errors.WithStack(err) + } + continue + } + defer func() { + if !traceSuccess { + err = syscall.PtraceDetach(tid) + if err != nil { + if !strings.Contains(err.Error(), "no such process") { + logger.Error(err, "detach failed", "tid", tid) + } + } + } + }() + + err = waitPid(tid) + if err != nil { + return nil, errors.WithStack(err) + } + + logger.Info("attach successfully", "tid", tid) + tids[tid] = true + tidMap[tid] = true + } + + if subset { + tidMap = tids + break + } + } + + var tids []int + for key := range tidMap { + tids = append(tids, key) + } + + entries, err := mapreader.Read(pid) + if err != nil { + return nil, err + } + + program := &TracedProgram{ + pid: pid, + tids: tids, + Entries: entries, + backupRegs: &syscall.PtraceRegs{}, + backupCode: make([]byte, syscallInstrSize), + logger: logger, + } + + traceSuccess = true + + return program, nil +} + +// Detach detaches from all threads of the processes +func (p *TracedProgram) Detach() error { + for _, tid := range p.tids { + p.logger.Info("detaching", "tid", tid) + + err := syscall.PtraceDetach(tid) + + if err != nil { + if !strings.Contains(err.Error(), "no such process") { + return errors.WithStack(err) + } + } + } + + p.logger.Info("Successfully detach and rerun process", "pid", p.pid) + return nil +} + +// Protect will backup regs and rip into fields +func (p *TracedProgram) Protect() error { + err := getRegs(p.pid, p.backupRegs) + if err != nil { + return errors.WithStack(err) + } + + _, err = syscall.PtracePeekData(p.pid, getIp(p.backupRegs), p.backupCode) + if err != nil { + return errors.WithStack(err) + } + + return nil +} + +// Restore will restore regs and rip from fields +func (p *TracedProgram) Restore() error { + err := setRegs(p.pid, p.backupRegs) + if err != nil { + return errors.WithStack(err) + } + + _, err = syscall.PtracePokeData(p.pid, getIp(p.backupRegs), p.backupCode) + if err != nil { + return errors.WithStack(err) + } + + return nil +} + +// Wait waits until the process stops +func (p *TracedProgram) Wait() error { + return waitPid(p.pid) +} + +// Step moves one step forward +func (p *TracedProgram) Step() error { + err := syscall.PtraceSingleStep(p.pid) + if err != nil { + return errors.WithStack(err) + } + + return p.Wait() +} + +// Mmap runs mmap syscall +func (p *TracedProgram) Mmap(length uint64, fd uint64) (uint64, error) { + return p.Syscall(syscall.SYS_MMAP, 0, length, syscall.PROT_READ|syscall.PROT_WRITE|syscall.PROT_EXEC, syscall.MAP_ANON|syscall.MAP_PRIVATE, fd, 0) +} + +// ReadSlice reads from addr and return a slice +func (p *TracedProgram) ReadSlice(addr uint64, size uint64) (*[]byte, error) { + buffer := make([]byte, size) + + localIov := C.struct_iovec{ + iov_base: C.long(uintptr(unsafe.Pointer(&buffer[0]))), + iov_len: C.ulong(size), + } + + remoteIov := C.struct_iovec{ + iov_base: C.long(addr), + iov_len: C.ulong(size), + } + + _, _, errno := syscall.Syscall6(nrProcessVMReadv, uintptr(p.pid), uintptr(unsafe.Pointer(&localIov)), uintptr(1), uintptr(unsafe.Pointer(&remoteIov)), uintptr(1), uintptr(0)) + if errno != 0 { + return nil, errors.WithStack(errno) + } + // TODO: check size and warn + + return &buffer, nil +} + +// WriteSlice writes a buffer into addr +func (p *TracedProgram) WriteSlice(addr uint64, buffer []byte) error { + size := len(buffer) + + localIov := C.struct_iovec{ + iov_base: C.long(uintptr(unsafe.Pointer(&buffer[0]))), + iov_len: C.ulong(size), + } + + remoteIov := C.struct_iovec{ + iov_base: C.long(addr), + iov_len: C.ulong(size), + } + + _, _, errno := syscall.Syscall6(nrProcessVMWritev, uintptr(p.pid), uintptr(unsafe.Pointer(&localIov)), uintptr(1), uintptr(unsafe.Pointer(&remoteIov)), uintptr(1), uintptr(0)) + if errno != 0 { + return errors.WithStack(errno) + } + // TODO: check size and warn + + return nil +} + +func alignBuffer(buffer []byte) []byte { + if buffer == nil { + return nil + } + + alignedSize := (len(buffer) / ptrSize) * ptrSize + if alignedSize < len(buffer) { + alignedSize += ptrSize + } + clonedBuffer := make([]byte, alignedSize) + copy(clonedBuffer, buffer) + + return clonedBuffer +} + +// PtraceWriteSlice uses ptrace rather than process_vm_write to write a buffer into addr +func (p *TracedProgram) PtraceWriteSlice(addr uint64, buffer []byte) error { + wroteSize := 0 + + buffer = alignBuffer(buffer) + + for wroteSize+ptrSize <= len(buffer) { + addr := uintptr(addr + uint64(wroteSize)) + data := buffer[wroteSize : wroteSize+ptrSize] + + _, err := syscall.PtracePokeData(p.pid, addr, data) + if err != nil { + err = errors.WithStack(err) + return errors.WithMessagef(err, "write to addr %x with %+v failed", addr, data) + } + + wroteSize += ptrSize + } + + return nil +} + +// GetLibBuffer reads an entry +func (p *TracedProgram) GetLibBuffer(entry *mapreader.Entry) (*[]byte, error) { + if entry.PaddingSize > 0 { + return nil, errors.New("entry with padding size is not supported") + } + + size := entry.EndAddress - entry.StartAddress + + return p.ReadSlice(entry.StartAddress, size) +} + +// MmapSlice mmaps a slice and return it's addr +func (p *TracedProgram) MmapSlice(slice []byte) (*mapreader.Entry, error) { + size := uint64(len(slice)) + + addr, err := p.Mmap(size, 0) + if err != nil { + return nil, errors.WithStack(err) + } + + err = p.WriteSlice(addr, slice) + if err != nil { + return nil, errors.WithStack(err) + } + + return &mapreader.Entry{ + StartAddress: addr, + EndAddress: addr + size, + Privilege: "rwxp", + PaddingSize: 0, + Path: "", + }, nil +} + +// FindSymbolInEntry finds symbol in entry through parsing elf +func (p *TracedProgram) FindSymbolInEntry(symbolName string, entry *mapreader.Entry) (uint64, uint64, error) { + libBuffer, err := p.GetLibBuffer(entry) + if err != nil { + return 0, 0, err + } + + reader := bytes.NewReader(*libBuffer) + vdsoElf, err := elf.NewFile(reader) + if err != nil { + return 0, 0, errors.WithStack(err) + } + + loadOffset := uint64(0) + + for _, prog := range vdsoElf.Progs { + if prog.Type == elf.PT_LOAD { + loadOffset = prog.Vaddr - prog.Off + + // break here is enough for vdso + break + } + } + + symbols, err := vdsoElf.DynamicSymbols() + if err != nil { + return 0, 0, errors.WithStack(err) + } + for _, symbol := range symbols { + if strings.Contains(symbol.Name, symbolName) { + offset := symbol.Value + + return entry.StartAddress + (offset - loadOffset), symbol.Size, nil + } + } + return 0, 0, errors.New("cannot find symbol") +} + +// WriteUint64ToAddr writes uint64 to addr +func (p *TracedProgram) WriteUint64ToAddr(addr uint64, value uint64) error { + valueSlice := make([]byte, 8) + endian.PutUint64(valueSlice, value) + err := p.WriteSlice(addr, valueSlice) + return err +} diff --git a/pkg/ptrace/ptrace_linux_amd64.go b/pkg/ptrace/ptrace_linux_amd64.go index 73a89fd537..56d508b37c 100644 --- a/pkg/ptrace/ptrace_linux_amd64.go +++ b/pkg/ptrace/ptrace_linux_amd64.go @@ -1,252 +1,60 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// +//go:build cgo package ptrace -/* -#include -struct iovec { - intptr_t iov_base; - size_t iov_len; -}; -*/ -import "C" - import ( - "bytes" - "debug/elf" "encoding/binary" - "fmt" - "io/ioutil" - "strconv" - "strings" "syscall" - "unsafe" - - "github.com/go-logr/logr" - ctrl "sigs.k8s.io/controller-runtime" "github.com/pkg/errors" - - "github.com/chaos-mesh/chaos-mesh/pkg/mapreader" ) -var log = ctrl.Log.WithName("ptrace") - -// RegisterLogger registers a logger on ptrace pkg -func RegisterLogger(logger logr.Logger) { - log = logger -} - -const waitPidErrorMessage = "waitpid ret value: %d" - -// If it's on 64-bit platform, `^uintptr(0)` will get a 64-bit number full of one. -// After shifting right for 63-bit, only 1 will be left. Than we got 8 here. -// If it's on 32-bit platform, After shifting nothing will be left. Than we got 4 here. -const ptrSize = 4 << uintptr(^uintptr(0)>>63) - -var threadRetryLimit = 10 - -// TracedProgram is a program traced by ptrace -type TracedProgram struct { - pid int - tids []int - Entries []mapreader.Entry - - backupRegs *syscall.PtraceRegs - backupCode []byte -} - -// Pid return the pid of traced program -func (p *TracedProgram) Pid() int { - return p.pid -} - -func waitPid(pid int) error { - ret := waitpid(pid) - if ret == pid { - return nil - } - - return errors.Errorf(waitPidErrorMessage, ret) -} - -// Trace ptrace all threads of a process -func Trace(pid int) (*TracedProgram, error) { - traceSuccess := false - - tidMap := make(map[int]bool) - retryCount := make(map[int]int) - for { - threads, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/task", pid)) - if err != nil { - log.Error(err, "read failed", "pid", pid) - return nil, errors.WithStack(err) - } - - // judge whether `threads` is a subset of `tidMap` - subset := true - - tids := make(map[int]bool) - for _, thread := range threads { - tid64, err := strconv.ParseInt(thread.Name(), 10, 32) - if err != nil { - return nil, errors.WithStack(err) - } - tid := int(tid64) - - _, ok := tidMap[tid] - if ok { - tids[tid] = true - continue - } - subset = false - - err = syscall.PtraceAttach(tid) - if err != nil { - _, ok := retryCount[tid] - if !ok { - retryCount[tid] = 1 - } else { - retryCount[tid]++ - } - if retryCount[tid] < threadRetryLimit { - log.Info("retry attaching thread", "tid", tid, "retryCount", retryCount[tid], "limit", threadRetryLimit) - continue - } - - if !strings.Contains(err.Error(), "no such process") { - log.Error(err, "attach failed", "tid", tid) - return nil, errors.WithStack(err) - } - continue - } - defer func() { - if !traceSuccess { - err = syscall.PtraceDetach(tid) - if err != nil { - if !strings.Contains(err.Error(), "no such process") { - log.Error(err, "detach failed", "tid", tid) - } - } - } - }() - - err = waitPid(tid) - if err != nil { - return nil, errors.WithStack(err) - } - - log.Info("attach successfully", "tid", tid) - tids[tid] = true - tidMap[tid] = true - } - - if subset { - tidMap = tids - break - } - } - - var tids []int - for key := range tidMap { - tids = append(tids, key) - } - - entries, err := mapreader.Read(pid) - if err != nil { - return nil, err - } +var endian = binary.LittleEndian - program := &TracedProgram{ - pid: pid, - tids: tids, - Entries: entries, - backupRegs: &syscall.PtraceRegs{}, - backupCode: make([]byte, ptrSize), - } +const syscallInstrSize = 2 - traceSuccess = true +const nrProcessVMReadv = 310 +const nrProcessVMWritev = 311 - return program, nil +func getIp(regs *syscall.PtraceRegs) uintptr { + return uintptr(regs.Rip) } -// Detach detaches from all threads of the processes -func (p *TracedProgram) Detach() error { - for _, tid := range p.tids { - log.Info("detaching", "tid", tid) - - err := syscall.PtraceDetach(tid) - - if err != nil { - if !strings.Contains(err.Error(), "no such process") { - log.Error(err, "detach failed", "tid", tid) - return errors.WithStack(err) - } - } - } - - log.Info("Successfully detach and rerun process", "pid", p.pid) - return nil -} - -// Protect will backup regs and rip into fields -func (p *TracedProgram) Protect() error { - err := syscall.PtraceGetRegs(p.pid, p.backupRegs) - if err != nil { - return errors.WithStack(err) - } - - _, err = syscall.PtracePeekData(p.pid, uintptr(p.backupRegs.Rip), p.backupCode) +func getRegs(pid int, regsout *syscall.PtraceRegs) error { + err := syscall.PtraceGetRegs(pid, regsout) if err != nil { - return errors.WithStack(err) + return errors.Wrapf(err, "get registers of process %d", pid) } return nil } -// Restore will restore regs and rip from fields -func (p *TracedProgram) Restore() error { - err := syscall.PtraceSetRegs(p.pid, p.backupRegs) - if err != nil { - return errors.WithStack(err) - } - - _, err = syscall.PtracePokeData(p.pid, uintptr(p.backupRegs.Rip), p.backupCode) +func setRegs(pid int, regs *syscall.PtraceRegs) error { + err := syscall.PtraceSetRegs(pid, regs) if err != nil { - return errors.WithStack(err) + return errors.Wrapf(err, "set registers of process %d", pid) } return nil } -// Wait waits until the process stops -func (p *TracedProgram) Wait() error { - return waitPid(p.pid) -} - -// Step moves one step forward -func (p *TracedProgram) Step() error { - err := syscall.PtraceSingleStep(p.pid) - if err != nil { - return errors.WithStack(err) - } - - return p.Wait() -} - // Syscall runs a syscall at main thread of process func (p *TracedProgram) Syscall(number uint64, args ...uint64) (uint64, error) { + // save the original registers and the current instructions err := p.Protect() if err != nil { return 0, err @@ -254,10 +62,14 @@ func (p *TracedProgram) Syscall(number uint64, args ...uint64) (uint64, error) { var regs syscall.PtraceRegs - err = syscall.PtraceGetRegs(p.pid, ®s) + err = getRegs(p.pid, ®s) if err != nil { return 0, err } + // set the registers according to the syscall convention. Learn more about + // it in `man 2 syscall`. In x86_64 the syscall nr is stored in rax + // register, and the arguments are stored in rdi, rsi, rdx, r10, r8, r9 in + // order regs.Rax = number for index, arg := range args { // All these registers are hard coded for x86 platform @@ -274,210 +86,41 @@ func (p *TracedProgram) Syscall(number uint64, args ...uint64) (uint64, error) { } else if index == 5 { regs.R9 = arg } else { - return 0, fmt.Errorf("too many arguments for a syscall") + return 0, errors.New("too many arguments for a syscall") } } - err = syscall.PtraceSetRegs(p.pid, ®s) + err = setRegs(p.pid, ®s) if err != nil { return 0, err } - ip := make([]byte, ptrSize) + instruction := make([]byte, syscallInstrSize) + ip := getIp(p.backupRegs) - // We only support x86-64 platform now, so using hard coded `LittleEndian` here is ok. - binary.LittleEndian.PutUint16(ip, 0x050f) - _, err = syscall.PtracePokeData(p.pid, uintptr(p.backupRegs.Rip), ip) + // set the current instruction (the ip register points to) to the `syscall` + // instruction. In x86_64, the `syscall` instruction is 0x050f. + binary.LittleEndian.PutUint16(instruction, 0x050f) + _, err = syscall.PtracePokeData(p.pid, ip, instruction) if err != nil { - return 0, err + return 0, errors.Wrapf(err, "writing data %v to %x", instruction, ip) } + // run one instruction, and stop err = p.Step() if err != nil { return 0, err } - err = syscall.PtraceGetRegs(p.pid, ®s) + // read registers, the return value of syscall is stored inside rax register + err = getRegs(p.pid, ®s) if err != nil { return 0, err } + // restore the state saved at beginning. return regs.Rax, p.Restore() } -// Mmap runs mmap syscall -func (p *TracedProgram) Mmap(length uint64, fd uint64) (uint64, error) { - return p.Syscall(syscall.SYS_MMAP, 0, length, syscall.PROT_READ|syscall.PROT_WRITE|syscall.PROT_EXEC, syscall.MAP_ANON|syscall.MAP_PRIVATE, fd, 0) -} - -// ReadSlice reads from addr and return a slice -func (p *TracedProgram) ReadSlice(addr uint64, size uint64) (*[]byte, error) { - buffer := make([]byte, size) - - localIov := C.struct_iovec{ - iov_base: C.long(uintptr(unsafe.Pointer(&buffer[0]))), - iov_len: C.ulong(size), - } - - remoteIov := C.struct_iovec{ - iov_base: C.long(addr), - iov_len: C.ulong(size), - } - - // process_vm_readv syscall number is 310 - _, _, errno := syscall.Syscall6(310, uintptr(p.pid), uintptr(unsafe.Pointer(&localIov)), uintptr(1), uintptr(unsafe.Pointer(&remoteIov)), uintptr(1), uintptr(0)) - if errno != 0 { - return nil, errors.WithStack(errno) - } - // TODO: check size and warn - - return &buffer, nil -} - -// WriteSlice writes a buffer into addr -func (p *TracedProgram) WriteSlice(addr uint64, buffer []byte) error { - size := len(buffer) - - localIov := C.struct_iovec{ - iov_base: C.long(uintptr(unsafe.Pointer(&buffer[0]))), - iov_len: C.ulong(size), - } - - remoteIov := C.struct_iovec{ - iov_base: C.long(addr), - iov_len: C.ulong(size), - } - - // process_vm_writev syscall number is 311 - _, _, errno := syscall.Syscall6(311, uintptr(p.pid), uintptr(unsafe.Pointer(&localIov)), uintptr(1), uintptr(unsafe.Pointer(&remoteIov)), uintptr(1), uintptr(0)) - if errno != 0 { - return errors.WithStack(errno) - } - // TODO: check size and warn - - return nil -} - -func alignBuffer(buffer []byte) []byte { - if buffer == nil { - return nil - } - - alignedSize := (len(buffer) / ptrSize) * ptrSize - if alignedSize < len(buffer) { - alignedSize += ptrSize - } - clonedBuffer := make([]byte, alignedSize) - copy(clonedBuffer, buffer) - - return clonedBuffer -} - -// PtraceWriteSlice uses ptrace rather than process_vm_write to write a buffer into addr -func (p *TracedProgram) PtraceWriteSlice(addr uint64, buffer []byte) error { - wroteSize := 0 - - buffer = alignBuffer(buffer) - - for wroteSize+ptrSize <= len(buffer) { - addr := uintptr(addr + uint64(wroteSize)) - data := buffer[wroteSize : wroteSize+ptrSize] - - _, err := syscall.PtracePokeData(p.pid, addr, data) - if err != nil { - err = errors.WithStack(err) - return errors.WithMessagef(err, "write to addr %x with %+v failed", addr, data) - } - - wroteSize += ptrSize - } - - return nil -} - -// GetLibBuffer reads an entry -func (p *TracedProgram) GetLibBuffer(entry *mapreader.Entry) (*[]byte, error) { - if entry.PaddingSize > 0 { - return nil, fmt.Errorf("entry with padding size is not supported") - } - - size := entry.EndAddress - entry.StartAddress - - return p.ReadSlice(entry.StartAddress, size) -} - -// MmapSlice mmaps a slice and return it's addr -func (p *TracedProgram) MmapSlice(slice []byte) (*mapreader.Entry, error) { - size := uint64(len(slice)) - - addr, err := p.Mmap(size, 0) - if err != nil { - return nil, errors.WithStack(err) - } - - err = p.WriteSlice(addr, slice) - if err != nil { - return nil, errors.WithStack(err) - } - - return &mapreader.Entry{ - StartAddress: addr, - EndAddress: addr + size, - Privilege: "rwxp", - PaddingSize: 0, - Path: "", - }, nil -} - -// FindSymbolInEntry finds symbol in entry through parsing elf -func (p *TracedProgram) FindSymbolInEntry(symbolName string, entry *mapreader.Entry) (uint64, error) { - libBuffer, err := p.GetLibBuffer(entry) - if err != nil { - return 0, err - } - - reader := bytes.NewReader(*libBuffer) - vdsoElf, err := elf.NewFile(reader) - if err != nil { - return 0, errors.WithStack(err) - } - - loadOffset := uint64(0) - - for _, prog := range vdsoElf.Progs { - if prog.Type == elf.PT_LOAD { - loadOffset = prog.Vaddr - prog.Off - - // break here is enough for vdso - break - } - } - - symbols, err := vdsoElf.DynamicSymbols() - if err != nil { - return 0, errors.WithStack(err) - } - for _, symbol := range symbols { - if symbol.Name == symbolName { - offset := symbol.Value - - return entry.StartAddress + (offset - loadOffset), nil - } - } - return 0, fmt.Errorf("cannot find symbol") -} - -// WriteUint64ToAddr writes uint64 to addr -func (p *TracedProgram) WriteUint64ToAddr(addr uint64, value uint64) error { - valueSlice := make([]byte, 8) - binary.LittleEndian.PutUint64(valueSlice, value) - err := p.WriteSlice(addr, valueSlice) - if err != nil { - return err - } - - return nil -} - // JumpToFakeFunc writes jmp instruction to jump to fake function func (p *TracedProgram) JumpToFakeFunc(originAddr uint64, targetAddr uint64) error { instructions := make([]byte, 16) @@ -486,7 +129,7 @@ func (p *TracedProgram) JumpToFakeFunc(originAddr uint64, targetAddr uint64) err // jmp rax ; instructions[0] = 0x48 instructions[1] = 0xb8 - binary.LittleEndian.PutUint64(instructions[2:10], targetAddr) + endian.PutUint64(instructions[2:10], targetAddr) instructions[10] = 0xff instructions[11] = 0xe0 diff --git a/pkg/ptrace/ptrace_linux_arm64.go b/pkg/ptrace/ptrace_linux_arm64.go new file mode 100644 index 0000000000..ab7d49e80a --- /dev/null +++ b/pkg/ptrace/ptrace_linux_arm64.go @@ -0,0 +1,127 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//go:build cgo + +package ptrace + +import ( + "encoding/binary" + "syscall" + + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +var endian = binary.LittleEndian + +const syscallInstrSize = 4 + +const nrProcessVMReadv = 270 +const nrProcessVMWritev = 271 + +// see kernel source /include/uapi/linux/elf.h +const nrPRStatus = 1 + +func getIp(regs *syscall.PtraceRegs) uintptr { + return uintptr(regs.Pc) +} + +func getRegs(pid int, regsout *syscall.PtraceRegs) error { + err := unix.PtraceGetRegSetArm64(pid, nrPRStatus, (*unix.PtraceRegsArm64)(regsout)) + if err != nil { + return errors.Wrapf(err, "get registers of process %d", pid) + } + return nil +} + +func setRegs(pid int, regs *syscall.PtraceRegs) error { + err := unix.PtraceSetRegSetArm64(pid, nrPRStatus, (*unix.PtraceRegsArm64)(regs)) + if err != nil { + return errors.Wrapf(err, "set registers of process %d", pid) + } + return nil +} + +// Syscall runs a syscall at main thread of process +func (p *TracedProgram) Syscall(number uint64, args ...uint64) (uint64, error) { + // save the original registers and the current instructions + err := p.Protect() + if err != nil { + return 0, err + } + + var regs syscall.PtraceRegs + + err = getRegs(p.pid, ®s) + if err != nil { + return 0, err + } + // set the registers according to the syscall convention. Learn more about + // it in `man 2 syscall`. In aarch64 the syscall nr is stored in w8, and the + // arguments are stored in x0, x1, x2, x3, x4, x5 in order + regs.Regs[8] = number + for index, arg := range args { + // All these registers are hard coded for x86 platform + if index > 6 { + return 0, errors.New("too many arguments for a syscall") + } else { + regs.Regs[index] = arg + } + } + err = setRegs(p.pid, ®s) + if err != nil { + return 0, err + } + + instruction := make([]byte, syscallInstrSize) + ip := getIp(p.backupRegs) + + // most aarch64 devices are little endian + // 0xd4000001 is `svc #0` to call the system call + endian.PutUint32(instruction, 0xd4000001) + _, err = syscall.PtracePokeData(p.pid, ip, instruction) + if err != nil { + return 0, errors.Wrapf(err, "writing data %v to %x", instruction, ip) + } + + // run one instruction, and stop + err = p.Step() + if err != nil { + return 0, err + } + + // read registers, the return value of syscall is stored inside x0 register + err = getRegs(p.pid, ®s) + if err != nil { + return 0, err + } + + return regs.Regs[0], p.Restore() +} + +// JumpToFakeFunc writes jmp instruction to jump to fake function +func (p *TracedProgram) JumpToFakeFunc(originAddr uint64, targetAddr uint64) error { + instructions := make([]byte, 16) + + // LDR x9, #8 + // BR x9 + // targetAddr + endian.PutUint32(instructions[0:], 0x58000049) + endian.PutUint32(instructions[4:], 0xD61F0120) + + endian.PutUint64(instructions[8:], targetAddr) + + return p.PtraceWriteSlice(originAddr, instructions) +} diff --git a/pkg/ptrace/ptrace_linux_test.go b/pkg/ptrace/ptrace_linux_test.go index 8adcc1cbf7..91a2526f53 100644 --- a/pkg/ptrace/ptrace_linux_test.go +++ b/pkg/ptrace/ptrace_linux_test.go @@ -1,15 +1,18 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// +//go:build cgo package ptrace @@ -22,22 +25,17 @@ import ( "time" "unsafe" - "github.com/go-logr/zapr" - "go.uber.org/zap" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/chaos-mesh/chaos-mesh/pkg/log" "github.com/chaos-mesh/chaos-mesh/test/pkg/timer" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "sigs.k8s.io/controller-runtime/pkg/envtest" ) func TestPTrace(t *testing.T) { RegisterFailHandler(Fail) - RunSpecsWithDefaultAndCustomReporters(t, - "PTrace Suit", - []Reporter{envtest.NewlineReporter{}}) + RunSpecs(t, "PTrace Suit") } var _ = BeforeSuite(func(done Done) { @@ -49,10 +47,6 @@ var _ = BeforeSuite(func(done Done) { Expect(err).NotTo(HaveOccurred()) By("register logger") - zapLog, err := zap.NewDevelopment() - Expect(err).NotTo(HaveOccurred()) - log := zapr.NewLogger(zapLog) - RegisterLogger(log) close(done) }) @@ -62,6 +56,9 @@ var _ = BeforeSuite(func(done Done) { var _ = Describe("PTrace", func() { + logger, err := log.NewDefaultZapLogger() + Expect(err).NotTo(HaveOccurred()) + var t *timer.Timer var program *TracedProgram @@ -73,7 +70,7 @@ var _ = Describe("PTrace", func() { time.Sleep(time.Millisecond) - program, err = Trace(t.Pid()) + program, err = Trace(t.Pid(), logger) Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) }) @@ -99,7 +96,7 @@ var _ = Describe("PTrace", func() { }) It("double trace should get error", func() { - _, err := Trace(t.Pid()) + _, err := Trace(t.Pid(), logger) Expect(err).Should(HaveOccurred()) }) @@ -139,7 +136,7 @@ var _ = Describe("PTrace", func() { err := program.Detach() Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) - program, err = Trace(t.Pid()) + program, err = Trace(t.Pid(), logger) Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) }) @@ -151,7 +148,7 @@ var _ = Describe("PTrace", func() { time.Sleep(time.Millisecond) pid := p.Process.Pid - program, err := Trace(pid) + program, err := Trace(pid, logger) Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) err = program.Detach() diff --git a/pkg/ptrace/ptrace_nocgo.go b/pkg/ptrace/ptrace_nocgo.go new file mode 100644 index 0000000000..f0fd56b2f4 --- /dev/null +++ b/pkg/ptrace/ptrace_nocgo.go @@ -0,0 +1,118 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//go:build !cgo + +package ptrace + +import ( + "github.com/go-logr/logr" + + "github.com/chaos-mesh/chaos-mesh/pkg/mapreader" +) + +// RegisterLogger registers a logger on ptrace pkg +func RegisterLogger(logger logr.Logger) { + panic("unimplemented") +} + +// TracedProgram is a program traced by ptrace +type TracedProgram struct { + Entries []mapreader.Entry +} + +// Pid return the pid of traced program +func (p *TracedProgram) Pid() int { + panic("unimplemented") +} + +// Trace ptrace all threads of a process +func Trace(pid int) (*TracedProgram, error) { + panic("unimplemented") +} + +// Detach detaches from all threads of the processes +func (p *TracedProgram) Detach() error { + panic("unimplemented") +} + +// Protect will backup regs and rip into fields +func (p *TracedProgram) Protect() error { + panic("unimplemented") +} + +// Restore will restore regs and rip from fields +func (p *TracedProgram) Restore() error { + panic("unimplemented") +} + +// Wait waits until the process stops +func (p *TracedProgram) Wait() error { + panic("unimplemented") +} + +// Step moves one step forward +func (p *TracedProgram) Step() error { + panic("unimplemented") +} + +// Syscall runs a syscall at main thread of process +func (p *TracedProgram) Syscall(number uint64, args ...uint64) (uint64, error) { + panic("unimplemented") +} + +// Mmap runs mmap syscall +func (p *TracedProgram) Mmap(length uint64, fd uint64) (uint64, error) { + panic("unimplemented") +} + +// ReadSlice reads from addr and return a slice +func (p *TracedProgram) ReadSlice(addr uint64, size uint64) (*[]byte, error) { + panic("unimplemented") +} + +// WriteSlice writes a buffer into addr +func (p *TracedProgram) WriteSlice(addr uint64, buffer []byte) error { + panic("unimplemented") +} + +// PtraceWriteSlice uses ptrace rather than process_vm_write to write a buffer into addr +func (p *TracedProgram) PtraceWriteSlice(addr uint64, buffer []byte) error { + panic("unimplemented") +} + +// GetLibBuffer reads an entry +func (p *TracedProgram) GetLibBuffer(entry *mapreader.Entry) (*[]byte, error) { + panic("unimplemented") +} + +// MmapSlice mmaps a slice and return it's addr +func (p *TracedProgram) MmapSlice(slice []byte) (*mapreader.Entry, error) { + panic("unimplemented") +} + +// FindSymbolInEntry finds symbol in entry through parsing elf +func (p *TracedProgram) FindSymbolInEntry(symbolName string, entry *mapreader.Entry) (uint64, error) { + panic("unimplemented") +} + +// WriteUint64ToAddr writes uint64 to addr +func (p *TracedProgram) WriteUint64ToAddr(addr uint64, value uint64) error { + panic("unimplemented") +} + +// JumpToFakeFunc writes jmp instruction to jump to fake function +func (p *TracedProgram) JumpToFakeFunc(originAddr uint64, targetAddr uint64) error { + panic("unimplemented") +} diff --git a/pkg/router/context/context.go b/pkg/router/context/context.go deleted file mode 100644 index f0b6966622..0000000000 --- a/pkg/router/context/context.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package context - -import ( - "github.com/go-logr/logr" - "k8s.io/client-go/tools/record" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -// Context is the running context for a controller -type Context struct { - client.Client - client.Reader - record.EventRecorder - Log logr.Logger -} - -// LogWithValues appends values for logger in the context -func (c *Context) LogWithValues(keysAndValues ...interface{}) Context { - return Context{ - Client: c.Client, - Reader: c.Reader, - EventRecorder: c.EventRecorder, - Log: c.Log.WithValues(keysAndValues...), - } -} diff --git a/pkg/router/endpoint/endpoint.go b/pkg/router/endpoint/endpoint.go deleted file mode 100644 index ceb6341574..0000000000 --- a/pkg/router/endpoint/endpoint.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package endpoint - -import ( - "context" - - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" -) - -// Endpoint is interface for reconciler -type Endpoint interface { - // Apply means the reconciler perform the chaos action - Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error - - // Recover means the reconciler recovers the chaos action - Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error - - // Object would return the instance of chaos - Object() v1alpha1.InnerObject -} - -// NewEndpoint represents a function who creates a new reconciler -type NewEndpoint func(ctx ctx.Context) Endpoint diff --git a/pkg/router/reconciler.go b/pkg/router/reconciler.go deleted file mode 100644 index 0d22f583c3..0000000000 --- a/pkg/router/reconciler.go +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package router - -import ( - "context" - "fmt" - "strings" - - "github.com/pkg/errors" - v1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/apiutil" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/controllers/common" - "github.com/chaos-mesh/chaos-mesh/controllers/twophase" - "github.com/chaos-mesh/chaos-mesh/pkg/events" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" -) - -// Reconciler reconciles a chaos resource -type Reconciler struct { - Name string - Object runtime.Object - Endpoints []routeEndpoint - ClusterScoped bool - TargetNamespace string - - ctx.Context -} - -// Reconcile reconciles a chaos resource -func (r *Reconciler) Reconcile(req ctrl.Request) (result ctrl.Result, err error) { - if !r.ClusterScoped && req.Namespace != r.TargetNamespace { - // NOOP - r.Log.Info("ignore chaos which belongs to an unexpected namespace within namespace scoped mode", - "chaosName", req.Name, "expectedNamespace", r.TargetNamespace, "actualNamespace", req.Namespace) - return ctrl.Result{}, nil - } - - ctx := r.Context.LogWithValues("reconciler", r.Name, "resource name", req.NamespacedName) - - chaos, ok := r.Object.DeepCopyObject().(v1alpha1.InnerSchedulerObject) - if !ok { - err := errors.New("object is not InnerSchedulerObject") - r.Log.Error(err, "object is not InnerSchedulerObject", "object", r.Object.DeepCopyObject()) - return ctrl.Result{}, err - } - - if err := r.Client.Get(context.Background(), req.NamespacedName, chaos); err != nil { - if apierrors.IsNotFound(err) { - r.Log.Info("chaos not found") - } else { - r.Log.Error(err, "unable to get chaos") - } - return ctrl.Result{}, nil - } - - scheduler := chaos.GetScheduler() - duration, err := chaos.GetDuration() - if err != nil { - r.Log.Error(err, fmt.Sprintf("unable to get chaos[%s/%s]'s duration", chaos.GetChaos().Namespace, chaos.GetChaos().Name)) - return ctrl.Result{}, err - } - - var controller end.Endpoint - for _, end := range r.Endpoints { - if end.RouteFunc(chaos.(runtime.Object)) { - controller = end.NewEndpoint(ctx) - } - } - if controller == nil { - err := errors.Errorf("cannot route object to one of the endpoint") - r.Log.Error(err, "fail to route to endpoint", "object", chaos, "endpoints", r.Endpoints) - return ctrl.Result{}, err - } - - var reconciler reconcile.Reconciler - if scheduler == nil && duration == nil { - reconciler = common.NewReconciler(req, controller, ctx) - } else if scheduler != nil { - // scheduler != nil && duration != nil - // but PodKill is an exception - reconciler = twophase.NewReconciler(req, controller, ctx) - } else { - err := errors.Errorf("both scheduler and duration should be nil or not nil") - r.Log.Error(err, "fail to construct reconciler", "scheduler", scheduler, "duration", duration) - return ctrl.Result{}, err - } - - result, err = reconciler.Reconcile(req) - if err != nil { - if chaos.IsDeleted() || chaos.IsPaused() { - r.Event(chaos, v1.EventTypeWarning, events.ChaosRecoverFailed, err.Error()) - } else { - r.Event(chaos, v1.EventTypeWarning, events.ChaosInjectFailed, err.Error()) - } - } - return result, nil -} - -// NewReconciler creates a new reconciler -func NewReconciler(name string, object runtime.Object, mgr ctrl.Manager, endpoints []routeEndpoint, clusterScoped bool, targetNamespace string) *Reconciler { - return &Reconciler{ - Name: name, - Object: object, - Endpoints: endpoints, - ClusterScoped: clusterScoped, - TargetNamespace: targetNamespace, - - Context: ctx.Context{ - Client: mgr.GetClient(), - Reader: mgr.GetAPIReader(), - EventRecorder: mgr.GetEventRecorderFor(name + "-controller"), - Log: ctrl.Log.WithName("controllers").WithName(name), - }, - } -} - -// SetupWithManager registers controller to manager -func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { - err := ctrl.NewControllerManagedBy(mgr). - For(r.Object.DeepCopyObject()). - WithEventFilter(predicate.Funcs{ - UpdateFunc: func(e event.UpdateEvent) bool { - old, _ := e.ObjectOld.(v1alpha1.InnerObject).GetSpecAndMetaString() - new, _ := e.ObjectNew.(v1alpha1.InnerObject).GetSpecAndMetaString() - - return old != new - }, - }). - Complete(r) - - if err != nil { - return err - } - - kind, err := apiutil.GVKForObject(r.Object.DeepCopyObject(), mgr.GetScheme()) - if err != nil { - return err - } - - return ctrl.NewControllerManagedBy(mgr). - For(r.Object.DeepCopyObject()). - Named(strings.ToLower(kind.Kind) + "-scheduler-updater"). - WithEventFilter(predicate.Funcs{ - CreateFunc: func(_ event.CreateEvent) bool { - return false - }, - DeleteFunc: func(_ event.DeleteEvent) bool { - return false - }, - GenericFunc: func(_ event.GenericEvent) bool { - return false - }, - UpdateFunc: func(e event.UpdateEvent) bool { - old := e.ObjectOld.(v1alpha1.InnerSchedulerObject).GetScheduler() - new := e.ObjectNew.(v1alpha1.InnerSchedulerObject).GetScheduler() - - if (old == nil) || (new == nil) { - return false - } - - return old.Cron != new.Cron - }, - }). - Complete(&twophase.SchedulerUpdater{ - Context: r.Context, - Object: r.Object, - }) -} diff --git a/pkg/router/route_table.go b/pkg/router/route_table.go deleted file mode 100644 index b559a1ca54..0000000000 --- a/pkg/router/route_table.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package router - -import ( - "reflect" - - "github.com/go-logr/logr" - "github.com/pkg/errors" - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/chaos-mesh/chaos-mesh/pkg/config" - "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" -) - -type routeEntry struct { - Name string - Object runtime.Object - Endpoints []routeEndpoint -} - -func newEntry(name string, obj runtime.Object) *routeEntry { - return &routeEntry{ - Name: name, - Object: obj, - Endpoints: []routeEndpoint{}, - } -} - -type routeEndpoint struct { - RouteFunc func(runtime.Object) bool - NewEndpoint endpoint.NewEndpoint -} - -var routeTable map[reflect.Type]*routeEntry - -var log logr.Logger - -// Register registers an endpoint -func Register(name string, obj runtime.Object, routeFunc func(runtime.Object) bool, newEndpoint endpoint.NewEndpoint) { - typ := reflect.TypeOf(obj) - _, ok := routeTable[typ] - if !ok { - routeTable[typ] = newEntry(name, obj) - } - - entry := routeTable[typ] - if entry.Name != name { - err := errors.Errorf("different names for one type of resource") - log.Error(err, "different names for one type of resource", "name", name, "existingName", entry.Name) - } - - entry.Endpoints = append(entry.Endpoints, routeEndpoint{ - RouteFunc: routeFunc, - NewEndpoint: newEndpoint, - }) -} - -// SetupWithManagerAndConfigs setups reconciler with manager and controller configs -func SetupWithManagerAndConfigs(mgr ctrl.Manager, cfg *config.ChaosControllerConfig) error { - for typ, end := range routeTable { - log.Info("setup reconciler with manager", "type", typ, "endpoint", end.Name) - reconciler := NewReconciler(end.Name, end.Object, mgr, end.Endpoints, cfg.ClusterScoped, cfg.TargetNamespace) - err := reconciler.SetupWithManager(mgr) - if err != nil { - log.Error(err, "fail to setup reconciler with manager") - - return err - } - - if err := ctrl.NewWebhookManagedBy(mgr). - For(end.Object). - Complete(); err != nil { - log.Error(err, "fail to setup webhook") - return err - } - } - - return nil -} - -func init() { - routeTable = make(map[reflect.Type]*routeEntry) - log = ctrl.Log.WithName("router") -} diff --git a/pkg/router/route_table_test.go b/pkg/router/route_table_test.go deleted file mode 100644 index 707eddb73b..0000000000 --- a/pkg/router/route_table_test.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package router - -import ( - "context" - "math/rand" - "reflect" - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/envtest" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - ctx "github.com/chaos-mesh/chaos-mesh/pkg/router/context" - end "github.com/chaos-mesh/chaos-mesh/pkg/router/endpoint" -) - -func TestRouter(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "Router Suit", - []Reporter{envtest.NewlineReporter{}}) -} - -var _ = BeforeSuite(func(done Done) { - rand.Seed(GinkgoRandomSeed()) - - close(done) -}) - -type testEndpoint struct{} - -func (e *testEndpoint) Apply(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - return nil -} - -func (e *testEndpoint) Recover(ctx context.Context, req ctrl.Request, chaos v1alpha1.InnerObject) error { - return nil -} - -func (e *testEndpoint) Object() v1alpha1.InnerObject { - return &v1alpha1.NetworkChaos{} -} - -var _ = Describe("Router", func() { - It("should register successfully", func() { - Register("hello", &v1alpha1.NetworkChaos{}, func(obj runtime.Object) bool { - return true - }, func(ctx ctx.Context) end.Endpoint { - return &testEndpoint{} - }) - - Expect(len(routeTable)).To(Equal(1)) - - typ := reflect.TypeOf(&v1alpha1.NetworkChaos{}) - Expect(routeTable[typ]).NotTo(BeNil()) - }) -}) diff --git a/pkg/scheduler/scheduler.go b/pkg/scheduler/scheduler.go deleted file mode 100644 index b6cbca9d08..0000000000 --- a/pkg/scheduler/scheduler.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package scheduler - -import ( - "fmt" - "time" - - "github.com/robfig/cron/v3" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -const ( - // Set the top bit if a star was included in the expression. - starBit = 1 << 63 -) - -// LastTime returns the last time this schedule activated, less than or equal with the given time. -func LastTime(spec v1alpha1.SchedulerSpec, now time.Time) (*time.Time, error) { - scheduler, err := cron.ParseStandard(spec.Cron) - if err != nil { - return nil, fmt.Errorf("fail to parse runner rule %s, %v", spec.Cron, err) - } - var last time.Time - if cronSpec, ok := scheduler.(*cron.SpecSchedule); ok { - scheduleLast := &cusSchedule{cronSpec} - last = scheduleLast.Last(now) - } else if cronSpec, ok := scheduler.(cron.ConstantDelaySchedule); ok { - scheduleLast := &cusConstantDelaySchedule{cronSpec} - last = scheduleLast.Last(now) - } else { - return nil, fmt.Errorf("assert cron spec failed") - } - return &last, nil -} - -type cusConstantDelaySchedule struct { - cron.ConstantDelaySchedule -} - -// Last returns the last time this schedule activated, less than or equal with the given time. -// So it would always return now -func (s cusConstantDelaySchedule) Last(t time.Time) time.Time { - return t -} - -type cusSchedule struct { - *cron.SpecSchedule -} - -// Last returns the last time this schedule activated, less than or equal with the given time. -// If no time can be found to satisfy the schedule, return the zero time. -// Modified from the original `Next` function in robfig/cron at Dec 15, 2020 -func (s *cusSchedule) Last(t time.Time) time.Time { - // General approach: - // For Month, Day, Hour, Minute, Second: - // Check if the time value matches. If yes, continue to the next field. - // If the field doesn't match the schedule, then decrement the field until it matches. - // While decrementing the field, a wrap-around brings it back to the beginning - // of the field list (since it is necessary to re-verify previous field - // values) - - // Convert the given time into the schedule's timezone, if one is specified. - // Save the original timezone so we can convert back after we find a time. - // Note that schedules without a time zone specified (time.Local) are treated - // as local to the time provided. - origLocation := t.Location() - loc := s.Location - if loc == time.Local { - loc = t.Location() - } - if s.Location != time.Local { - t = t.In(s.Location) - } - - // If no time is found within five years, return zero. - yearLimit := t.Year() - 5 - -WRAP: - if t.Year() < yearLimit { - return time.Time{} - } - - // Find the first applicable month. - // If it's this month, then do nothing. - for 1< 0 - dowMatch bool = 1< 0 - ) - if s.Dom&starBit > 0 || s.Dow&starBit > 0 { - return domMatch && dowMatch - } - return domMatch || dowMatch -} diff --git a/pkg/scheduler/scheduler_test.go b/pkg/scheduler/scheduler_test.go deleted file mode 100644 index 8a9070b35f..0000000000 --- a/pkg/scheduler/scheduler_test.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package scheduler - -import ( - "strings" - "testing" - "time" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -// Modified from the original `TestNext` function in robfig/cron at Dec 15, 2020 -func TestLast(t *testing.T) { - runs := []struct { - time, spec string - expected string - }{ - // `@every` cron - {"Jul 9 14:45:00 2012", "@every 1s", "Jul 9 14:45:00 2012"}, - {"Jul 9 14:45:00 2012", "@every 1m", "Jul 9 14:45:00 2012"}, - {"Jul 9 14:45:00 2012", "@every 1h", "Jul 9 14:45:00 2012"}, - {"Jul 9 14:45:00 2012", "@every 1h1m1s", "Jul 9 14:45:00 2012"}, - - // Simple cases - {"Jul 9 14:45 2012", "0/15 * * * *", "Jul 9 14:45 2012"}, - {"Jul 9 14:59 2012", "0/15 * * * *", "Jul 9 14:45 2012"}, - {"Jul 9 14:59:59 2012", "0/15 * * * *", "Jul 9 14:45 2012"}, - - // Wrap around hours - {"Jul 9 16:15 2012", "20-35/15 * * * *", "Jul 9 15:35 2012"}, - - // Wrap around days - {"Jul 9 00:15 2012", "20-35/15 * * * *", "Jul 8 23:35 2012"}, - - // Wrap around months - {"Jul 9 23:35 2012", "0 0 10 Apr-Oct ?", "Jun 10 00:00 2012"}, - {"Jul 9 23:35 2012", "0 0 */5 Apr,Aug,Oct Mon", "Apr 30 00:00 2012"}, - {"Jul 9 23:35 2012", "0 0 */5 Oct Mon", "Oct 31 00:00 2011"}, - - // Wrap around years - {"Jan 9 23:35 2012", "0 0 * Feb Mon", "Feb 28 00:00 2011"}, - {"Jan 9 23:35 2012", "0 0 * Feb Mon/2", "Feb 28 00:00 2011"}, - - // Leap year - {"Jan 9 23:35 2012", "0 0 29 Feb ?", "Feb 29 00:00 2008"}, - - // Daylight savings time 2am EST (-5) -> 3am EDT (-4) - {"2012-03-11T03:59:00-0400", "TZ=America/New_York 30 1 11 Mar ?", "2012-03-11T02:30:00-0400"}, - - // hourly job - {"2012-03-11T00:59:00-0500", "TZ=America/New_York 0 * * * ?", "2012-03-11T00:00:00-0500"}, - {"2012-03-11T02:59:00-0400", "TZ=America/New_York 0 * * * ?", "2012-03-11T01:00:00-0500"}, - {"2012-03-11T03:59:00-0400", "TZ=America/New_York 0 * * * ?", "2012-03-11T03:00:00-0400"}, - {"2012-03-11T04:59:00-0400", "TZ=America/New_York 0 * * * ?", "2012-03-11T04:00:00-0400"}, - - // hourly job using CRON_TZ - {"2012-03-11T00:59:00-0500", "CRON_TZ=America/New_York 0 * * * ?", "2012-03-11T00:00:00-0500"}, - {"2012-03-11T02:59:00-0400", "CRON_TZ=America/New_York 0 * * * ?", "2012-03-11T01:00:00-0500"}, - {"2012-03-11T03:59:00-0400", "CRON_TZ=America/New_York 0 * * * ?", "2012-03-11T03:00:00-0400"}, - {"2012-03-11T04:59:00-0400", "CRON_TZ=America/New_York 0 * * * ?", "2012-03-11T04:00:00-0400"}, - - // 1am nightly job - {"2012-03-11T01:59:00-0500", "TZ=America/New_York 0 1 * * ?", "2012-03-11T01:00:00-0500"}, - {"2012-03-11T03:00:00-0400", "TZ=America/New_York 0 1 * * ?", "2012-03-11T01:00:00-0500"}, - - // 2am nightly job (skipped) - {"2012-03-12T01:00:00-0400", "TZ=America/New_York 0 2 * * ?", "2012-03-10T02:00:00-0500"}, - - // Daylight savings time 2am EDT (-4) => 1am EST (-5) - {"2012-11-04T02:30:00-0500", "TZ=America/New_York 0 0 04 Nov ?", "2012-11-04T00:00:00-0400"}, - {"2012-11-04T01:30:00-0500", "TZ=America/New_York 45 1 04 Nov ?", "2012-11-04T01:45:00-0400"}, - - // hourly job - {"2012-11-04T00:59:00-0400", "TZ=America/New_York 0 * * * ?", "2012-11-04T00:00:00-0400"}, - {"2012-11-04T01:00:00-0500", "TZ=America/New_York 30 * * * ?", "2012-11-04T01:30:00-0400"}, - {"2012-11-04T01:00:00-0500", "TZ=America/New_York 0 * * * ?", "2012-11-04T01:00:00-0500"}, - - // 1am nightly job (runs twice) - {"2012-11-04T01:59:00-0400", "TZ=America/New_York 0 1 * * ?", "2012-11-04T01:00:00-0400"}, - {"2012-11-04T02:00:00-0400", "TZ=America/New_York 0 1 * * ?", "2012-11-04T01:00:00-0500"}, - {"2012-11-04T01:00:00-0500", "TZ=America/New_York 0 1 * * ?", "2012-11-04T01:00:00-0500"}, - - // 2am nightly job - {"2012-11-04T01:59:00-0500", "TZ=America/New_York 0 2 * * ?", "2012-11-03T02:00:00-0400"}, - - // Unsatisfiable - {"Jul 9 23:35 2012", "0 0 30 Feb ?", ""}, - {"Jul 9 23:35 2012", "0 0 31 Apr ?", ""}, - } - - for _, c := range runs { - ss := v1alpha1.SchedulerSpec{Cron: c.spec} - actual, err := LastTime(ss, getTime(c.time)) - if err != nil { - t.Error(err) - continue - } - expected := getTime(c.expected) - if !actual.Equal(expected) { - t.Errorf("%s, \"%s\": (expected) %v != %v (actual)", c.time, c.spec, expected, actual) - } - } -} - -func getTime(value string) time.Time { - if value == "" { - return time.Time{} - } - - var location = time.Local - if strings.HasPrefix(value, "TZ=") { - parts := strings.Fields(value) - loc, err := time.LoadLocation(parts[0][len("TZ="):]) - if err != nil { - panic("could not parse location:" + err.Error()) - } - location = loc - value = parts[1] - } - - var layouts = []string{ - "Jan 2 15:04 2006", - "Jan 2 15:04:05 2006", - } - for _, layout := range layouts { - if t, err := time.ParseInLocation(layout, value, location); err == nil { - return t - } - } - if t, err := time.ParseInLocation("2006-01-02T15:04:05-0700", value, location); err == nil { - return t - } - panic("could not parse time value " + value) -} diff --git a/pkg/selector/aws/selector.go b/pkg/selector/aws/selector.go new file mode 100644 index 0000000000..aff7749540 --- /dev/null +++ b/pkg/selector/aws/selector.go @@ -0,0 +1,32 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package aws + +import ( + "context" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type SelectImpl struct{} + +func (impl *SelectImpl) Select(ctx context.Context, awsSelector *v1alpha1.AWSSelector) ([]*v1alpha1.AWSSelector, error) { + return []*v1alpha1.AWSSelector{awsSelector}, nil +} + +func New() *SelectImpl { + return &SelectImpl{} +} diff --git a/pkg/selector/azure/selector.go b/pkg/selector/azure/selector.go new file mode 100644 index 0000000000..ac4a15e0ac --- /dev/null +++ b/pkg/selector/azure/selector.go @@ -0,0 +1,32 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package azure + +import ( + "context" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type SelectImpl struct{} + +func (impl *SelectImpl) Select(ctx context.Context, azureSelector *v1alpha1.AzureSelector) ([]*v1alpha1.AzureSelector, error) { + return []*v1alpha1.AzureSelector{azureSelector}, nil +} + +func New() *SelectImpl { + return &SelectImpl{} +} diff --git a/pkg/selector/container/selector.go b/pkg/selector/container/selector.go new file mode 100644 index 0000000000..aaf5ab822f --- /dev/null +++ b/pkg/selector/container/selector.go @@ -0,0 +1,98 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package container + +import ( + "context" + + "go.uber.org/fx" + v1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/pod" +) + +type SelectImpl struct { + c client.Client + r client.Reader + + generic.Option +} + +type Container struct { + v1.Pod + ContainerName string +} + +func (c *Container) Id() string { + return c.Pod.Namespace + "/" + c.Pod.Name + "/" + c.ContainerName +} + +func (impl *SelectImpl) Select(ctx context.Context, cs *v1alpha1.ContainerSelector) ([]*Container, error) { + pods, err := pod.SelectAndFilterPods(ctx, impl.c, impl.r, &cs.PodSelector, impl.ClusterScoped, impl.TargetNamespace, impl.EnableFilterNamespace) + if err != nil { + return nil, err + } + + containerNameMap := make(map[string]struct{}) + for _, name := range cs.ContainerNames { + containerNameMap[name] = struct{}{} + } + + var result []*Container + for _, pod := range pods { + if len(cs.ContainerNames) == 0 { + result = append(result, &Container{ + Pod: pod, + ContainerName: pod.Spec.Containers[0].Name, + }) + continue + } + + for _, container := range pod.Spec.Containers { + if _, ok := containerNameMap[container.Name]; ok { + result = append(result, &Container{ + Pod: pod, + ContainerName: container.Name, + }) + } + } + } + + return result, nil +} + +type Params struct { + fx.In + + Client client.Client + Reader client.Reader `name:"no-cache"` +} + +func New(params Params) *SelectImpl { + return &SelectImpl{ + params.Client, + params.Reader, + generic.Option{ + ClusterScoped: config.ControllerCfg.ClusterScoped, + TargetNamespace: config.ControllerCfg.TargetNamespace, + EnableFilterNamespace: config.ControllerCfg.EnableFilterNamespace, + }, + } +} diff --git a/pkg/selector/gcp/selector.go b/pkg/selector/gcp/selector.go new file mode 100644 index 0000000000..703623ae4c --- /dev/null +++ b/pkg/selector/gcp/selector.go @@ -0,0 +1,32 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gcp + +import ( + "context" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type SelectImpl struct{} + +func (impl *SelectImpl) Select(ctx context.Context, gcpSelector *v1alpha1.GCPSelector) ([]*v1alpha1.GCPSelector, error) { + return []*v1alpha1.GCPSelector{gcpSelector}, nil +} + +func New() *SelectImpl { + return &SelectImpl{} +} diff --git a/pkg/selector/generic/annotation/selector.go b/pkg/selector/generic/annotation/selector.go new file mode 100644 index 0000000000..8754f5eee8 --- /dev/null +++ b/pkg/selector/generic/annotation/selector.go @@ -0,0 +1,55 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package annotation + +import ( + "k8s.io/apimachinery/pkg/labels" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/label" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" +) + +const Name = "annotation" + +type annotationSelector struct { + labels.Selector +} + +var _ generic.Selector = &annotationSelector{} + +func (s *annotationSelector) ListOption() client.ListOption { + return nil +} + +func (s *annotationSelector) ListFunc(_ client.Reader) generic.ListFunc { + return nil +} + +func (s *annotationSelector) Match(obj client.Object) bool { + annotations := labels.Set(obj.GetAnnotations()) + return s.Matches(annotations) +} + +func New(spec v1alpha1.GenericSelectorSpec, _ generic.Option) (generic.Selector, error) { + selectorStr := label.Label(spec.AnnotationSelectors).String() + s, err := labels.Parse(selectorStr) + if err != nil { + return nil, err + } + return &annotationSelector{Selector: s}, nil +} diff --git a/pkg/selector/generic/annotation/selector_test.go b/pkg/selector/generic/annotation/selector_test.go new file mode 100644 index 0000000000..2cb8450e9a --- /dev/null +++ b/pkg/selector/generic/annotation/selector_test.go @@ -0,0 +1,65 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package annotation + +import ( + "testing" + + . "github.com/onsi/gomega" + v1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" + . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" +) + +func TestMatch(t *testing.T) { + g := NewGomegaWithT(t) + + p2Selector, err := New(v1alpha1.GenericSelectorSpec{AnnotationSelectors: map[string]string{"p2": "p2"}}, generic.Option{}) + g.Expect(err).ShouldNot(HaveOccurred()) + + emptySelector, err := New(v1alpha1.GenericSelectorSpec{}, generic.Option{}) + g.Expect(err).ShouldNot(HaveOccurred()) + + tcs := []struct { + name string + pod v1.Pod + selector generic.Selector + match bool + }{ + { + name: "filter p2, exist p2 annotations", + pod: NewPod(PodArg{Name: "p2", Ans: map[string]string{"p2": "p2"}}), + selector: p2Selector, + match: true, + }, { + name: "filter p2, not exist p2 annotations", + pod: NewPod(PodArg{Name: "p1", Ans: map[string]string{"p1": "p1"}}), + selector: p2Selector, + match: false, + }, { + name: "empty filter", + pod: NewPod(PodArg{Name: "p1", Ans: map[string]string{"p1": "p1"}}), + selector: emptySelector, + match: true, + }, + } + + for _, tc := range tcs { + g.Expect(tc.selector.Match(&tc.pod)).To(Equal(tc.match), tc.name) + } +} diff --git a/pkg/selector/generic/field/selector.go b/pkg/selector/generic/field/selector.go new file mode 100644 index 0000000000..a98eeb3cdd --- /dev/null +++ b/pkg/selector/generic/field/selector.go @@ -0,0 +1,108 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package field + +import ( + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" +) + +const Name = "field" + +type fieldSelector struct { + fields.Selector +} + +var _ generic.Selector = &fieldSelector{} + +func (s *fieldSelector) ListOption() client.ListOption { + if !s.Empty() { + return client.MatchingFieldsSelector{Selector: s} + } + return nil +} + +func (s *fieldSelector) ListFunc(r client.Reader) generic.ListFunc { + // Since FieldSelectors need to implement index creation, Reader.List is used to get the pod list. + // Otherwise, just call Client.List directly, which can be obtained through cache. + if !s.Empty() && r != nil { + return r.List + } + return nil +} + +func (s *fieldSelector) Match(obj client.Object) bool { + var objFields fields.Set + switch obj := obj.(type) { + case *v1.Pod: + objFields = toPodSelectableFields(obj) + case *v1alpha1.PhysicalMachine: + objFields = toPhysicalMachineSelectableFields(obj) + default: + // not support + return false + } + return s.Matches(objFields) +} + +func New(spec v1alpha1.GenericSelectorSpec, _ generic.Option) (generic.Selector, error) { + return &fieldSelector{ + Selector: fields.SelectorFromSet(spec.FieldSelectors), + }, nil +} + +// toPodSelectableFields returns a field set that represents the object +// https://github.com/kubernetes/kubernetes/blob/v1.22.2/pkg/registry/core/pod/strategy.go#L306 +func toPodSelectableFields(pod *v1.Pod) fields.Set { + // The purpose of allocation with a given number of elements is to reduce + // amount of allocations needed to create the fields.Set. If you add any + // field here or the number of object-meta related fields changes, this should + // be adjusted. + podSpecificFieldsSet := make(fields.Set, 9) + podSpecificFieldsSet["spec.nodeName"] = pod.Spec.NodeName + podSpecificFieldsSet["spec.restartPolicy"] = string(pod.Spec.RestartPolicy) + podSpecificFieldsSet["spec.schedulerName"] = pod.Spec.SchedulerName + podSpecificFieldsSet["spec.serviceAccountName"] = pod.Spec.ServiceAccountName + podSpecificFieldsSet["status.phase"] = string(pod.Status.Phase) + podIP := "" + if len(pod.Status.PodIPs) > 0 { + podIP = string(pod.Status.PodIPs[0].IP) + } + podSpecificFieldsSet["status.podIP"] = podIP + podSpecificFieldsSet["status.nominatedNodeName"] = pod.Status.NominatedNodeName + return addObjectMetaFieldsSet(podSpecificFieldsSet, &pod.ObjectMeta, true) +} + +// toPhysicalMachineSelectableFields returns a field set that represents the object +func toPhysicalMachineSelectableFields(physicalMachine *v1alpha1.PhysicalMachine) fields.Set { + pmSpecificFieldsSet := make(fields.Set, 3) + pmSpecificFieldsSet["spec.address"] = physicalMachine.Spec.Address + return addObjectMetaFieldsSet(pmSpecificFieldsSet, &physicalMachine.ObjectMeta, true) +} + +// addObjectMetaFieldsSet add fields that represent the ObjectMeta to source. +func addObjectMetaFieldsSet(source fields.Set, objectMeta *metav1.ObjectMeta, hasNamespaceField bool) fields.Set { + source["metadata.name"] = objectMeta.Name + if hasNamespaceField { + source["metadata.namespace"] = objectMeta.Namespace + } + return source +} diff --git a/pkg/selector/generic/field/selector_test.go b/pkg/selector/generic/field/selector_test.go new file mode 100644 index 0000000000..401a7017dd --- /dev/null +++ b/pkg/selector/generic/field/selector_test.go @@ -0,0 +1,89 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package field + +import ( + "testing" + + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" + . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" +) + +func TestMatch(t *testing.T) { + g := NewGomegaWithT(t) + + nameFieldSelector, err := New(v1alpha1.GenericSelectorSpec{FieldSelectors: map[string]string{"metadata.name": "p2"}}, generic.Option{}) + g.Expect(err).ShouldNot(HaveOccurred()) + + emptySelector, err := New(v1alpha1.GenericSelectorSpec{}, generic.Option{}) + g.Expect(err).ShouldNot(HaveOccurred()) + + addressFieldSelector, err := New(v1alpha1.GenericSelectorSpec{FieldSelectors: map[string]string{"spec.address": "123"}}, generic.Option{}) + g.Expect(err).ShouldNot(HaveOccurred()) + + p1Pod := NewPod(PodArg{Name: "p1"}) + p2Pod := NewPod(PodArg{Name: "p2"}) + p1PhysicalMachine := v1alpha1.PhysicalMachine{ObjectMeta: metav1.ObjectMeta{Name: "p1"}, Spec: v1alpha1.PhysicalMachineSpec{Address: "123"}} + p2PhysicalMachine := v1alpha1.PhysicalMachine{ObjectMeta: metav1.ObjectMeta{Name: "p2"}} + + tcs := []struct { + name string + obj client.Object + selector generic.Selector + match bool + }{ + { + name: "filter by name", + obj: &p2Pod, + selector: nameFieldSelector, + match: true, + }, { + name: "filter by name", + obj: &p1Pod, + selector: nameFieldSelector, + match: false, + }, { + name: "empty filter", + obj: &p1Pod, + selector: emptySelector, + match: true, + }, { + name: "filter by physical machine address", + obj: &p1PhysicalMachine, + selector: addressFieldSelector, + match: true, + }, { + name: "filter by physical machine address", + obj: &p2PhysicalMachine, + selector: addressFieldSelector, + match: false, + }, { + name: "filter by physical machine address", + obj: &p1Pod, + selector: addressFieldSelector, + match: false, + }, + } + + for _, tc := range tcs { + g.Expect(tc.selector.Match(tc.obj)).To(Equal(tc.match), tc.name) + } +} diff --git a/pkg/selector/generic/label/selector.go b/pkg/selector/generic/label/selector.go new file mode 100644 index 0000000000..5ad523eecd --- /dev/null +++ b/pkg/selector/generic/label/selector.go @@ -0,0 +1,58 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package label + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" +) + +const Name = "label" + +type labelSelector struct { + labels.Selector +} + +var _ generic.Selector = &labelSelector{} + +func (s *labelSelector) ListOption() client.ListOption { + return client.MatchingLabelsSelector{Selector: s} +} + +func (s *labelSelector) ListFunc(_ client.Reader) generic.ListFunc { + return nil +} + +func (s *labelSelector) Match(obj client.Object) bool { + objLabels := labels.Set(obj.GetLabels()) + return s.Matches(objLabels) +} + +func New(spec v1alpha1.GenericSelectorSpec, _ generic.Option) (generic.Selector, error) { + metav1Ls := &metav1.LabelSelector{ + MatchLabels: spec.LabelSelectors, + MatchExpressions: spec.ExpressionSelectors, + } + ls, err := metav1.LabelSelectorAsSelector(metav1Ls) + if err != nil { + return nil, err + } + return &labelSelector{Selector: ls}, nil +} diff --git a/pkg/selector/generic/label/selector_test.go b/pkg/selector/generic/label/selector_test.go new file mode 100644 index 0000000000..9b49bae701 --- /dev/null +++ b/pkg/selector/generic/label/selector_test.go @@ -0,0 +1,65 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package label + +import ( + "testing" + + . "github.com/onsi/gomega" + v1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" + . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" +) + +func TestMatch(t *testing.T) { + g := NewGomegaWithT(t) + + p2Selector, err := New(v1alpha1.GenericSelectorSpec{LabelSelectors: map[string]string{"p2": "p2"}}, generic.Option{}) + g.Expect(err).ShouldNot(HaveOccurred()) + + emptySelector, err := New(v1alpha1.GenericSelectorSpec{}, generic.Option{}) + g.Expect(err).ShouldNot(HaveOccurred()) + + tcs := []struct { + name string + pod v1.Pod + selector generic.Selector + match bool + }{ + { + name: "filter p2, exist p2 labels", + pod: NewPod(PodArg{Name: "p2", Labels: map[string]string{"p2": "p2"}}), + selector: p2Selector, + match: true, + }, { + name: "filter p2, not exist p2 labels", + pod: NewPod(PodArg{Name: "p1", Labels: map[string]string{"p1": "p1"}}), + selector: p2Selector, + match: false, + }, { + name: "empty filter", + pod: NewPod(PodArg{Name: "p1", Labels: map[string]string{"p1": "p1"}}), + selector: emptySelector, + match: true, + }, + } + + for _, tc := range tcs { + g.Expect(tc.selector.Match(&tc.pod)).To(Equal(tc.match), tc.name) + } +} diff --git a/pkg/selector/generic/mode.go b/pkg/selector/generic/mode.go new file mode 100644 index 0000000000..9127973281 --- /dev/null +++ b/pkg/selector/generic/mode.go @@ -0,0 +1,134 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package generic + +import ( + "crypto/rand" + "math" + "math/big" + "strconv" + + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +// FilterObjectsByMode filters objects by mode +func FilterObjectsByMode(mode v1alpha1.SelectorMode, value string, count int) ([]uint, error) { + if count == 0 { + return nil, errors.New("cannot generate objects from empty list") + } + + switch mode { + case v1alpha1.OneMode: + index := getRandomNumber(count) + return []uint{uint(index)}, nil + case v1alpha1.AllMode: + return RandomFixedIndexes(0, uint(count), uint(count)+1), nil + case v1alpha1.FixedMode: + num, err := strconv.Atoi(value) + if err != nil { + return nil, err + } + + if count < num { + num = count + } + + if num <= 0 { + return nil, errors.New("cannot select any object as value below or equal 0") + } + + return RandomFixedIndexes(0, uint(count), uint(num)), nil + case v1alpha1.FixedPercentMode: + percentage, err := strconv.Atoi(value) + if err != nil { + return nil, err + } + + if percentage == 0 { + return nil, errors.New("cannot select any object as value below or equal 0") + } + + if percentage < 0 || percentage > 100 { + return nil, errors.Errorf("fixed percentage value of %d is invalid, Must be (0,100]", percentage) + } + + // at least one object should be selected + num := int(math.Ceil(float64(count) * float64(percentage) / 100)) + + return RandomFixedIndexes(0, uint(count), uint(num)), nil + case v1alpha1.RandomMaxPercentMode: + maxPercentage, err := strconv.Atoi(value) + if err != nil { + return nil, err + } + + if maxPercentage == 0 { + return nil, errors.New("cannot select any object as value below or equal 0") + } + + if maxPercentage < 0 || maxPercentage > 100 { + return nil, errors.Errorf("fixed percentage value of %d is invalid, Must be [0-100]", maxPercentage) + } + + percentage := getRandomNumber(maxPercentage + 1) // + 1 because Intn works with half open interval [0,n) and we want [0,n] + num := int(math.Ceil(float64(count) * float64(percentage) / 100)) + + return RandomFixedIndexes(0, uint(count), uint(num)), nil + default: + return nil, errors.Errorf("mode %s not supported", mode) + } +} + +// RandomFixedIndexes returns the `count` random indexes between `start` and `end`. +// [start, end) +func RandomFixedIndexes(start, end, count uint) []uint { + var indexes []uint + m := make(map[uint]uint, count) + + if end < start { + return indexes + } + + if count > end-start { + for i := start; i < end; i++ { + indexes = append(indexes, i) + } + + return indexes + } + + for i := 0; i < int(count); { + index := uint(getRandomNumber(int(end-start))) + start + + _, exist := m[index] + if exist { + continue + } + + m[index] = index + indexes = append(indexes, index) + i++ + } + + return indexes +} + +func getRandomNumber(max int) uint64 { + num, _ := rand.Int(rand.Reader, big.NewInt(int64(max))) + return num.Uint64() +} diff --git a/pkg/selector/generic/mode_test.go b/pkg/selector/generic/mode_test.go new file mode 100644 index 0000000000..baea588274 --- /dev/null +++ b/pkg/selector/generic/mode_test.go @@ -0,0 +1,68 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package generic + +import ( + "testing" + + . "github.com/onsi/gomega" +) + +func TestRandomFixedIndexes(t *testing.T) { + g := NewGomegaWithT(t) + + type TestCase struct { + name string + start uint + end uint + count uint + expectedOutputLen int + } + + tcs := []TestCase{ + { + name: "start 0, end 10, count 3", + start: 0, + end: 10, + count: 3, + expectedOutputLen: 3, + }, + { + name: "start 0, end 10, count 12", + start: 0, + end: 10, + count: 12, + expectedOutputLen: 10, + }, + { + name: "start 5, end 10, count 3", + start: 5, + end: 10, + count: 3, + expectedOutputLen: 3, + }, + } + + for _, tc := range tcs { + values := RandomFixedIndexes(tc.start, tc.end, tc.count) + g.Expect(len(values)).To(Equal(tc.expectedOutputLen), tc.name) + + for _, v := range values { + g.Expect(v).Should(BeNumerically(">=", tc.start), tc.name) + g.Expect(v).Should(BeNumerically("<", tc.end), tc.name) + } + } +} diff --git a/pkg/selector/generic/namespace/selector.go b/pkg/selector/generic/namespace/selector.go new file mode 100644 index 0000000000..fe0cf64965 --- /dev/null +++ b/pkg/selector/generic/namespace/selector.go @@ -0,0 +1,111 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package namespace + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" +) + +const Name = "namespace" + +type namespaceSelector struct { + generic.Option + namespaces []string +} + +var _ generic.Selector = &namespaceSelector{} + +func (s *namespaceSelector) ListOption() client.ListOption { + if !s.ClusterScoped { + return client.InNamespace(s.TargetNamespace) + } + return nil +} + +func (s *namespaceSelector) ListFunc(_ client.Reader) generic.ListFunc { + return nil +} + +func (s *namespaceSelector) Match(obj client.Object) bool { + if len(s.namespaces) == 0 { + return true + } + + for _, namespace := range s.namespaces { + if namespace == obj.GetNamespace() { + return true + } + } + return false +} + +func New(spec v1alpha1.GenericSelectorSpec, option generic.Option) (generic.Selector, error) { + if !option.ClusterScoped { + if len(spec.Namespaces) > 1 { + return nil, errors.New("could NOT use more than 1 namespace selector within namespace scoped mode") + } else if len(spec.Namespaces) == 1 { + if spec.Namespaces[0] != option.TargetNamespace { + return nil, errors.Errorf("could NOT list pods from out of scoped namespace: %s", spec.Namespaces[0]) + } + } + } + + return &namespaceSelector{ + Option: generic.Option{ + ClusterScoped: option.ClusterScoped, + TargetNamespace: option.TargetNamespace, + EnableFilterNamespace: option.EnableFilterNamespace, + }, + namespaces: spec.Namespaces, + }, nil +} + +func CheckNamespace(ctx context.Context, c client.Client, namespace string, logger logr.Logger) bool { + ok, err := IsAllowedNamespaces(ctx, c, namespace) + if err != nil { + logger.Error(err, "fail to check whether this namespace is allowed", "namespace", namespace) + return false + } + + if !ok { + logger.Info("namespace is not enabled for chaos-mesh", "namespace", namespace) + } + return ok +} + +func IsAllowedNamespaces(ctx context.Context, c client.Client, namespace string) (bool, error) { + ns := &v1.Namespace{} + + err := c.Get(ctx, types.NamespacedName{Name: namespace}, ns) + if err != nil { + return false, err + } + + if ns.Annotations[generic.InjectAnnotationKey] == "enabled" { + return true, nil + } + + return false, nil +} diff --git a/pkg/selector/generic/namespace/selector_test.go b/pkg/selector/generic/namespace/selector_test.go new file mode 100644 index 0000000000..679f2c040f --- /dev/null +++ b/pkg/selector/generic/namespace/selector_test.go @@ -0,0 +1,108 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package namespace + +import ( + "testing" + + . "github.com/onsi/gomega" + v1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" + . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" +) + +func TestMatch(t *testing.T) { + g := NewGomegaWithT(t) + + pods := []v1.Pod{ + NewPod(PodArg{Name: "p1", Namespace: "n1"}), + NewPod(PodArg{Name: "p2", Namespace: "n2"}), + NewPod(PodArg{Name: "p4", Namespace: "n4"}), + } + + option := generic.Option{ + ClusterScoped: true, + TargetNamespace: "", + EnableFilterNamespace: false, + } + + n2Selector, err := New(v1alpha1.GenericSelectorSpec{Namespaces: []string{"n2"}}, option) + g.Expect(err).ShouldNot(HaveOccurred()) + + emptySelector, err := New(v1alpha1.GenericSelectorSpec{}, option) + g.Expect(err).ShouldNot(HaveOccurred()) + + n2AndN3Selector, err := New(v1alpha1.GenericSelectorSpec{Namespaces: []string{"n2", "n3"}}, option) + g.Expect(err).ShouldNot(HaveOccurred()) + + n2AndN4Selector, err := New(v1alpha1.GenericSelectorSpec{Namespaces: []string{"n2", "n4"}}, option) + g.Expect(err).ShouldNot(HaveOccurred()) + + tcs := []struct { + name string + pod v1.Pod + selector generic.Selector + match bool + }{ + { + name: "filter n2, exist n2 namespace", + pod: pods[1], + selector: n2Selector, + match: true, + }, { + name: "filter n2, not exist n2 namespace", + pod: pods[0], + selector: n2Selector, + match: false, + }, { + name: "empty filter", + pod: pods[0], + selector: emptySelector, + match: true, + }, { + name: "filter n2 and n3, exist n2 namespace", + pod: pods[1], + selector: n2AndN3Selector, + match: true, + }, { + name: "filter n2 and n3, not exist n2 namespace", + pod: pods[0], + selector: n2AndN3Selector, + match: false, + }, { + name: "filter n2 and n4, exist n2 namespace", + pod: pods[1], + selector: n2AndN4Selector, + match: true, + }, { + name: "filter n2 and n4, exist n4 namespace", + pod: pods[2], + selector: n2AndN4Selector, + match: true, + }, { + name: "filter n2 and n4, not exist n2 namespace", + pod: pods[0], + selector: n2AndN4Selector, + match: false, + }, + } + + for _, tc := range tcs { + g.Expect(tc.selector.Match(&tc.pod)).To(Equal(tc.match), tc.name) + } +} diff --git a/pkg/selector/generic/registry/registry.go b/pkg/selector/generic/registry/registry.go new file mode 100644 index 0000000000..b4f6ab32a3 --- /dev/null +++ b/pkg/selector/generic/registry/registry.go @@ -0,0 +1,40 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package registry + +import ( + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" +) + +type Registry map[string]SelectorFactory + +// SelectorFactory is a function that builds a selector. +type SelectorFactory = func(selector v1alpha1.GenericSelectorSpec, option generic.Option) (generic.Selector, error) + +func Parse(registry Registry, spec v1alpha1.GenericSelectorSpec, option generic.Option) (generic.SelectorChain, error) { + selectors := make([]generic.Selector, 0, len(registry)) + for name, factory := range registry { + selector, err := factory(spec, option) + if err != nil { + return nil, errors.Errorf("cannot parse %s selector, msg: %+v", name, err) + } + selectors = append(selectors, selector) + } + return selectors, nil +} diff --git a/pkg/selector/generic/selector.go b/pkg/selector/generic/selector.go new file mode 100644 index 0000000000..518993a7fb --- /dev/null +++ b/pkg/selector/generic/selector.go @@ -0,0 +1,77 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package generic + +import ( + "context" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const InjectAnnotationKey = "chaos-mesh.org/inject" + +type Option struct { + ClusterScoped bool + TargetNamespace string + EnableFilterNamespace bool +} + +type ListFunc func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error + +// Selector is an interface implemented by things that know how to list objects from cluster and whether this object matches the selector. +type Selector interface { + // ListFunc returns the function to list object from kubernetes cluster. + // If no method is specified, returns `nil` directly. (default: `List` function of `client.Client`) + // If needed, `List` function of `client.Reader` can be returned. Only `field selector` uses it for now. + // When registering the Selector, it's important to note that multiple ListFunc will be overwritten in the SelectorChain. + ListFunc(client.Reader) ListFunc + // ListOption returns the client.ListOption that modifies options for a list request. + // If no option is specified, returns `nil` directly. + // When registering a Selector, it is important to note that multiple ListOptions will all apply to + // the same `client.ListOptions` and will be overwritten if they have the same fields in the SelectorChain. + ListOption() client.ListOption + // Match returns whether the object matches the selector + Match(client.Object) bool +} + +type SelectorChain []Selector + +func (s SelectorChain) ListObjects(c client.Client, r client.Reader, + listObj func(listFunc ListFunc, opts client.ListOptions) error) error { + var options []client.ListOption + listFunc := c.List + + for _, selector := range s { + if tmpOption := selector.ListOption(); tmpOption != nil { + options = append(options, selector.ListOption()) + } + if tmpListFunc := selector.ListFunc(r); tmpListFunc != nil { + listFunc = tmpListFunc + } + } + opts := client.ListOptions{} + opts.ApplyOptions(options) + return listObj(listFunc, opts) +} + +func (s SelectorChain) Match(obj client.Object) bool { + for _, selector := range s { + if !selector.Match(obj) { + return false + } + } + return true +} diff --git a/pkg/selector/nodevolumepath/selector.go b/pkg/selector/nodevolumepath/selector.go new file mode 100644 index 0000000000..9967a62a68 --- /dev/null +++ b/pkg/selector/nodevolumepath/selector.go @@ -0,0 +1,132 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package nodevolumepath + +import ( + "context" + + "github.com/pkg/errors" + "go.uber.org/fx" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/container" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" +) + +var errNotSupported = errors.New("not supported") + +type SelectImpl struct { + c client.Client + r client.Reader + + containerSelector *container.SelectImpl + generic.Option +} + +type NodeVolumePath struct { + *container.Container + + // volumePath is a volumePath to the block device or directory on a node + volumePath string +} + +func (n *NodeVolumePath) Id() string { + // The path may contain "/", but it doesn't matter + return n.Container.Id() + "/" + n.volumePath +} + +func (impl *SelectImpl) Select(ctx context.Context, selector *v1alpha1.ContainerNodeVolumePathSelector) ([]*NodeVolumePath, error) { + containers, err := impl.containerSelector.Select(ctx, &selector.ContainerSelector) + if err != nil { + return nil, err + } + + var result []*NodeVolumePath + for _, container := range containers { + for _, volume := range container.Spec.Volumes { + if volume.Name == selector.VolumeName { + // Find the path of the volume + // If the volume is a `HostPath`, the path is the `Path` field + // If the volume is a `PersistentVolumeClaim`, we can get the path from the related `PersistentVolume` + if volume.HostPath != nil { + result = append(result, &NodeVolumePath{ + Container: container, + volumePath: volume.HostPath.Path, + }) + } else if volume.PersistentVolumeClaim != nil { + var pvc v1.PersistentVolumeClaim + impl.c.Get(ctx, types.NamespacedName{ + Namespace: container.Namespace, + Name: volume.PersistentVolumeClaim.ClaimName, + }, &pvc) + if pvc.Status.Phase == v1.ClaimBound { + var pv v1.PersistentVolume + impl.c.Get(ctx, types.NamespacedName{ + Name: pvc.Spec.VolumeName, + }, &pv) + + // Only `HostPath` and `LocalVolume` are supported + // TODO: Possibly support more PersistentVolume source. + if pv.Spec.HostPath != nil { + result = append(result, &NodeVolumePath{ + Container: container, + volumePath: pv.Spec.HostPath.Path, + }) + } else if pv.Spec.Local != nil { + result = append(result, &NodeVolumePath{ + Container: container, + volumePath: pv.Spec.Local.Path, + }) + } else { + return nil, errors.Wrap(errNotSupported, "unsupported PersistentVolume source") + } + } else { + return nil, errors.Wrapf(errNotSupported, "PVC is not bounded yet: pvc phase: %s", pvc.Status.Phase) + } + } else { + return nil, errors.Wrapf(errNotSupported, "volume source is not supported") + } + } + } + } + + return result, nil +} + +type Params struct { + fx.In + + ContainerSelector *container.SelectImpl + Client client.Client + Reader client.Reader `name:"no-cache"` +} + +func New(params Params) *SelectImpl { + return &SelectImpl{ + params.Client, + params.Reader, + params.ContainerSelector, + generic.Option{ + ClusterScoped: config.ControllerCfg.ClusterScoped, + TargetNamespace: config.ControllerCfg.TargetNamespace, + EnableFilterNamespace: config.ControllerCfg.EnableFilterNamespace, + }, + } +} diff --git a/pkg/selector/physicalmachine/selector.go b/pkg/selector/physicalmachine/selector.go new file mode 100644 index 0000000000..8c6389a635 --- /dev/null +++ b/pkg/selector/physicalmachine/selector.go @@ -0,0 +1,265 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package physicalmachine + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "go.uber.org/fx" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" + genericannotation "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic/annotation" + genericfield "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic/field" + genericlabel "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic/label" + genericnamespace "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic/namespace" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic/registry" +) + +type SelectImpl struct { + c client.Client + r client.Reader + + generic.Option + logger logr.Logger +} + +type Params struct { + fx.In + + Client client.Client + Reader client.Reader `name:"no-cache"` +} + +type PhysicalMachine struct { + v1alpha1.PhysicalMachine + Address string +} + +func (pm *PhysicalMachine) Id() string { + if len(pm.Address) > 0 { + return pm.Address + } + return (types.NamespacedName{ + Name: pm.Name, + Namespace: pm.Namespace, + }).String() +} + +func (impl *SelectImpl) Select(ctx context.Context, physicalMachineSelector *v1alpha1.PhysicalMachineSelector) ([]*PhysicalMachine, error) { + if physicalMachineSelector == nil { + return []*PhysicalMachine{}, nil + } + + physicalMachines, err := SelectAndFilterPhysicalMachines(ctx, impl.c, impl.r, physicalMachineSelector, impl.ClusterScoped, impl.TargetNamespace, impl.EnableFilterNamespace, impl.logger) + if err != nil { + return nil, err + } + + filtered, err := filterPhysicalMachinesByMode(physicalMachines, physicalMachineSelector.Mode, physicalMachineSelector.Value) + if err != nil { + return nil, err + } + return filtered, nil +} + +func New(params Params, logger logr.Logger) *SelectImpl { + return &SelectImpl{ + params.Client, + params.Reader, + generic.Option{ + ClusterScoped: config.ControllerCfg.ClusterScoped, + TargetNamespace: config.ControllerCfg.TargetNamespace, + EnableFilterNamespace: config.ControllerCfg.EnableFilterNamespace, + }, + logger.WithName("physical-machine-selector"), + } +} + +// SelectAndFilterPhysicalMachines returns the list of physical machines that filtered by selector and SelectorMode +func SelectAndFilterPhysicalMachines(ctx context.Context, c client.Client, r client.Reader, spec *v1alpha1.PhysicalMachineSelector, clusterScoped bool, targetNamespace string, enableFilterNamespace bool, logger logr.Logger) ([]*PhysicalMachine, error) { + if len(spec.Address) > 0 { + var result []*PhysicalMachine + for _, address := range spec.Address { + result = append(result, &PhysicalMachine{ + Address: address, + }) + } + return result, nil + } + + physicalMachines, err := SelectPhysicalMachines(ctx, c, r, spec.Selector, clusterScoped, targetNamespace, enableFilterNamespace, logger) + if err != nil { + return nil, err + } + + if len(physicalMachines) == 0 { + err = errors.New("no physical machine is selected") + return nil, err + } + + var result []*PhysicalMachine + for _, physicalMachine := range physicalMachines { + result = append(result, &PhysicalMachine{ + PhysicalMachine: physicalMachine, + }) + } + return result, nil +} + +func SelectPhysicalMachines(ctx context.Context, c client.Client, r client.Reader, + selector v1alpha1.PhysicalMachineSelectorSpec, + clusterScoped bool, targetNamespace string, enableFilterNamespace bool, logger logr.Logger) ([]v1alpha1.PhysicalMachine, error) { + if len(selector.PhysicalMachines) > 0 { + return selectSpecifiedPhysicalMachines(ctx, c, selector, clusterScoped, targetNamespace, enableFilterNamespace, logger) + } + + selectorRegistry := newSelectorRegistry() + selectorChain, err := registry.Parse(selectorRegistry, selector.GenericSelectorSpec, generic.Option{ + ClusterScoped: clusterScoped, + TargetNamespace: targetNamespace, + EnableFilterNamespace: enableFilterNamespace, + }) + if err != nil { + return nil, err + } + + return listPhysicalMachines(ctx, c, r, selector, selectorChain, enableFilterNamespace, logger) +} + +func listPhysicalMachines(ctx context.Context, c client.Client, r client.Reader, spec v1alpha1.PhysicalMachineSelectorSpec, + selectorChain generic.SelectorChain, enableFilterNamespace bool, logger logr.Logger) ([]v1alpha1.PhysicalMachine, error) { + var physicalMachines []v1alpha1.PhysicalMachine + namespaceCheck := make(map[string]bool) + + if err := selectorChain.ListObjects(c, r, + func(listFunc generic.ListFunc, opts client.ListOptions) error { + var pmList v1alpha1.PhysicalMachineList + + if len(spec.Namespaces) > 0 { + for _, namespace := range spec.Namespaces { + if enableFilterNamespace { + allow, ok := namespaceCheck[namespace] + if !ok { + allow = genericnamespace.CheckNamespace(ctx, c, namespace, logger) + namespaceCheck[namespace] = allow + } + if !allow { + continue + } + } + + opts.Namespace = namespace + if err := listFunc(ctx, &pmList, &opts); err != nil { + return err + } + physicalMachines = append(physicalMachines, pmList.Items...) + } + } else { + // in fact, this will never happen + if err := listFunc(ctx, &pmList, &opts); err != nil { + return err + } + physicalMachines = append(physicalMachines, pmList.Items...) + } + return nil + }); err != nil { + return nil, err + } + + filterList := make([]v1alpha1.PhysicalMachine, 0, len(physicalMachines)) + for _, physicalMachine := range physicalMachines { + physicalMachine := physicalMachine + if selectorChain.Match(&physicalMachine) { + filterList = append(filterList, physicalMachine) + } + } + return filterList, nil +} + +func newSelectorRegistry() registry.Registry { + return map[string]registry.SelectorFactory{ + genericlabel.Name: genericlabel.New, + genericnamespace.Name: genericnamespace.New, + genericfield.Name: genericfield.New, + genericannotation.Name: genericannotation.New, + } +} + +func selectSpecifiedPhysicalMachines(ctx context.Context, c client.Client, spec v1alpha1.PhysicalMachineSelectorSpec, + clusterScoped bool, targetNamespace string, enableFilterNamespace bool, logger logr.Logger) ([]v1alpha1.PhysicalMachine, error) { + var physicalMachines []v1alpha1.PhysicalMachine + namespaceCheck := make(map[string]bool) + + for ns, names := range spec.PhysicalMachines { + if !clusterScoped { + if targetNamespace != ns { + logger.Info("skip namespace because ns is out of scope within namespace scoped mode", "namespace", ns) + continue + } + } + if enableFilterNamespace { + allow, ok := namespaceCheck[ns] + if !ok { + allow = genericnamespace.CheckNamespace(ctx, c, ns, logger) + namespaceCheck[ns] = allow + } + if !allow { + continue + } + } + for _, name := range names { + var physicalMachine v1alpha1.PhysicalMachine + err := c.Get(ctx, types.NamespacedName{ + Namespace: ns, + Name: name, + }, &physicalMachine) + if err == nil { + physicalMachines = append(physicalMachines, physicalMachine) + continue + } + + if apierrors.IsNotFound(err) { + logger.Error(err, "PhysicalMachine is not found", "namespace", ns, "physical machine name", name) + continue + } + + return nil, err + } + } + return physicalMachines, nil +} + +// filterPhysicalMachinesByMode filters physical machines by mode from physical machine list +func filterPhysicalMachinesByMode(physicalMachines []*PhysicalMachine, mode v1alpha1.SelectorMode, value string) ([]*PhysicalMachine, error) { + indexes, err := generic.FilterObjectsByMode(mode, value, len(physicalMachines)) + if err != nil { + return nil, err + } + + var filtered []*PhysicalMachine + for _, index := range indexes { + index := index + filtered = append(filtered, physicalMachines[index]) + } + return filtered, nil +} diff --git a/pkg/selector/physicalmachine/selector_test.go b/pkg/selector/physicalmachine/selector_test.go new file mode 100644 index 0000000000..a48432a1b7 --- /dev/null +++ b/pkg/selector/physicalmachine/selector_test.go @@ -0,0 +1,143 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package physicalmachine + +import ( + "context" + "testing" + + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/kubectl/pkg/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/log" + . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" +) + +func TestSelectPhysicalMachines(t *testing.T) { + g := NewGomegaWithT(t) + + objects, physicalMachines := GenerateNPhysicalMachines("p", 5, PhysicalMachineArg{Labels: map[string]string{"l1": "l1"}}) + objects2, physicalMachines2 := GenerateNPhysicalMachines("s", 2, PhysicalMachineArg{Namespace: "test-s", Labels: map[string]string{"l2": "l2"}}) + + objects = append(objects, objects2...) + physicalMachines = append(physicalMachines, physicalMachines2...) + + err := v1alpha1.SchemeBuilder.AddToScheme(scheme.Scheme) + g.Expect(err).NotTo(HaveOccurred()) + + c := fake.NewClientBuilder(). + WithScheme(scheme.Scheme). + WithRuntimeObjects(objects...). + WithStatusSubresource(&v1alpha1.PodNetworkChaos{}). + Build() + var r client.Reader + + type TestCase struct { + name string + selector v1alpha1.PhysicalMachineSelectorSpec + expected []v1alpha1.PhysicalMachine + } + + tcs := []TestCase{ + { + name: "filter specified physical machines", + selector: v1alpha1.PhysicalMachineSelectorSpec{ + PhysicalMachines: map[string][]string{ + metav1.NamespaceDefault: {"p3", "p4"}, + "test-s": {"s1"}, + }, + }, + expected: []v1alpha1.PhysicalMachine{physicalMachines[3], physicalMachines[4], physicalMachines[6]}, + }, + { + name: "filter labels physical machines", + selector: v1alpha1.PhysicalMachineSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + LabelSelectors: map[string]string{"l2": "l2"}, + }, + }, + expected: []v1alpha1.PhysicalMachine{physicalMachines[5], physicalMachines[6]}, + }, + { + name: "filter physicalMachines by label expressions", + selector: v1alpha1.PhysicalMachineSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + ExpressionSelectors: []metav1.LabelSelectorRequirement{ + { + Key: "l2", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"l2"}, + }, + }, + }, + }, + expected: []v1alpha1.PhysicalMachine{physicalMachines[5], physicalMachines[6]}, + }, + { + name: "filter physicalMachines by label selectors and expression selectors", + selector: v1alpha1.PhysicalMachineSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + LabelSelectors: map[string]string{"l1": "l1"}, + ExpressionSelectors: []metav1.LabelSelectorRequirement{ + { + Key: "l2", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"l2"}, + }, + }, + }, + }, + expected: nil, + }, + { + name: "filter namespace and labels", + selector: v1alpha1.PhysicalMachineSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{"test-s"}, + LabelSelectors: map[string]string{"l2": "l2"}, + }, + }, + expected: []v1alpha1.PhysicalMachine{physicalMachines[5], physicalMachines[6]}, + }, + { + name: "filter namespace and labels", + selector: v1alpha1.PhysicalMachineSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{metav1.NamespaceDefault}, + LabelSelectors: map[string]string{"l2": "l2"}, + }, + }, + expected: nil, + }, + } + + var ( + testCfgClusterScoped = true + testCfgTargetNamespace = "" + ) + + logger, _ := log.NewDefaultZapLogger() + + for _, tc := range tcs { + filtered, err := SelectPhysicalMachines(context.Background(), c, r, tc.selector, testCfgClusterScoped, testCfgTargetNamespace, false, logger) + g.Expect(err).ShouldNot(HaveOccurred(), tc.name) + g.Expect(len(filtered)).To(Equal(len(tc.expected)), tc.name) + } +} diff --git a/pkg/selector/pod/node_selector.go b/pkg/selector/pod/node_selector.go new file mode 100644 index 0000000000..23667f9b68 --- /dev/null +++ b/pkg/selector/pod/node_selector.go @@ -0,0 +1,88 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package pod + +import ( + "context" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" +) + +const nodeSelectorName = "node" + +type nodeSelector struct { + nodes []v1.Node + // empty avoids the situation that v1alpha1.PodSelectorSpec.NodeSelectors does not match any nodes, which should not skip the selector check + // empty is true only when v1alpha1.PodSelectorSpec.Nodes and v1alpha1.PodSelectorSpec.NodeSelectors are both empty + empty bool +} + +var _ generic.Selector = &nodeSelector{} + +func (s *nodeSelector) ListOption() client.ListOption { + return nil +} + +func (s *nodeSelector) ListFunc(_ client.Reader) generic.ListFunc { + return nil +} + +func (s *nodeSelector) Match(obj client.Object) bool { + if s.empty { + return true + } + + pod := obj.(*v1.Pod) + for _, node := range s.nodes { + if node.Name == pod.Spec.NodeName { + return true + } + } + return false +} + +// if both setting Nodes and NodeSelectors, the node list will be combined. +func newNodeSelector(ctx context.Context, c client.Client, spec v1alpha1.PodSelectorSpec) (generic.Selector, error) { + if len(spec.Nodes) == 0 && len(spec.NodeSelectors) == 0 { + return &nodeSelector{empty: true}, nil + } + var nodes []v1.Node + if len(spec.Nodes) > 0 { + for _, name := range spec.Nodes { + var node v1.Node + if err := c.Get(ctx, types.NamespacedName{Name: name}, &node); err != nil { + return nil, err + } + nodes = append(nodes, node) + } + } + if len(spec.NodeSelectors) > 0 { + var nodeList v1.NodeList + if err := c.List(ctx, &nodeList, &client.ListOptions{ + LabelSelector: labels.SelectorFromSet(spec.NodeSelectors), + }); err != nil { + return nil, err + } + nodes = append(nodes, nodeList.Items...) + } + return &nodeSelector{nodes: nodes}, nil +} diff --git a/pkg/selector/pod/node_selector_test.go b/pkg/selector/pod/node_selector_test.go new file mode 100644 index 0000000000..533334abfc --- /dev/null +++ b/pkg/selector/pod/node_selector_test.go @@ -0,0 +1,84 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package pod + +import ( + "testing" + + . "github.com/onsi/gomega" + v1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" + . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" +) + +func TestFilterPodByNode(t *testing.T) { + g := NewGomegaWithT(t) + + pods := []v1.Pod{ + NewPod(PodArg{Name: "p1", Namespace: "n1", Nodename: "node1"}), + NewPod(PodArg{Name: "p2", Namespace: "n2", Nodename: "node1"}), + NewPod(PodArg{Name: "p3", Namespace: "n2", Nodename: "node2"}), + NewPod(PodArg{Name: "p4", Namespace: "n4", Nodename: "node3"}), + } + + nodes := []v1.Node{ + NewNode("node1", map[string]string{"disktype": "ssd", "zone": "az1"}), + NewNode("node2", map[string]string{"disktype": "hdd", "zone": "az1"}), + } + + node1AndNode2Selector := &nodeSelector{nodes: nodes} + emptyNodeSelector := &nodeSelector{empty: true} + noNodeSelector := &nodeSelector{} + + tcs := []struct { + name string + pod v1.Pod + selector generic.Selector + match bool + }{ + { + name: "filter pods from node1 and node2", + pod: pods[0], + selector: node1AndNode2Selector, + match: true, + }, { + name: "filter pods from node1 and node2", + pod: pods[2], + selector: node1AndNode2Selector, + match: true, + }, { + name: "filter pods from node1 and node2", + pod: pods[3], + selector: node1AndNode2Selector, + match: false, + }, { + name: "empty filter", + pod: pods[0], + selector: emptyNodeSelector, + match: true, + }, { + name: "filter no nodes", + pod: pods[0], + selector: noNodeSelector, + match: false, + }, + } + + for _, tc := range tcs { + g.Expect(tc.selector.Match(&tc.pod)).To(Equal(tc.match), tc.name) + } +} diff --git a/pkg/selector/pod/phase_selector.go b/pkg/selector/pod/phase_selector.go new file mode 100644 index 0000000000..80e0c63db8 --- /dev/null +++ b/pkg/selector/pod/phase_selector.go @@ -0,0 +1,99 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package pod + +import ( + "strings" + + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" +) + +const phaseSelectorName = "phase" + +type phaseSelector struct { + reqIncl []labels.Requirement + reqExcl []labels.Requirement +} + +var _ generic.Selector = &phaseSelector{} + +func (s *phaseSelector) ListOption() client.ListOption { + return nil +} + +func (s *phaseSelector) ListFunc(_ client.Reader) generic.ListFunc { + return nil +} + +func (s *phaseSelector) Match(obj client.Object) bool { + included := len(s.reqIncl) == 0 + pod := obj.(*v1.Pod) + selector := labels.Set{string(pod.Status.Phase): ""} + + // include pod if one including requirement matches + for _, req := range s.reqIncl { + if req.Matches(selector) { + included = true + break + } + } + + // exclude pod if it is filtered out by at least one excluding requirement + for _, req := range s.reqExcl { + if !req.Matches(selector) { + return false + } + } + + return included +} + +func newPhaseSelector(spec v1alpha1.PodSelectorSpec) (generic.Selector, error) { + selectorStr := strings.Join(spec.PodPhaseSelectors, ",") + selector, err := labels.Parse(selectorStr) + if err != nil { + return nil, err + } + + reqs, _ := selector.Requirements() + var ( + reqIncl []labels.Requirement + reqExcl []labels.Requirement + ) + + for _, req := range reqs { + switch req.Operator() { + case selection.Exists: + reqIncl = append(reqIncl, req) + case selection.DoesNotExist: + reqExcl = append(reqExcl, req) + default: + return nil, errors.Errorf("unsupported operator: %s", req.Operator()) + } + } + + return &phaseSelector{ + reqIncl: reqIncl, + reqExcl: reqExcl, + }, nil +} diff --git a/pkg/selector/pod/phase_selector_test.go b/pkg/selector/pod/phase_selector_test.go new file mode 100644 index 0000000000..59d235a077 --- /dev/null +++ b/pkg/selector/pod/phase_selector_test.go @@ -0,0 +1,111 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package pod + +import ( + "testing" + + . "github.com/onsi/gomega" + v1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" + . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" +) + +func TestPhaseSelectorMatch(t *testing.T) { + g := NewGomegaWithT(t) + + runningSelector, err := newPhaseSelector(v1alpha1.PodSelectorSpec{PodPhaseSelectors: []string{string(v1.PodRunning)}}) + g.Expect(err).ShouldNot(HaveOccurred()) + + emptySelector, err := newPhaseSelector(v1alpha1.PodSelectorSpec{}) + g.Expect(err).ShouldNot(HaveOccurred()) + + runningAndPendingSelector, err := newPhaseSelector(v1alpha1.PodSelectorSpec{PodPhaseSelectors: []string{string(v1.PodRunning), string(v1.PodPending)}}) + g.Expect(err).ShouldNot(HaveOccurred()) + + failedSelector, err := newPhaseSelector(v1alpha1.PodSelectorSpec{PodPhaseSelectors: []string{string(v1.PodFailed)}}) + g.Expect(err).ShouldNot(HaveOccurred()) + + unknownSelector, err := newPhaseSelector(v1alpha1.PodSelectorSpec{PodPhaseSelectors: []string{string(v1.PodUnknown)}}) + g.Expect(err).ShouldNot(HaveOccurred()) + + pods := []v1.Pod{ + NewPod(PodArg{Name: "p1", Status: v1.PodRunning}), + NewPod(PodArg{Name: "p2", Status: v1.PodRunning}), + NewPod(PodArg{Name: "p3", Status: v1.PodPending}), + NewPod(PodArg{Name: "p4", Status: v1.PodFailed}), + } + + tcs := []struct { + name string + pod v1.Pod + selector generic.Selector + match bool + }{ + { + name: "filter running pod, exist running pod", + pod: pods[0], + selector: runningSelector, + match: true, + }, { + name: "filter running pod, not exist running pod", + pod: pods[2], + selector: runningSelector, + match: false, + }, { + name: "empty filter", + pod: pods[0], + selector: emptySelector, + match: true, + }, { + name: "filter running and pending", + pod: pods[0], + selector: runningAndPendingSelector, + match: true, + }, { + name: "filter running and pending", + pod: pods[2], + selector: runningAndPendingSelector, + match: true, + }, { + name: "filter running and pending", + pod: pods[3], + selector: runningAndPendingSelector, + match: false, + }, { + name: "filter failed", + pod: pods[3], + selector: failedSelector, + match: true, + }, { + name: "filter failed", + pod: pods[0], + selector: failedSelector, + match: false, + }, { + name: "filter unknown", + pod: pods[0], + selector: unknownSelector, + match: false, + }, + } + + for _, tc := range tcs { + g.Expect(tc.selector.Match(&tc.pod)).To(Equal(tc.match), tc.name) + } +} diff --git a/pkg/selector/pod/selector.go b/pkg/selector/pod/selector.go new file mode 100644 index 0000000000..5c0471b48a --- /dev/null +++ b/pkg/selector/pod/selector.go @@ -0,0 +1,319 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package pod + +import ( + "context" + + "github.com/pkg/errors" + "go.uber.org/fx" + v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/pkg/log" + "github.com/chaos-mesh/chaos-mesh/pkg/mock" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic" + genericannotation "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic/annotation" + genericfield "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic/field" + genericlabel "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic/label" + genericnamespace "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic/namespace" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/generic/registry" +) + +var ErrNoPodSelected = errors.New("no pod is selected") + +type SelectImpl struct { + c client.Client + r client.Reader + + generic.Option +} + +type Pod struct { + v1.Pod +} + +func (pod *Pod) Id() string { + return (types.NamespacedName{ + Name: pod.Name, + Namespace: pod.Namespace, + }).String() +} + +func (impl *SelectImpl) Select(ctx context.Context, ps *v1alpha1.PodSelector) ([]*Pod, error) { + if ps == nil { + return []*Pod{}, nil + } + + pods, err := SelectAndFilterPods(ctx, impl.c, impl.r, ps, impl.ClusterScoped, impl.TargetNamespace, impl.EnableFilterNamespace) + if err != nil { + return nil, err + } + + var result []*Pod + for _, pod := range pods { + result = append(result, &Pod{ + pod, + }) + } + + return result, nil +} + +type Params struct { + fx.In + + Client client.Client + Reader client.Reader `name:"no-cache"` +} + +func New(params Params) *SelectImpl { + return &SelectImpl{ + params.Client, + params.Reader, + generic.Option{ + ClusterScoped: config.ControllerCfg.ClusterScoped, + TargetNamespace: config.ControllerCfg.TargetNamespace, + EnableFilterNamespace: config.ControllerCfg.EnableFilterNamespace, + }, + } +} + +// SelectAndFilterPods returns the list of pods that filtered by selector and SelectorMode +// Deprecated: use pod.SelectImpl as instead +func SelectAndFilterPods(ctx context.Context, c client.Client, r client.Reader, spec *v1alpha1.PodSelector, clusterScoped bool, targetNamespace string, enableFilterNamespace bool) ([]v1.Pod, error) { + if pods := mock.On("MockSelectAndFilterPods"); pods != nil { + return pods.(func() []v1.Pod)(), nil + } + if err := mock.On("MockSelectedAndFilterPodsError"); err != nil { + return nil, err.(error) + } + + selector := spec.Selector + mode := spec.Mode + value := spec.Value + + pods, err := SelectPods(ctx, c, r, selector, clusterScoped, targetNamespace, enableFilterNamespace) + if err != nil { + return nil, err + } + + if len(pods) == 0 { + return nil, ErrNoPodSelected + } + + filteredPod, err := filterPodsByMode(pods, mode, value) + if err != nil { + return nil, err + } + + return filteredPod, nil +} + +//revive:disable:flag-parameter + +// SelectPods returns the list of pods that are available for pod chaos action. +// It returns all pods that match the configured label, annotation and namespace selectors. +// If pods are specifically specified by `selector.Pods`, it just returns the selector.Pods. +func SelectPods(ctx context.Context, c client.Client, r client.Reader, selector v1alpha1.PodSelectorSpec, clusterScoped bool, targetNamespace string, enableFilterNamespace bool) ([]v1.Pod, error) { + // pods are specifically specified + if len(selector.Pods) > 0 { + return selectSpecifiedPods(ctx, c, selector, clusterScoped, targetNamespace, enableFilterNamespace) + } + + selectorRegistry := newSelectorRegistry(ctx, c, selector) + selectorChain, err := registry.Parse(selectorRegistry, selector.GenericSelectorSpec, generic.Option{ + ClusterScoped: clusterScoped, + TargetNamespace: targetNamespace, + EnableFilterNamespace: enableFilterNamespace, + }) + if err != nil { + return nil, err + } + + return listPods(ctx, c, r, selector, selectorChain, enableFilterNamespace) +} + +func selectSpecifiedPods(ctx context.Context, c client.Client, spec v1alpha1.PodSelectorSpec, + clusterScoped bool, targetNamespace string, enableFilterNamespace bool) ([]v1.Pod, error) { + var pods []v1.Pod + namespaceCheck := make(map[string]bool) + logger, err := log.NewDefaultZapLogger() + if err != nil { + return pods, errors.Wrap(err, "failed to create logger") + } + for ns, names := range spec.Pods { + if !clusterScoped { + if targetNamespace != ns { + log.L().WithName("pod-selector").Info("skip namespace because ns is out of scope within namespace scoped mode", "namespace", ns) + continue + } + } + + if enableFilterNamespace { + allow, ok := namespaceCheck[ns] + if !ok { + allow = genericnamespace.CheckNamespace(ctx, c, ns, logger) + namespaceCheck[ns] = allow + } + if !allow { + continue + } + } + for _, name := range names { + var pod v1.Pod + err := c.Get(ctx, types.NamespacedName{ + Namespace: ns, + Name: name, + }, &pod) + if err == nil { + pods = append(pods, pod) + continue + } + + if apierrors.IsNotFound(err) { + log.L().WithName("pod-selector").Info("pod is not found, skip it", "namespace", ns, "pod name", name) + continue + } + + return nil, err + } + } + return pods, nil +} + +//revive:enable:flag-parameter + +// CheckPodMeetSelector checks if this pod meets the selection criteria. +func CheckPodMeetSelector(ctx context.Context, c client.Client, pod v1.Pod, selector v1alpha1.PodSelectorSpec, clusterScoped bool, targetNamespace string, enableFilterNamespace bool) (bool, error) { + if len(selector.Pods) > 0 { + meet := false + for ns, names := range selector.Pods { + if pod.Namespace != ns { + continue + } + + for _, name := range names { + if pod.Name == name { + meet = true + } + } + + if !meet { + return false, nil + } + } + } + + selectorRegistry := newSelectorRegistry(ctx, c, selector) + selectorChain, err := registry.Parse(selectorRegistry, selector.GenericSelectorSpec, generic.Option{ + ClusterScoped: clusterScoped, + TargetNamespace: targetNamespace, + EnableFilterNamespace: enableFilterNamespace, + }) + if err != nil { + return false, err + } + + return selectorChain.Match(&pod), nil +} + +func newSelectorRegistry(ctx context.Context, c client.Client, spec v1alpha1.PodSelectorSpec) registry.Registry { + return map[string]registry.SelectorFactory{ + genericlabel.Name: genericlabel.New, + genericnamespace.Name: genericnamespace.New, + genericfield.Name: genericfield.New, + genericannotation.Name: genericannotation.New, + nodeSelectorName: func(selector v1alpha1.GenericSelectorSpec, _ generic.Option) (generic.Selector, error) { + return newNodeSelector(ctx, c, spec) + }, + phaseSelectorName: func(selector v1alpha1.GenericSelectorSpec, _ generic.Option) (generic.Selector, error) { + return newPhaseSelector(spec) + }, + } +} + +func listPods(ctx context.Context, c client.Client, r client.Reader, spec v1alpha1.PodSelectorSpec, + selectorChain generic.SelectorChain, enableFilterNamespace bool) ([]v1.Pod, error) { + var pods []v1.Pod + namespaceCheck := make(map[string]bool) + logger, err := log.NewDefaultZapLogger() + if err != nil { + return pods, errors.Wrap(err, "failed to create logger") + } + if err := selectorChain.ListObjects(c, r, + func(listFunc generic.ListFunc, opts client.ListOptions) error { + var podList v1.PodList + if len(spec.Namespaces) > 0 { + for _, namespace := range spec.Namespaces { + if enableFilterNamespace { + allow, ok := namespaceCheck[namespace] + if !ok { + allow = genericnamespace.CheckNamespace(ctx, c, namespace, logger) + namespaceCheck[namespace] = allow + } + if !allow { + continue + } + } + + opts.Namespace = namespace + if err := listFunc(ctx, &podList, &opts); err != nil { + return err + } + pods = append(pods, podList.Items...) + } + } else { + // in fact, this will never happen + if err := listFunc(ctx, &podList, &opts); err != nil { + return err + } + pods = append(pods, podList.Items...) + } + return nil + }); err != nil { + return nil, err + } + + filterPods := make([]v1.Pod, 0, len(pods)) + for _, pod := range pods { + pod := pod + if selectorChain.Match(&pod) { + filterPods = append(filterPods, pod) + } + } + return filterPods, nil +} + +// filterPodsByMode filters pods by mode from pod list +func filterPodsByMode(pods []v1.Pod, mode v1alpha1.SelectorMode, value string) ([]v1.Pod, error) { + indexes, err := generic.FilterObjectsByMode(mode, value, len(pods)) + if err != nil { + return nil, err + } + + var filteredPods []v1.Pod + + for _, index := range indexes { + index := index + filteredPods = append(filteredPods, pods[index]) + } + return filteredPods, nil +} diff --git a/pkg/selector/pod/selector_test.go b/pkg/selector/pod/selector_test.go new file mode 100644 index 0000000000..aa8251eca2 --- /dev/null +++ b/pkg/selector/pod/selector_test.go @@ -0,0 +1,443 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package pod + +import ( + "context" + "testing" + + . "github.com/onsi/gomega" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" +) + +func TestSelectPods(t *testing.T) { + g := NewGomegaWithT(t) + + objects, pods := GenerateNPods("p", 5, PodArg{Labels: map[string]string{"l1": "l1"}, Nodename: "az1-node1"}) + objects2, pods2 := GenerateNPods("s", 2, PodArg{Namespace: "test-s", Labels: map[string]string{"l2": "l2"}, Nodename: "az2-node1"}) + + objects3, _ := GenerateNNodes("az1-node", 3, map[string]string{"disktype": "ssd", "zone": "az1"}) + objects4, _ := GenerateNNodes("az2-node", 2, map[string]string{"disktype": "hdd", "zone": "az2"}) + + objects = append(objects, objects2...) + objects = append(objects, objects3...) + objects = append(objects, objects4...) + + pods = append(pods, pods2...) + + c := fake.NewClientBuilder(). + WithRuntimeObjects(objects...). + Build() + var r client.Reader + + type TestCase struct { + name string + selector v1alpha1.PodSelectorSpec + expectedPods []v1.Pod + } + + tcs := []TestCase{ + { + name: "filter specified pods", + selector: v1alpha1.PodSelectorSpec{ + Pods: map[string][]string{ + metav1.NamespaceDefault: {"p3", "p4"}, + "test-s": {"s1"}, + }, + }, + expectedPods: []v1.Pod{pods[3], pods[4], pods[6]}, + }, + { + name: "filter labels pods", + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + LabelSelectors: map[string]string{"l2": "l2"}, + }, + }, + expectedPods: []v1.Pod{pods[5], pods[6]}, + }, + { + name: "filter pods by label expressions", + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + ExpressionSelectors: []metav1.LabelSelectorRequirement{ + { + Key: "l2", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"l2"}, + }, + }, + }, + }, + expectedPods: []v1.Pod{pods[5], pods[6]}, + }, + { + name: "filter pods by label selectors and expression selectors", + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + LabelSelectors: map[string]string{"l1": "l1"}, + ExpressionSelectors: []metav1.LabelSelectorRequirement{ + { + Key: "l2", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"l2"}, + }, + }, + }, + }, + expectedPods: nil, + }, + { + name: "filter namespace and labels", + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{"test-s"}, + LabelSelectors: map[string]string{"l2": "l2"}, + }, + }, + expectedPods: []v1.Pod{pods[5], pods[6]}, + }, + { + name: "filter namespace and labels", + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{metav1.NamespaceDefault}, + LabelSelectors: map[string]string{"l2": "l2"}, + }, + }, + expectedPods: nil, + }, + { + name: "filter by specified node", + selector: v1alpha1.PodSelectorSpec{ + Nodes: []string{"az1-node1"}, + }, + expectedPods: []v1.Pod{pods[0], pods[1], pods[2], pods[3], pods[4]}, + }, + { + name: "filter node and labels", + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + LabelSelectors: map[string]string{"l1": "l1"}, + }, + Nodes: []string{"az2-node1"}, + }, + expectedPods: nil, + }, + { + name: "filter pods by nodeSelector", + selector: v1alpha1.PodSelectorSpec{ + NodeSelectors: map[string]string{"disktype": "hdd"}, + }, + expectedPods: []v1.Pod{pods[5], pods[6]}, + }, + { + name: "filter pods by node and nodeSelector", + selector: v1alpha1.PodSelectorSpec{ + NodeSelectors: map[string]string{"zone": "az1"}, + Nodes: []string{"az2-node1"}, + }, + expectedPods: []v1.Pod{pods[0], pods[1], pods[2], pods[3], pods[4], pods[5], pods[6]}, + }, + } + + var ( + testCfgClusterScoped = true + testCfgTargetNamespace = "" + ) + + for _, tc := range tcs { + filteredPods, err := SelectPods(context.Background(), c, r, tc.selector, testCfgClusterScoped, testCfgTargetNamespace, false) + g.Expect(err).ShouldNot(HaveOccurred(), tc.name) + g.Expect(len(filteredPods)).To(Equal(len(tc.expectedPods)), tc.name) + } +} + +func TestCheckPodMeetSelector(t *testing.T) { + g := NewGomegaWithT(t) + + objects, _ := GenerateNNodes("az1-node", 3, map[string]string{"disktype": "ssd", "zone": "az1"}) + objects2, _ := GenerateNNodes("az2-node", 2, map[string]string{"disktype": "hdd", "zone": "az2"}) + objects = append(objects, objects2...) + + c := fake.NewClientBuilder().WithRuntimeObjects(objects...).Build() + + type TestCase struct { + name string + selector v1alpha1.PodSelectorSpec + pod v1.Pod + expectedValue bool + } + + tcs := []TestCase{ + { + name: "meet label", + pod: NewPod(PodArg{Name: "t1", Status: v1.PodPending, Labels: map[string]string{"app": "tikv", "ss": "t1"}}), + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + LabelSelectors: map[string]string{"app": "tikv"}, + }, + }, + expectedValue: true, + }, + { + name: "not meet label", + pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb", "ss": "t1"}}), + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + LabelSelectors: map[string]string{"app": "tikv"}, + }, + }, + expectedValue: false, + }, + { + name: "pod labels is empty", + pod: NewPod(PodArg{Name: "t1"}), + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + LabelSelectors: map[string]string{"app": "tikv"}, + }, + }, + expectedValue: false, + }, + { + name: "selector is empty", + pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}), + selector: v1alpha1.PodSelectorSpec{}, + expectedValue: true, + }, + { + name: "meet labels and meet expressions", + pod: NewPod(PodArg{Name: "t1", Status: v1.PodPending, Labels: map[string]string{"app": "tikv", "ss": "t1"}}), + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + LabelSelectors: map[string]string{"app": "tikv"}, + ExpressionSelectors: []metav1.LabelSelectorRequirement{ + { + Key: "ss", + Operator: metav1.LabelSelectorOpExists, + }, + }, + }, + }, + expectedValue: true, + }, + { + name: "meet labels and not meet expressions", + pod: NewPod(PodArg{Name: "t1", Status: v1.PodPending, Labels: map[string]string{"app": "tikv", "ss": "t1"}}), + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + LabelSelectors: map[string]string{"app": "tikv"}, + ExpressionSelectors: []metav1.LabelSelectorRequirement{ + { + Key: "ss", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"t1"}, + }, + }, + }, + }, + expectedValue: false, + }, + { + name: "meet namespace", + pod: NewPod(PodArg{Name: "t1"}), + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{metav1.NamespaceDefault}, + }, + }, + expectedValue: true, + }, + { + name: "meet namespace and meet labels", + pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tikv"}}), + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{metav1.NamespaceDefault}, + LabelSelectors: map[string]string{"app": "tikv"}, + }, + }, + expectedValue: true, + }, + { + name: "meet namespace and not meet labels", + pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}), + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{metav1.NamespaceDefault}, + LabelSelectors: map[string]string{"app": "tikv"}, + }, + }, + expectedValue: false, + }, + { + name: "meet pods", + pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}), + selector: v1alpha1.PodSelectorSpec{ + Pods: map[string][]string{ + metav1.NamespaceDefault: {"t1"}, + }, + }, + expectedValue: true, + }, + { + name: "meet annotation", + pod: NewPod(PodArg{Name: "t1", Ans: map[string]string{"an": "n1", "an2": "n2"}, Labels: map[string]string{"app": "tidb"}}), + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{metav1.NamespaceDefault}, + AnnotationSelectors: map[string]string{ + "an": "n1", + }, + }, + }, + expectedValue: true, + }, + { + name: "not meet annotation", + pod: NewPod(PodArg{Name: "t1", Ans: map[string]string{"an": "n1"}, Labels: map[string]string{"app": "tidb"}}), + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{metav1.NamespaceDefault}, + AnnotationSelectors: map[string]string{ + "an": "n2", + }, + }, + }, + expectedValue: false, + }, + { + name: "meet field", + pod: NewPod(PodArg{Name: "t1"}), + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + FieldSelectors: map[string]string{"metadata.name": "t1"}, + }, + }, + expectedValue: true, + }, + { + name: "not meet field", + pod: NewPod(PodArg{Name: "t2"}), + selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + FieldSelectors: map[string]string{"metadata.name": "t1"}, + }, + }, + expectedValue: false, + }, + { + name: "meet node", + pod: NewPod(PodArg{Name: "t1", Nodename: "az1-node1"}), + selector: v1alpha1.PodSelectorSpec{ + Nodes: []string{"az1-node0", "az1-node1"}, + }, + expectedValue: true, + }, + { + name: "not meet node", + pod: NewPod(PodArg{Name: "t1", Nodename: "az2-node1"}), + selector: v1alpha1.PodSelectorSpec{ + Nodes: []string{"az1-node0", "az1-node1"}, + }, + expectedValue: false, + }, + { + name: "meet node selector", + pod: NewPod(PodArg{Name: "t1", Nodename: "az1-node1"}), + selector: v1alpha1.PodSelectorSpec{ + NodeSelectors: map[string]string{"disktype": "ssd"}, + }, + expectedValue: true, + }, + { + name: "not meet node selector", + pod: NewPod(PodArg{Name: "t1", Nodename: "az2-node1"}), + selector: v1alpha1.PodSelectorSpec{ + NodeSelectors: map[string]string{"disktype": "ssd"}, + }, + expectedValue: false, + }, { + name: "meet node selector or node name", + pod: NewPod(PodArg{Name: "t1", Nodename: "az2-node1"}), + selector: v1alpha1.PodSelectorSpec{ + Nodes: []string{"az2-node1"}, + NodeSelectors: map[string]string{"disktype": "ssd"}, + }, + expectedValue: true, + }, + { + name: "not meet node selector and node name", + pod: NewPod(PodArg{Name: "t1", Nodename: "az2-node1"}), + selector: v1alpha1.PodSelectorSpec{ + Nodes: []string{"az2-node0"}, + NodeSelectors: map[string]string{"disktype": "ssd"}, + }, + expectedValue: false, + }, + { + name: "meet pod selector", + pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}), + selector: v1alpha1.PodSelectorSpec{ + Pods: map[string][]string{ + metav1.NamespaceDefault: {"t1", "t2"}, + }, + }, + expectedValue: true, + }, + { + name: "not meet pod selector", + pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}), + selector: v1alpha1.PodSelectorSpec{ + Pods: map[string][]string{ + metav1.NamespaceDefault: {"t2"}, + }, + }, + expectedValue: false, + }, + { + name: "meet pod selector and not meet labels", + pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}), + selector: v1alpha1.PodSelectorSpec{ + Pods: map[string][]string{ + metav1.NamespaceDefault: {"t1", "t2"}, + }, + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + LabelSelectors: map[string]string{"app": "tikv"}, + }, + }, + expectedValue: false, + }, + } + + var ( + testCfgClusterScoped = true + testCfgTargetNamespace = "" + ) + + for _, tc := range tcs { + meet, err := CheckPodMeetSelector(context.Background(), c, tc.pod, tc.selector, testCfgClusterScoped, testCfgTargetNamespace, false) + g.Expect(err).ShouldNot(HaveOccurred(), tc.name) + g.Expect(meet).To(Equal(tc.expectedValue), tc.name) + } +} diff --git a/pkg/selector/selector.go b/pkg/selector/selector.go index 64fd760f27..d64ab8aa0e 100644 --- a/pkg/selector/selector.go +++ b/pkg/selector/selector.go @@ -1,643 +1,107 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package selector import ( "context" - "errors" - "fmt" - "math" - "math/rand" - "strconv" - "strings" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/label" - "github.com/chaos-mesh/chaos-mesh/pkg/mock" - - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - v1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/selection" - "k8s.io/apimachinery/pkg/types" + "reflect" + + "github.com/pkg/errors" + "go.uber.org/fx" + + "github.com/chaos-mesh/chaos-mesh/pkg/selector/aws" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/azure" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/container" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/gcp" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/nodevolumepath" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/physicalmachine" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/pod" ) -var log = ctrl.Log.WithName("selector") - -const injectAnnotationKey = "chaos-mesh.org/inject" - -type SelectSpec interface { - GetSelector() v1alpha1.SelectorSpec - GetMode() v1alpha1.PodMode - GetValue() string -} - -// SelectAndFilterPods returns the list of pods that filtered by selector and PodMode -func SelectAndFilterPods(ctx context.Context, c client.Client, r client.Reader, spec SelectSpec, clusterScoped bool, targetNamespace string, enableFilterNamespace bool) ([]v1.Pod, error) { - if pods := mock.On("MockSelectAndFilterPods"); pods != nil { - return pods.(func() []v1.Pod)(), nil - } - if err := mock.On("MockSelectedAndFilterPodsError"); err != nil { - return nil, err.(error) - } - - selector := spec.GetSelector() - mode := spec.GetMode() - value := spec.GetValue() - - pods, err := SelectPods(ctx, c, r, selector, clusterScoped, targetNamespace, enableFilterNamespace) - if err != nil { - return nil, err - } - - if len(pods) == 0 { - err = errors.New("no pod is selected") - return nil, err - } - - filteredPod, err := filterPodsByMode(pods, mode, value) - if err != nil { - return nil, err - } - - return filteredPod, nil -} - -//revive:disable:flag-parameter - -// SelectPods returns the list of pods that are available for pod chaos action. -// It returns all pods that match the configured label, annotation and namespace selectors. -// If pods are specifically specified by `selector.Pods`, it just returns the selector.Pods. -func SelectPods(ctx context.Context, c client.Client, r client.Reader, selector v1alpha1.SelectorSpec, clusterScoped bool, targetNamespace string, enableFilterNamespace bool) ([]v1.Pod, error) { - // TODO: refactor: make different selectors to replace if-else logics - var pods []v1.Pod - - // pods are specifically specified - if len(selector.Pods) > 0 { - for ns, names := range selector.Pods { - if !clusterScoped { - if targetNamespace != ns { - log.Info("skip namespace because ns is out of scope within namespace scoped mode", "namespace", ns) - continue - } - } - for _, name := range names { - var pod v1.Pod - err := c.Get(ctx, types.NamespacedName{ - Namespace: ns, - Name: name, - }, &pod) - if err == nil { - pods = append(pods, pod) - continue - } - - if apierrors.IsNotFound(err) { - log.Error(err, "Pod is not found", "namespace", ns, "pod name", name) - continue - } - - return nil, err - } - } - - return pods, nil - } - - if !clusterScoped { - if len(selector.Namespaces) > 1 { - return nil, fmt.Errorf("could NOT use more than 1 namespace selector within namespace scoped mode") - } else if len(selector.Namespaces) == 1 { - if selector.Namespaces[0] != targetNamespace { - return nil, fmt.Errorf("could NOT list pods from out of scoped namespace: %s", selector.Namespaces[0]) - } - } - } - - var listOptions = client.ListOptions{} - if !clusterScoped { - listOptions.Namespace = targetNamespace - } - if len(selector.LabelSelectors) > 0 || len(selector.ExpressionSelectors) > 0 { - metav1Ls := &metav1.LabelSelector{ - MatchLabels: selector.LabelSelectors, - MatchExpressions: selector.ExpressionSelectors, - } - ls, err := metav1.LabelSelectorAsSelector(metav1Ls) - if err != nil { - return nil, err - } - listOptions.LabelSelector = ls - } - - listFunc := c.List - - if len(selector.FieldSelectors) > 0 { - listOptions.FieldSelector = fields.SelectorFromSet(selector.FieldSelectors) - - // Since FieldSelectors need to implement index creation, Reader.List is used to get the pod list. - // Otherwise, just call Client.List directly, which can be obtained through cache. - if r != nil { - listFunc = r.List - } - } - - var podList v1.PodList - if len(selector.Namespaces) > 0 { - for _, namespace := range selector.Namespaces { - listOptions.Namespace = namespace - - if err := listFunc(ctx, &podList, &listOptions); err != nil { - return nil, err - } - - pods = append(pods, podList.Items...) - } - } else { - if err := listFunc(ctx, &podList, &listOptions); err != nil { - return nil, err - } - - pods = append(pods, podList.Items...) - } - - var ( - nodes []v1.Node - nodeList v1.NodeList - nodeListOptions = client.ListOptions{} - ) - // if both setting Nodes and NodeSelectors, the node list will be combined. - if len(selector.Nodes) > 0 || len(selector.NodeSelectors) > 0 { - if len(selector.Nodes) > 0 { - for _, nodename := range selector.Nodes { - var node v1.Node - if err := c.Get(ctx, types.NamespacedName{Name: nodename}, &node); err != nil { - return nil, err - } - nodes = append(nodes, node) - } - } - if len(selector.NodeSelectors) > 0 { - nodeListOptions.LabelSelector = labels.SelectorFromSet(selector.NodeSelectors) - if err := c.List(ctx, &nodeList, &nodeListOptions); err != nil { - return nil, err - } - nodes = append(nodes, nodeList.Items...) - } - pods = filterPodByNode(pods, nodes) - } - if enableFilterNamespace { - pods = filterByNamespaces(ctx, c, pods) - } - - namespaceSelector, err := parseSelector(strings.Join(selector.Namespaces, ",")) - if err != nil { - return nil, err - } - pods, err = filterByNamespaceSelector(pods, namespaceSelector) - if err != nil { - return nil, err - } - - annotationsSelector, err := parseSelector(label.Label(selector.AnnotationSelectors).String()) - if err != nil { - return nil, err - } - pods = filterByAnnotations(pods, annotationsSelector) - - phaseSelector, err := parseSelector(strings.Join(selector.PodPhaseSelectors, ",")) - if err != nil { - return nil, err - } - pods, err = filterByPhaseSelector(pods, phaseSelector) - if err != nil { - return nil, err - } - - return pods, nil -} - -//revive:enable:flag-parameter - -// GetService get k8s service by service name -func GetService(ctx context.Context, c client.Client, namespace, controllerNamespace string, serviceName string) (*v1.Service, error) { - // use the environment value if namespace is empty - if len(namespace) == 0 { - namespace = controllerNamespace - } - - service := &v1.Service{} - err := c.Get(ctx, client.ObjectKey{ - Namespace: namespace, - Name: serviceName, - }, service) - if err != nil { - return nil, err - } - - return service, nil -} - -// CheckPodMeetSelector checks if this pod meets the selection criteria. -// TODO: support to check fieldsSelector -func CheckPodMeetSelector(pod v1.Pod, selector v1alpha1.SelectorSpec) (bool, error) { - if len(selector.Pods) > 0 { - meet := false - for ns, names := range selector.Pods { - if pod.Namespace != ns { - continue - } - - for _, name := range names { - if pod.Name == name { - meet = true - } - } - - if !meet { - return false, nil - } - } - } - - // check pod labels. - if pod.Labels == nil { - pod.Labels = make(map[string]string) - } - - if selector.LabelSelectors == nil { - selector.LabelSelectors = make(map[string]string) - } - - if len(selector.LabelSelectors) > 0 || len(selector.ExpressionSelectors) > 0 { - metav1Ls := &metav1.LabelSelector{ - MatchLabels: selector.LabelSelectors, - MatchExpressions: selector.ExpressionSelectors, - } - ls, err := metav1.LabelSelectorAsSelector(metav1Ls) - if err != nil { - return false, err - } - podLabels := labels.Set(pod.Labels) - if len(pod.Labels) == 0 || !ls.Matches(podLabels) { - return false, nil - } - } - - pods := []v1.Pod{pod} - - namespaceSelector, err := parseSelector(strings.Join(selector.Namespaces, ",")) - if err != nil { - return false, err - } - - pods, err = filterByNamespaceSelector(pods, namespaceSelector) - if err != nil { - return false, err - } - - annotationsSelector, err := parseSelector(label.Label(selector.AnnotationSelectors).String()) - if err != nil { - return false, err - } - - pods = filterByAnnotations(pods, annotationsSelector) - - phaseSelector, err := parseSelector(strings.Join(selector.PodPhaseSelectors, ",")) - if err != nil { - return false, err - } - pods, err = filterByPhaseSelector(pods, phaseSelector) - if err != nil { - return false, err - } - - if len(pods) > 0 { - return true, nil - } - - return false, nil +type Selector struct { + selectorMap map[reflect.Type]interface{} } -func filterPodByNode(pods []v1.Pod, nodes []v1.Node) []v1.Pod { - if len(nodes) == 0 { - return nil - } - var filteredList []v1.Pod - for _, pod := range pods { - for _, node := range nodes { - if pod.Spec.NodeName == node.Name { - filteredList = append(filteredList, pod) - } - } - } - return filteredList +type Target interface { + Id() string } -// filterPodsByMode filters pods by mode from pod list -func filterPodsByMode(pods []v1.Pod, mode v1alpha1.PodMode, value string) ([]v1.Pod, error) { - if len(pods) == 0 { - return nil, errors.New("cannot generate pods from empty list") +func (s *Selector) Select(ctx context.Context, spec interface{}) ([]Target, error) { + if spec == nil { + return []Target{}, nil } - switch mode { - case v1alpha1.OnePodMode: - index := rand.Intn(len(pods)) - pod := pods[index] - - return []v1.Pod{pod}, nil - case v1alpha1.AllPodMode: - return pods, nil - case v1alpha1.FixedPodMode: - num, err := strconv.Atoi(value) - if err != nil { - return nil, err - } - - if len(pods) < num { - num = len(pods) - } - - if num <= 0 { - return nil, errors.New("cannot select any pod as value below or equal 0") - } - - return getFixedSubListFromPodList(pods, num), nil - case v1alpha1.FixedPercentPodMode: - percentage, err := strconv.Atoi(value) - if err != nil { - return nil, err - } - - if percentage == 0 { - return nil, errors.New("cannot select any pod as value below or equal 0") - } - - if percentage < 0 || percentage > 100 { - return nil, fmt.Errorf("fixed percentage value of %d is invalid, Must be (0,100]", percentage) - } - - num := int(math.Floor(float64(len(pods)) * float64(percentage) / 100)) - - return getFixedSubListFromPodList(pods, num), nil - case v1alpha1.RandomMaxPercentPodMode: - maxPercentage, err := strconv.Atoi(value) - if err != nil { - return nil, err - } + var targets []Target + impl, ok := s.selectorMap[reflect.TypeOf(spec)] + if ok { + vals := reflect.ValueOf(impl).MethodByName("Select").Call([]reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(spec)}) + ret := vals[0] - if maxPercentage == 0 { - return nil, errors.New("cannot select any pod as value below or equal 0") + for i := 0; i < ret.Len(); i++ { + targets = append(targets, ret.Index(i).Interface().(Target)) } - if maxPercentage < 0 || maxPercentage > 100 { - return nil, fmt.Errorf("fixed percentage value of %d is invalid, Must be [0-100]", maxPercentage) + err := vals[1].Interface() + if err == nil { + return targets, nil } - percentage := rand.Intn(maxPercentage + 1) // + 1 because Intn works with half open interval [0,n) and we want [0,n] - num := int(math.Floor(float64(len(pods)) * float64(percentage) / 100)) - - return getFixedSubListFromPodList(pods, num), nil - default: - return nil, fmt.Errorf("mode %s not supported", mode) + return targets, err.(error) } -} -// filterByAnnotations filters a list of pods by a given annotation selector. -func filterByAnnotations(pods []v1.Pod, annotations labels.Selector) []v1.Pod { - // empty filter returns original list - if annotations.Empty() { - return pods - } - - var filteredList []v1.Pod - - for _, pod := range pods { - // convert the pod's annotations to an equivalent label selector - selector := labels.Set(pod.Annotations) - - // include pod if its annotations match the selector - if annotations.Matches(selector) { - filteredList = append(filteredList, pod) - } - } - - return filteredList + return nil, errors.Errorf("specification type not found: %s", reflect.TypeOf(spec)) } -// filterByPhaseSet filters a list of pods by a given PodPhase selector. -func filterByPhaseSelector(pods []v1.Pod, phases labels.Selector) ([]v1.Pod, error) { - if phases.Empty() { - return pods, nil - } - - reqs, _ := phases.Requirements() - var ( - reqIncl []labels.Requirement - reqExcl []labels.Requirement +type SelectorParams struct { + fx.In - filteredList []v1.Pod - ) - - for _, req := range reqs { - switch req.Operator() { - case selection.Exists: - reqIncl = append(reqIncl, req) - case selection.DoesNotExist: - reqExcl = append(reqExcl, req) - default: - return nil, fmt.Errorf("unsupported operator: %s", req.Operator()) - } - } - - for _, pod := range pods { - included := len(reqIncl) == 0 - selector := labels.Set{string(pod.Status.Phase): ""} - - // include pod if one including requirement matches - for _, req := range reqIncl { - if req.Matches(selector) { - included = true - break - } - } - - // exclude pod if it is filtered out by at least one excluding requirement - for _, req := range reqExcl { - if !req.Matches(selector) { - included = false - break - } - } - - if included { - filteredList = append(filteredList, pod) - } - } - - return filteredList, nil + PodSelector *pod.SelectImpl + ContainerSelector *container.SelectImpl + AWSSelector *aws.SelectImpl + AzureSelector *azure.SelectImpl + GCPSelector *gcp.SelectImpl + PhysicalMachineSelector *physicalmachine.SelectImpl + NodeVolumePath *nodevolumepath.SelectImpl } -func filterByNamespaces(ctx context.Context, c client.Client, pods []v1.Pod) []v1.Pod { - var filteredList []v1.Pod - - for _, pod := range pods { - ok, err := IsAllowedNamespaces(ctx, c, pod.Namespace) - if err != nil { - log.Error(err, "fail to check whether this namespace is allowed", "namespace", pod.Namespace) - continue - } +func New(p SelectorParams) *Selector { + selectorMap := make(map[reflect.Type]interface{}) - if ok { - filteredList = append(filteredList, pod) - } else { - log.Info("namespace is not enabled for chaos-mesh", "namespace", pod.Namespace) + val := reflect.ValueOf(p) + for i := 0; i < val.NumField(); i++ { + method := val.Field(i).MethodByName("Select") + if method.IsValid() && method.Type().NumIn() > 1 { + typ := method.Type().In(1) + selectorMap[typ] = val.Field(i).Interface() } } - return filteredList -} - -func IsAllowedNamespaces(ctx context.Context, c client.Client, namespace string) (bool, error) { - ns := &v1.Namespace{} - - err := c.Get(ctx, types.NamespacedName{Name: namespace}, ns) - if err != nil { - return false, err - } - - if ns.Annotations[injectAnnotationKey] == "enabled" { - return true, nil - } - - return false, nil -} - -// filterByNamespaceSelector filters a list of pods by a given namespace selector. -func filterByNamespaceSelector(pods []v1.Pod, namespaces labels.Selector) ([]v1.Pod, error) { - // empty filter returns original list - if namespaces.Empty() { - return pods, nil - } - - // split requirements into including and excluding groups - reqs, _ := namespaces.Requirements() - - var ( - reqIncl []labels.Requirement - reqExcl []labels.Requirement - - filteredList []v1.Pod - ) - - for _, req := range reqs { - switch req.Operator() { - case selection.Exists: - reqIncl = append(reqIncl, req) - case selection.DoesNotExist: - reqExcl = append(reqExcl, req) - default: - return nil, fmt.Errorf("unsupported operator: %s", req.Operator()) - } - } - - for _, pod := range pods { - // if there aren't any including requirements, we're in by default - included := len(reqIncl) == 0 - - // convert the pod's namespace to an equivalent label selector - selector := labels.Set{pod.Namespace: ""} - - // include pod if one including requirement matches - for _, req := range reqIncl { - if req.Matches(selector) { - included = true - break - } - } - - // exclude pod if it is filtered out by at least one excluding requirement - for _, req := range reqExcl { - if !req.Matches(selector) { - included = false - break - } - } - - if included { - filteredList = append(filteredList, pod) - } - } - - return filteredList, nil -} - -func parseSelector(str string) (labels.Selector, error) { - selector, err := labels.Parse(str) - if err != nil { - return nil, err - } - return selector, nil -} - -func getFixedSubListFromPodList(pods []v1.Pod, num int) []v1.Pod { - indexes := RandomFixedIndexes(0, uint(len(pods)), uint(num)) - - var filteredPods []v1.Pod - for _, index := range indexes { - index := index - filteredPods = append(filteredPods, pods[index]) + return &Selector{ + selectorMap, } - - return filteredPods } -// RandomFixedIndexes returns the `count` random indexes between `start` and `end`. -// [start, end) -func RandomFixedIndexes(start, end, count uint) []uint { - var indexes []uint - m := make(map[uint]uint, count) - - if end < start { - return indexes - } +var Module = fx.Provide( + New, - if count > end-start { - for i := start; i < end; i++ { - indexes = append(indexes, i) - } - - return indexes - } - - for i := 0; i < int(count); { - index := uint(rand.Intn(int(end-start))) + start - - _, exist := m[index] - if exist { - continue - } - - m[index] = index - indexes = append(indexes, index) - i++ - } - - return indexes -} + pod.New, + container.New, + aws.New, + azure.New, + gcp.New, + physicalmachine.New, + nodevolumepath.New, +) diff --git a/pkg/selector/selector_test.go b/pkg/selector/selector_test.go deleted file mode 100644 index 2c62b44ff7..0000000000 --- a/pkg/selector/selector_test.go +++ /dev/null @@ -1,682 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package selector - -import ( - "context" - "testing" - - "k8s.io/apimachinery/pkg/runtime" - - . "github.com/onsi/gomega" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/label" - . "github.com/chaos-mesh/chaos-mesh/pkg/testutils" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" -) - -func TestSelectPods(t *testing.T) { - g := NewGomegaWithT(t) - - objects, pods := GenerateNPods("p", 5, PodArg{Labels: map[string]string{"l1": "l1"}, Nodename: "az1-node1"}) - objects2, pods2 := GenerateNPods("s", 2, PodArg{Namespace: "test-s", Labels: map[string]string{"l2": "l2"}, Nodename: "az2-node1"}) - - objects3, _ := GenerateNNodes("az1-node", 3, map[string]string{"disktype": "ssd", "zone": "az1"}) - objects4, _ := GenerateNNodes("az2-node", 2, map[string]string{"disktype": "hdd", "zone": "az2"}) - - objects = append(objects, objects2...) - objects = append(objects, objects3...) - objects = append(objects, objects4...) - - pods = append(pods, pods2...) - - c := fake.NewFakeClient(objects...) - var r client.Reader - - type TestCase struct { - name string - selector v1alpha1.SelectorSpec - expectedPods []v1.Pod - } - - tcs := []TestCase{ - { - name: "filter specified pods", - selector: v1alpha1.SelectorSpec{ - Pods: map[string][]string{ - metav1.NamespaceDefault: {"p3", "p4"}, - "test-s": {"s1"}, - }, - }, - expectedPods: []v1.Pod{pods[3], pods[4], pods[6]}, - }, - { - name: "filter labels pods", - selector: v1alpha1.SelectorSpec{ - LabelSelectors: map[string]string{"l2": "l2"}, - }, - expectedPods: []v1.Pod{pods[5], pods[6]}, - }, - { - name: "filter pods by label expressions", - selector: v1alpha1.SelectorSpec{ - ExpressionSelectors: []metav1.LabelSelectorRequirement{ - { - Key: "l2", - Operator: metav1.LabelSelectorOpIn, - Values: []string{"l2"}, - }, - }, - }, - expectedPods: []v1.Pod{pods[5], pods[6]}, - }, - { - name: "filter pods by label selectors and expression selectors", - selector: v1alpha1.SelectorSpec{ - LabelSelectors: map[string]string{"l1": "l1"}, - ExpressionSelectors: []metav1.LabelSelectorRequirement{ - { - Key: "l2", - Operator: metav1.LabelSelectorOpIn, - Values: []string{"l2"}, - }, - }, - }, - expectedPods: nil, - }, - { - name: "filter namespace and labels", - selector: v1alpha1.SelectorSpec{ - Namespaces: []string{"test-s"}, - LabelSelectors: map[string]string{"l2": "l2"}, - }, - expectedPods: []v1.Pod{pods[5], pods[6]}, - }, - { - name: "filter namespace and labels", - selector: v1alpha1.SelectorSpec{ - Namespaces: []string{metav1.NamespaceDefault}, - LabelSelectors: map[string]string{"l2": "l2"}, - }, - expectedPods: nil, - }, - { - name: "filter by specified node", - selector: v1alpha1.SelectorSpec{ - Nodes: []string{"az1-node1"}, - }, - expectedPods: []v1.Pod{pods[0], pods[1], pods[2], pods[3], pods[4]}, - }, - { - name: "filter node and labels", - selector: v1alpha1.SelectorSpec{ - LabelSelectors: map[string]string{"l1": "l1"}, - Nodes: []string{"az2-node1"}, - }, - expectedPods: nil, - }, - { - name: "filter pods by nodeSelector", - selector: v1alpha1.SelectorSpec{ - NodeSelectors: map[string]string{"disktype": "hdd"}, - }, - expectedPods: []v1.Pod{pods[5], pods[6]}, - }, - { - name: "filter pods by node and nodeSelector", - selector: v1alpha1.SelectorSpec{ - NodeSelectors: map[string]string{"zone": "az1"}, - Nodes: []string{"az2-node1"}, - }, - expectedPods: []v1.Pod{pods[0], pods[1], pods[2], pods[3], pods[4], pods[5], pods[6]}, - }, - } - - var ( - testCfgClusterScoped = true - testCfgTargetNamespace = "" - testCfgEnableNamespaceFilter = false - ) - - for _, tc := range tcs { - filteredPods, err := SelectPods(context.Background(), c, r, tc.selector, testCfgClusterScoped, testCfgTargetNamespace, testCfgEnableNamespaceFilter) - g.Expect(err).ShouldNot(HaveOccurred(), tc.name) - g.Expect(len(filteredPods)).To(Equal(len(tc.expectedPods)), tc.name) - } -} - -func TestSelectPodWithNamespaceFilter(t *testing.T) { - g := NewGomegaWithT(t) - - objectsInNs1, podsInNs1 := GenerateNPods("ns1", 5, PodArg{Namespace: "ns1"}) - objectsInNs2, podsInNs2 := GenerateNPods("ns2", 5, PodArg{Namespace: "ns2"}) - namespaces := []runtime.Object{ - &v1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "ns1", - }, - }, - &v1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "ns2", - Annotations: map[string]string{ - "chaos-mesh.org/inject": "enabled", - }, - }, - }, - } - - objs := append(objectsInNs1, objectsInNs2...) - objs = append(objs, namespaces...) - c := fake.NewFakeClient(objs...) - - type TestCase struct { - name string - selector v1alpha1.SelectorSpec - expectedPods []v1.Pod - enableNamespaceFilter bool - } - tcs := []TestCase{ - { - name: "without namespace filter", - selector: v1alpha1.SelectorSpec{ - Namespaces: []string{"ns1", "ns2"}, - }, - enableNamespaceFilter: false, - expectedPods: append(podsInNs1, podsInNs2...), - }, - { - name: "with namespace filter", - selector: v1alpha1.SelectorSpec{ - Namespaces: []string{"ns1", "ns2"}, - }, - enableNamespaceFilter: true, - expectedPods: podsInNs2, - }, - } - - var ( - testCfgClusterScoped = true - testCfgTargetNamespace = "" - ) - - var r client.Reader - for _, tc := range tcs { - filteredPods, err := SelectPods(context.Background(), c, r, tc.selector, testCfgClusterScoped, testCfgTargetNamespace, tc.enableNamespaceFilter) - g.Expect(err).ShouldNot(HaveOccurred(), tc.name) - g.Expect(len(filteredPods)).To(Equal(len(tc.expectedPods)), tc.name) - } -} - -func TestCheckPodMeetSelector(t *testing.T) { - g := NewGomegaWithT(t) - - type TestCase struct { - name string - selector v1alpha1.SelectorSpec - pod v1.Pod - expectedValue bool - } - - tcs := []TestCase{ - { - name: "meet label", - pod: NewPod(PodArg{Name: "t1", Status: v1.PodPending, Labels: map[string]string{"app": "tikv", "ss": "t1"}}), - selector: v1alpha1.SelectorSpec{ - LabelSelectors: map[string]string{"app": "tikv"}, - }, - expectedValue: true, - }, - { - name: "not meet label", - pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb", "ss": "t1"}}), - selector: v1alpha1.SelectorSpec{ - LabelSelectors: map[string]string{"app": "tikv"}, - }, - expectedValue: false, - }, - { - name: "pod labels is empty", - pod: NewPod(PodArg{Name: "t1"}), - selector: v1alpha1.SelectorSpec{ - LabelSelectors: map[string]string{"app": "tikv"}, - }, - expectedValue: false, - }, - { - name: "selector is empty", - pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}), - selector: v1alpha1.SelectorSpec{}, - expectedValue: true, - }, - { - name: "meet labels and meet expressions", - pod: NewPod(PodArg{Name: "t1", Status: v1.PodPending, Labels: map[string]string{"app": "tikv", "ss": "t1"}}), - selector: v1alpha1.SelectorSpec{ - LabelSelectors: map[string]string{"app": "tikv"}, - ExpressionSelectors: []metav1.LabelSelectorRequirement{ - { - Key: "ss", - Operator: metav1.LabelSelectorOpExists, - }, - }, - }, - expectedValue: true, - }, - { - name: "meet labels and not meet expressions", - pod: NewPod(PodArg{Name: "t1", Status: v1.PodPending, Labels: map[string]string{"app": "tikv", "ss": "t1"}}), - selector: v1alpha1.SelectorSpec{ - LabelSelectors: map[string]string{"app": "tikv"}, - ExpressionSelectors: []metav1.LabelSelectorRequirement{ - { - Key: "ss", - Operator: metav1.LabelSelectorOpNotIn, - Values: []string{"t1"}, - }, - }, - }, - expectedValue: false, - }, - { - name: "meet namespace", - pod: NewPod(PodArg{Name: "t1"}), - selector: v1alpha1.SelectorSpec{ - Namespaces: []string{metav1.NamespaceDefault}, - }, - expectedValue: true, - }, - { - name: "meet namespace and meet labels", - pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tikv"}}), - selector: v1alpha1.SelectorSpec{ - Namespaces: []string{metav1.NamespaceDefault}, - LabelSelectors: map[string]string{"app": "tikv"}, - }, - expectedValue: true, - }, - { - name: "meet namespace and not meet labels", - pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}), - selector: v1alpha1.SelectorSpec{ - Namespaces: []string{metav1.NamespaceDefault}, - LabelSelectors: map[string]string{"app": "tikv"}, - }, - expectedValue: false, - }, - { - name: "meet pods", - pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}), - selector: v1alpha1.SelectorSpec{ - Pods: map[string][]string{ - metav1.NamespaceDefault: {"t1"}, - }, - }, - expectedValue: true, - }, - { - name: "meet annotation", - pod: NewPod(PodArg{Name: "t1", Ans: map[string]string{"an": "n1", "an2": "n2"}, Labels: map[string]string{"app": "tidb"}}), - selector: v1alpha1.SelectorSpec{ - Namespaces: []string{metav1.NamespaceDefault}, - AnnotationSelectors: map[string]string{ - "an": "n1", - }, - }, - expectedValue: true, - }, - { - name: "not meet annotation", - pod: NewPod(PodArg{Name: "t1", Ans: map[string]string{"an": "n1"}, Labels: map[string]string{"app": "tidb"}}), - selector: v1alpha1.SelectorSpec{ - Namespaces: []string{metav1.NamespaceDefault}, - AnnotationSelectors: map[string]string{ - "an": "n2", - }, - }, - expectedValue: false, - }, - { - name: "meet pod selector", - pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}), - selector: v1alpha1.SelectorSpec{ - Pods: map[string][]string{ - metav1.NamespaceDefault: {"t1", "t2"}, - }, - }, - expectedValue: true, - }, - { - name: "not meet pod selector", - pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}), - selector: v1alpha1.SelectorSpec{ - Pods: map[string][]string{ - metav1.NamespaceDefault: {"t2"}, - }, - }, - expectedValue: false, - }, - { - name: "meet pod selector and not meet labels", - pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}), - selector: v1alpha1.SelectorSpec{ - Pods: map[string][]string{ - metav1.NamespaceDefault: {"t1", "t2"}, - }, - LabelSelectors: map[string]string{"app": "tikv"}, - }, - expectedValue: false, - }, - } - - for _, tc := range tcs { - meet, err := CheckPodMeetSelector(tc.pod, tc.selector) - g.Expect(err).ShouldNot(HaveOccurred(), tc.name) - g.Expect(meet).To(Equal(tc.expectedValue), tc.name) - } -} - -func TestRandomFixedIndexes(t *testing.T) { - g := NewGomegaWithT(t) - - type TestCase struct { - name string - start uint - end uint - count uint - expectedOutputLen int - } - - tcs := []TestCase{ - { - name: "start 0, end 10, count 3", - start: 0, - end: 10, - count: 3, - expectedOutputLen: 3, - }, - { - name: "start 0, end 10, count 12", - start: 0, - end: 10, - count: 12, - expectedOutputLen: 10, - }, - { - name: "start 5, end 10, count 3", - start: 5, - end: 10, - count: 3, - expectedOutputLen: 3, - }, - } - - for _, tc := range tcs { - values := RandomFixedIndexes(tc.start, tc.end, tc.count) - g.Expect(len(values)).To(Equal(tc.expectedOutputLen), tc.name) - - for _, v := range values { - g.Expect(v).Should(BeNumerically(">=", tc.start), tc.name) - g.Expect(v).Should(BeNumerically("<", tc.end), tc.name) - } - } -} - -func TestFilterByPhaseSelector(t *testing.T) { - g := NewGomegaWithT(t) - - type TestCase struct { - name string - pods []v1.Pod - filterSelector labels.Selector - filteredPods []v1.Pod - } - - pods := []v1.Pod{ - NewPod(PodArg{Name: "p1", Status: v1.PodRunning}), - NewPod(PodArg{Name: "p2", Status: v1.PodRunning}), - NewPod(PodArg{Name: "p3", Status: v1.PodPending}), - NewPod(PodArg{Name: "p4", Status: v1.PodFailed}), - } - - var tcs []TestCase - - runningSelector, err := parseSelector(string(pods[1].Status.Phase)) - g.Expect(err).ShouldNot(HaveOccurred()) - - tcs = append(tcs, TestCase{ - name: "filter n2", - pods: pods, - filterSelector: runningSelector, - filteredPods: []v1.Pod{pods[0], pods[1]}, - }) - - emptySelector, err := parseSelector("") - g.Expect(err).ShouldNot(HaveOccurred()) - tcs = append(tcs, TestCase{ - name: "filter empty selector", - pods: pods, - filterSelector: emptySelector, - filteredPods: pods, - }) - - tcs = append(tcs, TestCase{ - name: "filter no pods", - pods: []v1.Pod{}, - filterSelector: runningSelector, - filteredPods: nil, - }) - - runningAndPendingSelector, err := parseSelector("Running,Pending") - g.Expect(err).ShouldNot(HaveOccurred()) - - tcs = append(tcs, TestCase{ - name: "filter running and pending", - pods: pods, - filterSelector: runningAndPendingSelector, - filteredPods: []v1.Pod{pods[0], pods[1], pods[2]}, - }) - - failedSelector, err := parseSelector("Failed") - g.Expect(err).ShouldNot(HaveOccurred()) - - tcs = append(tcs, TestCase{ - name: "filter failed", - pods: pods, - filterSelector: failedSelector, - filteredPods: []v1.Pod{pods[3]}, - }) - - unknownSelector, err := parseSelector("Unknown") - g.Expect(err).ShouldNot(HaveOccurred()) - tcs = append(tcs, TestCase{ - name: "filter Unknown", - pods: pods, - filterSelector: unknownSelector, - filteredPods: nil, - }) - - for _, tc := range tcs { - g.Expect(filterByPhaseSelector(tc.pods, tc.filterSelector)).To(Equal(tc.filteredPods), tc.name) - } -} - -func TestFilterByAnnotations(t *testing.T) { - g := NewGomegaWithT(t) - - type TestCase struct { - name string - pods []v1.Pod - filterSelector labels.Selector - filteredPods []v1.Pod - } - - pods := []v1.Pod{ - NewPod(PodArg{Name: "p1", Ans: map[string]string{"p1": "p1"}}), - NewPod(PodArg{Name: "p2", Ans: map[string]string{"p2": "p2"}}), - NewPod(PodArg{Name: "p3", Ans: map[string]string{"t": "t"}}), - NewPod(PodArg{Name: "p4", Ans: map[string]string{"t": "t"}}), - } - - var tcs []TestCase - p2Selector, err := parseSelector(label.Label(pods[1].Annotations).String()) - g.Expect(err).ShouldNot(HaveOccurred()) - - tcs = append(tcs, TestCase{ - name: "filter p2", - pods: pods, - filterSelector: p2Selector, - filteredPods: []v1.Pod{pods[1]}, - }) - - emptySelector, err := parseSelector(label.Label(map[string]string{}).String()) - g.Expect(err).ShouldNot(HaveOccurred()) - tcs = append(tcs, TestCase{ - name: "filter empty selector", - pods: pods, - filterSelector: emptySelector, - filteredPods: pods, - }) - - tcs = append(tcs, TestCase{ - name: "filter no pods", - pods: []v1.Pod{}, - filterSelector: p2Selector, - filteredPods: nil, - }) - - for _, tc := range tcs { - g.Expect(filterByAnnotations(tc.pods, tc.filterSelector)).To(Equal(tc.filteredPods), tc.name) - } -} - -func TestFilterNamespaceSelector(t *testing.T) { - g := NewGomegaWithT(t) - - type TestCase struct { - name string - pods []v1.Pod - filterSelector labels.Selector - filteredPods []v1.Pod - } - - pods := []v1.Pod{ - NewPod(PodArg{Name: "p1", Namespace: "n1"}), - NewPod(PodArg{Name: "p2", Namespace: "n2"}), - NewPod(PodArg{Name: "p3", Namespace: "n2"}), - NewPod(PodArg{Name: "p4", Namespace: "n4"}), - } - - var tcs []TestCase - n2Selector, err := parseSelector(pods[1].Namespace) - g.Expect(err).ShouldNot(HaveOccurred()) - - tcs = append(tcs, TestCase{ - name: "filter n2", - pods: pods, - filterSelector: n2Selector, - filteredPods: []v1.Pod{pods[1], pods[2]}, - }) - - emptySelector, err := parseSelector("") - g.Expect(err).ShouldNot(HaveOccurred()) - tcs = append(tcs, TestCase{ - name: "filter empty selector", - pods: pods, - filterSelector: emptySelector, - filteredPods: pods, - }) - - tcs = append(tcs, TestCase{ - name: "filter no pods", - pods: []v1.Pod{}, - filterSelector: n2Selector, - filteredPods: nil, - }) - - n2AndN3Selector, err := parseSelector("n2,n3") - g.Expect(err).ShouldNot(HaveOccurred()) - - tcs = append(tcs, TestCase{ - name: "filter n2 and n3", - pods: pods, - filterSelector: n2AndN3Selector, - filteredPods: []v1.Pod{pods[1], pods[2]}, - }) - - n2AndN4Selector, err := parseSelector("n2,n4") - g.Expect(err).ShouldNot(HaveOccurred()) - - tcs = append(tcs, TestCase{ - name: "filter n2 and n4", - pods: pods, - filterSelector: n2AndN4Selector, - filteredPods: []v1.Pod{pods[1], pods[2], pods[3]}, - }) - - for _, tc := range tcs { - g.Expect(filterByNamespaceSelector(tc.pods, tc.filterSelector)).To(Equal(tc.filteredPods), tc.name) - } -} - -func TestFilterPodByNode(t *testing.T) { - g := NewGomegaWithT(t) - - type TestCase struct { - name string - pods []v1.Pod - nodes []v1.Node - filteredPods []v1.Pod - } - - var tcs []TestCase - - pods := []v1.Pod{ - NewPod(PodArg{Name: "p1", Namespace: "n1", Nodename: "node1"}), - NewPod(PodArg{Name: "p2", Namespace: "n2", Nodename: "node1"}), - NewPod(PodArg{Name: "p3", Namespace: "n2", Nodename: "node2"}), - NewPod(PodArg{Name: "p4", Namespace: "n4", Nodename: "node3"}), - } - - nodes := []v1.Node{ - NewNode("node1", map[string]string{"disktype": "ssd", "zone": "az1"}), - NewNode("node2", map[string]string{"disktype": "hdd", "zone": "az1"}), - } - - tcs = append(tcs, TestCase{ - name: "filter pods from node1 and node2", - pods: pods, - nodes: nodes, - filteredPods: []v1.Pod{pods[0], pods[1], pods[2]}, - }) - - tcs = append(tcs, TestCase{ - name: "filter no nodes", - pods: pods, - nodes: []v1.Node{}, - filteredPods: nil, - }) - - for _, tc := range tcs { - g.Expect(filterPodByNode(tc.pods, tc.nodes)).To(Equal(tc.filteredPods), tc.name) - } - -} diff --git a/pkg/status/status.go b/pkg/status/status.go new file mode 100644 index 0000000000..7d8530c3bf --- /dev/null +++ b/pkg/status/status.go @@ -0,0 +1,93 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package status + +import ( + "time" + + corev1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" +) + +type ChaosStatus string + +const ( + Injecting ChaosStatus = "injecting" + Running ChaosStatus = "running" + Finished ChaosStatus = "finished" + Paused ChaosStatus = "paused" + Deleting ChaosStatus = "deleting" +) + +type AllChaosStatus struct { + Injecting int `json:"injecting"` + Running int `json:"running"` + Finished int `json:"finished"` + Paused int `json:"paused"` + Deleting int `json:"deleting"` +} + +type ScheduleStatus string + +const ( + ScheduleRunning ScheduleStatus = "running" + SchedulePaused ScheduleStatus = "paused" +) + +// GetChaosStatus returns the status of chaos object. +func GetChaosStatus(obj v1alpha1.InnerObject) ChaosStatus { + if obj.IsDeleted() { + return Deleting + } + + selected := false + allInjected := false + for _, c := range obj.GetStatus().Conditions { + if c.Status == corev1.ConditionTrue { + switch c.Type { + // If ConditionPaused is true, represent the chaos experiment is paused. + case v1alpha1.ConditionPaused: + return Paused + case v1alpha1.ConditionSelected: + selected = true + case v1alpha1.ConditionAllInjected: + allInjected = true + } + } + } + + if controller.IsChaosFinished(obj, time.Now()) { + return Finished + } + + // Only when the target objects are successfully selected and injected, + // it means that the chaos experiment is running well. + if selected && allInjected { + return Running + } + + return Injecting +} + +func GetScheduleStatus(sch v1alpha1.Schedule) ScheduleStatus { + if sch.IsPaused() { + return SchedulePaused + } + + return ScheduleRunning +} diff --git a/pkg/store/dbstore/store.go b/pkg/store/dbstore/store.go deleted file mode 100644 index 89c15573ea..0000000000 --- a/pkg/store/dbstore/store.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbstore - -import ( - "context" - - "go.uber.org/fx" - - "github.com/jinzhu/gorm" - - "github.com/chaos-mesh/chaos-mesh/pkg/config" - - ctrl "sigs.k8s.io/controller-runtime" -) - -var ( - sqliteDriver string = "sqlite3" - log = ctrl.Log.WithName("store/dbstore") -) - -// DB defines a db storage. -type DB struct { - *gorm.DB -} - -// NewDBStore returns a new DB -func NewDBStore(lc fx.Lifecycle, conf *config.ChaosDashboardConfig) (*DB, error) { - dsn := conf.Database.Datasource - - // fix error `database is locked`, refer to https://github.com/mattn/go-sqlite3/blob/master/README.md#faq - if conf.Database.Driver == sqliteDriver { - dsn += "?cache=shared" - } - - gormDB, err := gorm.Open(conf.Database.Driver, dsn) - if err != nil { - log.Error(err, "failed to open DB", "driver", conf.Database.Driver, "datasource", conf.Database.Datasource) - return nil, err - } - - // fix error `database is locked`, refer to https://github.com/mattn/go-sqlite3/blob/master/README.md#faq - if conf.Database.Driver == sqliteDriver { - gormDB.DB().SetMaxOpenConns(1) - } - - db := &DB{ - gormDB, - } - - lc.Append(fx.Hook{ - OnStop: func(context.Context) error { - return db.Close() - }, - }) - - return db, nil -} diff --git a/pkg/store/event/event.go b/pkg/store/event/event.go deleted file mode 100644 index 1b85f24505..0000000000 --- a/pkg/store/event/event.go +++ /dev/null @@ -1,570 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package event - -import ( - "context" - "fmt" - "sort" - "strconv" - "strings" - "time" - - "github.com/jinzhu/gorm" - - "github.com/chaos-mesh/chaos-mesh/pkg/core" - "github.com/chaos-mesh/chaos-mesh/pkg/store/dbstore" - - ctrl "sigs.k8s.io/controller-runtime" -) - -var log = ctrl.Log.WithName("store/event") - -// NewStore return a new EventStore. -func NewStore(db *dbstore.DB) core.EventStore { - db.AutoMigrate(&core.Event{}) - db.AutoMigrate(&core.PodRecord{}) - - es := &eventStore{db} - - if err := es.DeleteIncompleteEvents(context.Background()); err != nil && !gorm.IsRecordNotFoundError(err) { - log.Error(err, "failed to delete all incomplete events") - } - - return es -} - -type eventStore struct { - db *dbstore.DB -} - -func min(x, y int) int { - if x > y { - return y - } - return x -} - -// findPodRecordsByEventID returns the list of PodRecords according to the eventID -func (e *eventStore) findPodRecordsByEventID(_ context.Context, id uint) ([]*core.PodRecord, error) { - pods := make([]*core.PodRecord, 0) - if err := e.db.Where( - "event_id = ?", id). - Find(&pods).Error; err != nil && !gorm.IsRecordNotFoundError(err) { - return nil, err - } - return pods, nil -} - -// List returns the list of events -func (e *eventStore) List(_ context.Context) ([]*core.Event, error) { - var resList []core.Event - eventList := make([]*core.Event, 0) - - if err := e.db.Find(&resList).Error; err != nil && !gorm.IsRecordNotFoundError(err) { - return nil, err - } - - for _, et := range resList { - pods, err := e.findPodRecordsByEventID(context.Background(), et.ID) - if err != nil { - return nil, err - } - var event core.Event = et - event.Pods = pods - eventList = append(eventList, &event) - } - - return eventList, nil -} - -// ListByUID returns an event list by the uid of the experiment. -func (e *eventStore) ListByUID(_ context.Context, uid string) ([]*core.Event, error) { - var resList []core.Event - eventList := make([]*core.Event, 0) - - if err := e.db.Where( - "experiment_id = ?", uid). - Find(&resList).Error; err != nil && !gorm.IsRecordNotFoundError(err) { - return nil, err - } - - for _, et := range resList { - pods, err := e.findPodRecordsByEventID(context.Background(), et.ID) - if err != nil { - return nil, err - } - var event core.Event = et - event.Pods = pods - eventList = append(eventList, &event) - } - - return eventList, nil -} - -// ListByUID returns an event list by the uid of the experiment. -func (e *eventStore) ListByUIDs(_ context.Context, uids []string) ([]*core.Event, error) { - var resList []core.Event - eventList := make([]*core.Event, 0) - - if err := e.db.Table("events").Where( - "experiment_id IN (?)", uids). - Find(&resList).Error; err != nil && !gorm.IsRecordNotFoundError(err) { - return nil, err - } - - for _, et := range resList { - pods, err := e.findPodRecordsByEventID(context.Background(), et.ID) - if err != nil { - return nil, err - } - var event core.Event = et - event.Pods = pods - eventList = append(eventList, &event) - } - - return eventList, nil -} - -// ListByExperiment returns an event list by the name and namespace of the experiment. -func (e *eventStore) ListByExperiment(_ context.Context, namespace string, experiment string) ([]*core.Event, error) { - var resList []core.Event - - if err := e.db.Where( - "namespace = ? and experiment = ? ", - namespace, experiment). - Find(&resList).Error; err != nil && !gorm.IsRecordNotFoundError(err) { - return nil, err - } - - eventList := make([]*core.Event, 0, len(resList)) - for _, et := range resList { - pods, err := e.findPodRecordsByEventID(context.Background(), et.ID) - if err != nil { - return nil, err - } - var event core.Event = et - event.Pods = pods - eventList = append(eventList, &event) - } - - return eventList, nil -} - -// ListByNamespace returns the list of events according to the namespace -func (e *eventStore) ListByNamespace(_ context.Context, namespace string) ([]*core.Event, error) { - podRecords := make([]*core.PodRecord, 0) - - if err := e.db.Where( - &core.PodRecord{Namespace: namespace}). - Find(&podRecords).Error; err != nil && !gorm.IsRecordNotFoundError(err) { - return nil, err - } - - eventList := make([]*core.Event, 0, len(podRecords)) - for _, pr := range podRecords { - et := new(core.Event) - if err := e.db.Where( - "id = ?", pr.EventID). - First(et).Error; err != nil && !gorm.IsRecordNotFoundError(err) { - return nil, err - } - pods, err := e.findPodRecordsByEventID(context.Background(), et.ID) - if err != nil { - return nil, err - } - et.Pods = pods - eventList = append(eventList, et) - } - return eventList, nil -} - -// ListByPod returns the list of events according to the pod -func (e *eventStore) ListByPod(_ context.Context, namespace string, name string) ([]*core.Event, error) { - podRecords := make([]*core.PodRecord, 0) - - if err := e.db.Where( - &core.PodRecord{PodName: name, Namespace: namespace}). - Find(&podRecords).Error; err != nil && !gorm.IsRecordNotFoundError(err) { - return nil, err - } - - eventList := make([]*core.Event, 0, len(podRecords)) - for _, pr := range podRecords { - et := new(core.Event) - if err := e.db.Where( - "id = ?", pr.EventID). - First(et).Error; err != nil && !gorm.IsRecordNotFoundError(err) { - return nil, err - } - - pods, err := e.findPodRecordsByEventID(context.Background(), et.ID) - if err != nil { - return nil, err - } - et.Pods = pods - eventList = append(eventList, et) - } - return eventList, nil -} - -// Find returns an event from the datastore by ID. -func (e *eventStore) Find(_ context.Context, id uint) (*core.Event, error) { - et := new(core.Event) - if err := e.db.Where( - "id = ?", id). - First(et).Error; err != nil { - return nil, err - } - pods, err := e.findPodRecordsByEventID(context.Background(), et.ID) - if err != nil { - return nil, err - } - et.Pods = pods - return et, nil -} - -func (e *eventStore) FindByExperimentAndStartTime( - _ context.Context, - name, namespace string, - startTime *time.Time, -) (*core.Event, error) { - et := new(core.Event) - if err := e.db.Where( - "namespace = ? and experiment = ? and start_time = ?", - namespace, name, startTime). - First(et).Error; err != nil { - return nil, err - } - - var pods []*core.PodRecord - - if err := e.db.Where( - "event_id = ?", et.ID). - Find(&pods).Error; err != nil && !gorm.IsRecordNotFoundError(err) { - return nil, err - } - - return et, nil -} - -// Create persists a new event to the datastore. -func (e *eventStore) Create(_ context.Context, et *core.Event) error { - if err := e.db.Create(et).Error; err != nil { - return err - } - - for _, pod := range et.Pods { - pod.EventID = et.ID - if err := e.db.Create(pod).Error; err != nil { - return err - } - } - - return nil -} - -// Update persists an updated event to the datastore. -func (e *eventStore) Update(_ context.Context, et *core.Event) error { - return e.db.Model(core.Event{}). - Where( - "namespace = ? and experiment = ? and start_time = ?", - et.Namespace, et.Experiment, et.StartTime). - Update("finish_time", et.FinishTime). - Error -} - -// DeleteIncompleteEvents implement core.EventStore interface. -func (e *eventStore) DeleteIncompleteEvents(_ context.Context) error { - return e.db.Where("finish_time IS NULL").Unscoped(). - Delete(core.Event{}).Error -} - -// ListByFilter returns an event list by podName, podNamespace, experimentName, experimentNamespace, uid, kind, startTime and finishTime. -func (e *eventStore) ListByFilter(_ context.Context, filter core.Filter) ([]*core.Event, error) { - var ( - resList []*core.Event - err error - startTime, finishTime time.Time - limit int - ) - - if filter.LimitStr != "" { - limit, err = strconv.Atoi(filter.LimitStr) - if err != nil { - return nil, fmt.Errorf("the format of the limitStr is wrong") - } - } - if filter.StartTimeStr != "" { - startTime, err = time.Parse(time.RFC3339, strings.Replace(filter.StartTimeStr, " ", "+", -1)) - if err != nil { - return nil, fmt.Errorf("the format of the startTime is wrong") - } - } - if filter.FinishTimeStr != "" { - finishTime, err = time.Parse(time.RFC3339, strings.Replace(filter.FinishTimeStr, " ", "+", -1)) - if err != nil { - return nil, fmt.Errorf("the format of the finishTime is wrong") - } - } - - if filter.PodName != "" { - resList, err = e.ListByPod(context.Background(), filter.PodNamespace, filter.PodName) - if err == nil && filter.LimitStr != "" { - sort.Slice(resList, func(i, j int) bool { - return resList[i].CreatedAt.After(resList[j].CreatedAt) - }) - resList = resList[:min(limit, len(resList))] - } - } else if filter.PodNamespace != "" { - resList, err = e.ListByNamespace(context.Background(), filter.PodNamespace) - if err == nil && filter.LimitStr != "" { - sort.Slice(resList, func(i, j int) bool { - return resList[i].CreatedAt.After(resList[j].CreatedAt) - }) - resList = resList[:min(limit, len(resList))] - } - } else { - resList, err = e.DryListByFilter(context.Background(), filter) - } - if err != nil { - return resList, err - } - - eventList := make([]*core.Event, 0) - for _, event := range resList { - if filter.PodName != "" || filter.PodNamespace != "" { - if filter.ExperimentName != "" && event.Experiment != filter.ExperimentName { - continue - } - if filter.ExperimentNamespace != "" && event.Namespace != filter.ExperimentNamespace { - continue - } - if filter.UID != "" && event.ExperimentID != filter.UID { - continue - } - if filter.Kind != "" && event.Kind != filter.Kind { - continue - } - if filter.StartTimeStr != "" && event.StartTime.Before(startTime) && !event.StartTime.Equal(startTime) { - continue - } - if filter.FinishTimeStr != "" && event.FinishTime.After(finishTime) && !event.FinishTime.Equal(finishTime) { - continue - } - } - if filter.PodNamespace == "" { - pods, err := e.findPodRecordsByEventID(context.Background(), event.ID) - if err != nil { - return nil, err - } - event.Pods = pods - } - eventList = append(eventList, event) - } - return eventList, nil -} - -// DryListByFilter returns an event list by experimentName, experimentNamespace, uid, kind, startTime and finishTime. -func (e *eventStore) DryListByFilter(_ context.Context, filter core.Filter) ([]*core.Event, error) { - var ( - resList []*core.Event - err error - db *dbstore.DB - limit int - ) - - if filter.LimitStr != "" { - limit, err = strconv.Atoi(filter.LimitStr) - if err != nil { - return nil, fmt.Errorf("the format of the limitStr is wrong") - } - } - if filter.StartTimeStr != "" { - _, err = time.Parse(time.RFC3339, strings.Replace(filter.StartTimeStr, " ", "+", -1)) - if err != nil { - return nil, fmt.Errorf("the format of the startTime is wrong") - } - } - if filter.FinishTimeStr != "" { - _, err = time.Parse(time.RFC3339, strings.Replace(filter.FinishTimeStr, " ", "+", -1)) - if err != nil { - return nil, fmt.Errorf("the format of the finishTime is wrong") - } - } - - query, args := constructQueryArgs(filter.ExperimentName, filter.ExperimentNamespace, filter.UID, filter.Kind, filter.StartTimeStr, filter.FinishTimeStr) - // List all events - if len(args) == 0 { - db = e.db - } else { - db = &dbstore.DB{DB: e.db.Where(query, args...)} - } - if filter.LimitStr != "" { - db = &dbstore.DB{DB: db.Order("created_at desc").Limit(limit)} - } - if err := db.Find(&resList).Error; err != nil && - !gorm.IsRecordNotFoundError(err) { - return resList, err - } - - return resList, err -} - -// DeleteByFinishTime deletes events and podrecords whose time difference is greater than the given time from FinishTime. -func (e *eventStore) DeleteByFinishTime(_ context.Context, ttl time.Duration) error { - eventList, err := e.List(context.Background()) - if err != nil { - return err - } - nowTime := time.Now() - for _, et := range eventList { - if et.FinishTime == nil { - continue - } - if et.FinishTime.Add(ttl).Before(nowTime) { - if err := e.db.Model(core.Event{}).Unscoped().Delete(*et).Error; err != nil { - return err - } - - if err := e.db.Model(core.PodRecord{}). - Where( - "event_id = ? ", - et.ID).Unscoped().Delete(core.PodRecord{}).Error; err != nil { - return err - } - } - } - return nil -} - -// DeleteByUID deletes events by the uid of the experiment. -func (e *eventStore) DeleteByUID(_ context.Context, uid string) error { - eventList, err := e.ListByUID(context.Background(), uid) - if err != nil { - return err - } - for _, et := range eventList { - if err := e.db.Model(core.PodRecord{}). - Where( - "event_id = ? ", - et.ID).Unscoped().Delete(core.PodRecord{}).Error; err != nil { - return err - } - } - return e.db.Where("experiment_id = ?", uid).Unscoped(). - Delete(core.Event{}).Error -} - -// DeleteByUIDs deletes events by the uid list of the experiment. -func (e *eventStore) DeleteByUIDs(_ context.Context, uids []string) error { - eventList, err := e.ListByUIDs(context.Background(), uids) - if err != nil { - return err - } - eventIDList := make([]uint, len(eventList)) - for _, et := range eventList { - eventIDList = append(eventIDList, et.ID) - } - if err = e.db.Model(core.PodRecord{}).Where("event_id IN (?)", eventIDList).Unscoped().Delete(core.PodRecord{}).Error; err != nil { - return err - } - return e.db.Where("experiment_id IN (?)", uids).Unscoped().Delete(core.Event{}).Error -} - -func (e *eventStore) getUID(_ context.Context, ns, name string) (string, error) { - events := make([]*core.Event, 0) - - if err := e.db.Where( - &core.Event{Experiment: name, Namespace: ns}). - Find(&events).Error; err != nil { - return "", err - } - - if len(events) == 0 { - return "", fmt.Errorf("get UID failure, maybe name or namespace is wrong") - } - - UID := events[0].ExperimentID - st := events[0].StartTime - - for _, et := range events { - if st.Before(*et.StartTime) { - st = et.StartTime - UID = et.ExperimentID - } - } - return UID, nil -} - -// UpdateIncompleteEvents updates the incomplete event by the namespace and name -func (e *eventStore) UpdateIncompleteEvents(_ context.Context, ns, name string) error { - return e.db.Model(core.Event{}). - Where( - "namespace = ? and experiment = ? and finish_time IS NULL", - ns, name). - Update("finish_time", time.Now()). - Error -} - -func constructQueryArgs(experimentName, experimentNamespace, uid, kind, startTime, finishTime string) (string, []interface{}) { - args := make([]interface{}, 0) - query := "" - if experimentName != "" { - query += "experiment = ?" - args = append(args, experimentName) - } - if experimentNamespace != "" { - if len(args) > 0 { - query += " AND namespace = ?" - } else { - query += "namespace = ?" - } - args = append(args, experimentNamespace) - } - if uid != "" { - if len(args) > 0 { - query += " AND experiment_id = ?" - } else { - query += "experiment_id = ?" - } - args = append(args, uid) - } - if kind != "" { - if len(args) > 0 { - query += " AND kind = ?" - } else { - query += "kind = ?" - } - args = append(args, kind) - } - if startTime != "" { - if len(args) > 0 { - query += " AND start_time >= ?" - } else { - query += "start_time >= ?" - } - args = append(args, strings.Replace(startTime, "T", " ", -1)) - } - if finishTime != "" { - if len(args) > 0 { - query += " AND finish_time <= ?" - } else { - query += "finish_time <= ?" - } - args = append(args, strings.Replace(finishTime, "T", " ", -1)) - } - - return query, args -} diff --git a/pkg/store/event/event_test.go b/pkg/store/event/event_test.go deleted file mode 100644 index 7287371c8e..0000000000 --- a/pkg/store/event/event_test.go +++ /dev/null @@ -1,957 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package event - -import ( - "context" - "database/sql" - "reflect" - "regexp" - "strings" - "testing" - "time" - - "github.com/chaos-mesh/chaos-mesh/pkg/core" - "github.com/chaos-mesh/chaos-mesh/pkg/store/dbstore" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/jinzhu/gorm" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -func TestEvent(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Event Suite") -} - -var _ = Describe("event", func() { - var ( - es *eventStore - mock sqlmock.Sqlmock - podRecord0 *core.PodRecord - podRecord1 *core.PodRecord - event0 *core.Event - event1 *core.Event - timeNow time.Time - ) - - BeforeEach(func() { - var db *sql.DB - var err error - db, mock, err = sqlmock.New() - Expect(err).ShouldNot(HaveOccurred()) - - gdb, err := gorm.Open("sqlite3", db) - Expect(err).ShouldNot(HaveOccurred()) - - es = &eventStore{db: &dbstore.DB{DB: gdb}} - - timeNow = time.Now() - oneMinute, _ := time.ParseDuration("1m") - timeAfter := timeNow.Add(oneMinute) - podRecord0 = &core.PodRecord{ - ID: 0, - CreatedAt: timeNow, - UpdatedAt: timeNow, - DeletedAt: &timeNow, - EventID: 0, - PodIP: "testIP", - PodName: "testName", - Namespace: "testNamespace", - Message: "testMessage", - Action: "testAction", - } - podRecord1 = &core.PodRecord{ - ID: 1, - CreatedAt: timeNow, - UpdatedAt: timeNow, - DeletedAt: &timeNow, - EventID: 1, - PodIP: "testIP", - PodName: "testName", - Namespace: "testNamespace", - Message: "testMessage", - Action: "testAction", - } - event0 = &core.Event{ - ID: 0, - CreatedAt: timeNow, - UpdatedAt: timeNow, - DeletedAt: &timeNow, - Experiment: "testExperiment0", - Namespace: "testNamespace", - Kind: "testKind", - Message: "testMessage", - StartTime: &timeNow, - FinishTime: &timeNow, - Duration: "10s", - Pods: []*core.PodRecord{podRecord0}, - ExperimentID: "testID0", - } - event1 = &core.Event{ - ID: 1, - CreatedAt: timeAfter, - UpdatedAt: timeAfter, - DeletedAt: &timeAfter, - Experiment: "testExperiment0", - Namespace: "testNamespace", - Kind: "testKind", - Message: "testMessage", - StartTime: &timeAfter, - FinishTime: &timeAfter, - Duration: "10s", - Pods: []*core.PodRecord{podRecord1}, - ExperimentID: "testID1", - } - }) - - AfterEach(func() { - err := mock.ExpectationsWereMet() - Expect(err).ShouldNot(HaveOccurred()) - }) - - Context("findPodRecordsByEventID", func() { - It("found", func() { - mockedRow := []*sqlmock.Rows{ - sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action), - sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord1.ID, podRecord1.CreatedAt, podRecord1.UpdatedAt, podRecord1.DeletedAt, podRecord1.EventID, - podRecord1.PodIP, podRecord1.PodName, podRecord1.Namespace, podRecord1.Message, podRecord1.Action), - } - sqlSelect := `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(mockedRow[0]) - - podRecords, err := es.findPodRecordsByEventID(context.TODO(), podRecord0.EventID) - Expect(err).ShouldNot(HaveOccurred()) - Expect(podRecords[0]).Should(Equal(podRecord0)) - }) - - It("not found", func() { - mock.ExpectQuery(`.+`).WillReturnRows(sqlmock.NewRows(nil)) - podRecords, err := es.findPodRecordsByEventID(context.TODO(), 1) - Expect(len(podRecords)).Should(Equal(0)) - Expect(err).ShouldNot(HaveOccurred()) - }) - }) - - Context("min", func() { - It("x", func() { - x := 1 - y := 2 - res := min(x, y) - Expect(res).Should(Equal(x)) - }) - - It("y", func() { - x := 2 - y := 1 - res := min(x, y) - Expect(res).Should(Equal(y)) - }) - }) - - Context("list", func() { - It("found", func() { - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID) - sqlSelect := `SELECT * FROM "events"` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect = `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(rows) - - events, err := es.List(context.TODO()) - Expect(err).ShouldNot(HaveOccurred()) - Expect(events[0]).Should(Equal(event0)) - }) - - It("not found", func() { - mock.ExpectQuery(`.+`).WillReturnRows(sqlmock.NewRows(nil)) - events, err := es.List(context.TODO()) - Expect(err).ShouldNot(HaveOccurred()) - Expect(len(events)).Should(Equal(0)) - }) - }) - - Context("listByUID", func() { - It("found", func() { - mockedRow := []*sqlmock.Rows{ - sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID), - sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event1.ID, event1.CreatedAt, event1.UpdatedAt, event1.DeletedAt, event1.Experiment, event1.Namespace, - event1.Kind, event1.Message, event1.StartTime, event1.FinishTime, event1.Duration, event1.ExperimentID), - } - - sqlSelect := `SELECT * FROM "events" WHERE "events"."deleted_at" IS NULL AND ((experiment_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.ExperimentID).WillReturnRows(mockedRow[0]) - - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect = `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(rows) - - events, err := es.ListByUID(context.TODO(), event0.ExperimentID) - Expect(err).ShouldNot(HaveOccurred()) - Expect(events[0]).Should(Equal(event0)) - }) - - It("not found", func() { - mock.ExpectQuery(`.+`).WillReturnRows(sqlmock.NewRows(nil)) - events, err := es.ListByUID(context.TODO(), "testIDNotFound") - Expect(err).ShouldNot(HaveOccurred()) - Expect(len(events)).Should(Equal(0)) - }) - }) - - Context("listByExperiment", func() { - It("found", func() { - mockedRow := []*sqlmock.Rows{ - sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID), - sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event1.ID, event1.CreatedAt, event1.UpdatedAt, event1.DeletedAt, event1.Experiment, event1.Namespace, - event1.Kind, event1.Message, event1.StartTime, event1.FinishTime, event1.Duration, event1.ExperimentID), - } - - sqlSelect := `SELECT * FROM "events" WHERE "events"."deleted_at" IS NULL AND ((namespace = ? and experiment = ? ))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.Namespace, event0.Experiment).WillReturnRows(mockedRow[0]) - - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect = `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(rows) - - events, err := es.ListByExperiment(context.TODO(), event0.Namespace, event0.Experiment) - Expect(err).ShouldNot(HaveOccurred()) - Expect(events[0]).Should(Equal(event0)) - }) - - It("not found", func() { - mock.ExpectQuery(`.+`).WillReturnRows(sqlmock.NewRows(nil)) - events, err := es.ListByExperiment(context.TODO(), "testNamespaceNotFound", "testNameNotFound") - Expect(err).ShouldNot(HaveOccurred()) - Expect(len(events)).Should(Equal(0)) - }) - }) - - Context("listByNamesoace", func() { - It("found", func() { - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect := `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND (("pod_records"."namespace" = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.Namespace).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID) - - sqlSelect = `SELECT * FROM "events" WHERE "events"."deleted_at" IS NULL AND ((id = ?)) ORDER BY "events"."id" ASC LIMIT 1` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.ID).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect = `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(rows) - - events, err := es.ListByNamespace(context.TODO(), event0.Namespace) - Expect(err).ShouldNot(HaveOccurred()) - Expect(events[0]).Should(Equal(event0)) - }) - - It("not found", func() { - mock.ExpectQuery(`.+`).WillReturnRows(sqlmock.NewRows(nil)) - events, err := es.ListByNamespace(context.TODO(), "testNamespaceNotFound") - Expect(err).ShouldNot(HaveOccurred()) - Expect(len(events)).Should(Equal(0)) - }) - }) - - Context("listByPod", func() { - It("found", func() { - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect := `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND (("pod_records"."pod_name" = ?) AND ("pod_records"."namespace" = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.PodName, podRecord0.Namespace).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID) - - sqlSelect = `SELECT * FROM "events" WHERE "events"."deleted_at" IS NULL AND ((id = ?)) ORDER BY "events"."id" ASC LIMIT 1` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.ID).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect = `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(rows) - - events, err := es.ListByPod(context.TODO(), podRecord0.Namespace, podRecord0.PodName) - Expect(err).ShouldNot(HaveOccurred()) - Expect(events[0]).Should(Equal(event0)) - }) - - It("not found", func() { - mock.ExpectQuery(`.+`).WillReturnRows(sqlmock.NewRows(nil)) - events, err := es.ListByPod(context.TODO(), "testNamespaceNotFound", "testnameNotFound") - Expect(err).ShouldNot(HaveOccurred()) - Expect(len(events)).Should(Equal(0)) - }) - }) - - Context("find", func() { - It("found", func() { - mockedRow := []*sqlmock.Rows{ - sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID), - sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event1.ID, event1.CreatedAt, event1.UpdatedAt, event1.DeletedAt, event1.Experiment, event1.Namespace, - event1.Kind, event1.Message, event1.StartTime, event1.FinishTime, event1.Duration, event1.ExperimentID), - } - - sqlSelect := `SELECT * FROM "events" WHERE "events"."deleted_at" IS NULL AND ((id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.ID).WillReturnRows(mockedRow[0]) - - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect = `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(rows) - - event, err := es.Find(context.TODO(), event0.ID) - Expect(err).ShouldNot(HaveOccurred()) - Expect(event).Should(Equal(event0)) - }) - - It("not found", func() { - mock.ExpectQuery(`.+`).WillReturnRows(sqlmock.NewRows(nil)) - _, err := es.Find(context.TODO(), 30) - Expect(err).Should(HaveOccurred()) - }) - }) - - Context("findByExperimentAndStartTime", func() { - It("found", func() { - mockedRow := []*sqlmock.Rows{ - sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID), - sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event1.ID, event1.CreatedAt, event1.UpdatedAt, event1.DeletedAt, event1.Experiment, event1.Namespace, - event1.Kind, event1.Message, event1.StartTime, event1.FinishTime, event1.Duration, event1.ExperimentID), - } - - sqlSelect := `SELECT * FROM "events" WHERE "events"."deleted_at" IS NULL AND ((namespace = ? and experiment = ? and start_time = ?)) ORDER BY "events"."id" ASC LIMIT 1` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.Namespace, event0.Experiment, event0.StartTime).WillReturnRows(mockedRow[0]) - - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect = `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(rows) - - event, err := es.FindByExperimentAndStartTime(context.TODO(), event0.Experiment, event0.Namespace, event0.StartTime) - Expect(err).ShouldNot(HaveOccurred()) - Expect(event.ID).Should(Equal(event0.ID)) - }) - - It("event not found", func() { - mock.ExpectQuery(`.+`).WillReturnRows(sqlmock.NewRows(nil)) - _, err := es.FindByExperimentAndStartTime(context.TODO(), "expNotFound", "namespaceNotFound", event0.StartTime) - Expect(err).Should(HaveOccurred()) - Expect(gorm.IsRecordNotFoundError(err)).Should(Equal(true)) - }) - }) - - Context("listByFilter", func() { - It("limitStr wrong", func() { - filter := core.Filter{ - LimitStr: "testWrong", - } - _, err := es.ListByFilter(context.TODO(), filter) - Expect(err).Should(HaveOccurred()) - Expect(strings.Contains(err.Error(), "the format of the limitStr is wrong")).To(Equal(true)) - }) - - It("startTimeStr wrong", func() { - filter := core.Filter{ - StartTimeStr: "testWrong", - } - _, err := es.ListByFilter(context.TODO(), filter) - Expect(err).Should(HaveOccurred()) - Expect(strings.Contains(err.Error(), "the format of the startTime is wrong")).To(Equal(true)) - }) - - It("finishTimeStr wrong", func() { - filter := core.Filter{ - FinishTimeStr: "testWrong", - } - _, err := es.ListByFilter(context.TODO(), filter) - Expect(err).Should(HaveOccurred()) - Expect(strings.Contains(err.Error(), "the format of the finishTime is wrong")).To(Equal(true)) - }) - - It("empty args", func() { - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID) - sqlSelect := `SELECT * FROM "events"` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect = `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(rows) - - filter := core.Filter{} - events, err := es.ListByFilter(context.TODO(), filter) - Expect(err).ShouldNot(HaveOccurred()) - Expect(events[0]).Should(Equal(event0)) - }) - - It("podName", func() { - filter := core.Filter{ - PodName: "testName", - PodNamespace: "testNamespace", - LimitStr: "1", - } - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect := `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND (("pod_records"."pod_name" = ?) AND ("pod_records"."namespace" = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.PodName, podRecord0.Namespace).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID) - - sqlSelect = `SELECT * FROM "events" WHERE "events"."deleted_at" IS NULL AND ((id = ?)) ORDER BY "events"."id" ASC LIMIT 1` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.ID).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect = `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(rows) - - events, err := es.ListByFilter(context.TODO(), filter) - Expect(err).ShouldNot(HaveOccurred()) - Expect(events[0]).Should(Equal(event0)) - }) - - It("podNamespace", func() { - filter := core.Filter{ - PodNamespace: "testNamespace", - LimitStr: "1", - } - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect := `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND (("pod_records"."namespace" = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.Namespace).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID) - - sqlSelect = `SELECT * FROM "events" WHERE "events"."deleted_at" IS NULL AND ((id = ?)) ORDER BY "events"."id" ASC LIMIT 1` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.ID).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect = `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(rows) - - events, err := es.ListByFilter(context.TODO(), filter) - Expect(err).ShouldNot(HaveOccurred()) - Expect(events[0]).Should(Equal(event0)) - }) - - It("experimentName continue", func() { - filter := core.Filter{ - PodNamespace: "testNamespace", - ExperimentName: "experimentNameNotFound", - LimitStr: "1", - } - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect := `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND (("pod_records"."namespace" = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.Namespace).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID) - - sqlSelect = `SELECT * FROM "events" WHERE "events"."deleted_at" IS NULL AND ((id = ?)) ORDER BY "events"."id" ASC LIMIT 1` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.ID).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect = `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(rows) - - events, err := es.ListByFilter(context.TODO(), filter) - Expect(err).ShouldNot(HaveOccurred()) - Expect(len(events)).Should(Equal(0)) - }) - - It("experimentNamespace continue", func() { - filter := core.Filter{ - PodNamespace: "testNamespace", - ExperimentNamespace: "experimentNamespaceNotFound", - LimitStr: "1", - } - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect := `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND (("pod_records"."namespace" = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.Namespace).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID) - - sqlSelect = `SELECT * FROM "events" WHERE "events"."deleted_at" IS NULL AND ((id = ?)) ORDER BY "events"."id" ASC LIMIT 1` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.ID).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect = `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(rows) - - events, err := es.ListByFilter(context.TODO(), filter) - Expect(err).ShouldNot(HaveOccurred()) - Expect(len(events)).Should(Equal(0)) - }) - - It("uid continue", func() { - filter := core.Filter{ - PodNamespace: "testNamespace", - UID: "UIDNotFound", - LimitStr: "1", - } - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect := `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND (("pod_records"."namespace" = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.Namespace).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID) - - sqlSelect = `SELECT * FROM "events" WHERE "events"."deleted_at" IS NULL AND ((id = ?)) ORDER BY "events"."id" ASC LIMIT 1` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.ID).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect = `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(rows) - - events, err := es.ListByFilter(context.TODO(), filter) - Expect(err).ShouldNot(HaveOccurred()) - Expect(len(events)).Should(Equal(0)) - }) - - It("kind continue", func() { - filter := core.Filter{ - PodNamespace: "testNamespace", - Kind: "KindNotFound", - LimitStr: "1", - } - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect := `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND (("pod_records"."namespace" = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.Namespace).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID) - - sqlSelect = `SELECT * FROM "events" WHERE "events"."deleted_at" IS NULL AND ((id = ?)) ORDER BY "events"."id" ASC LIMIT 1` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.ID).WillReturnRows(rows) - - rows = sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "event_id", "pod_ip", "pod_name", - "namespace", "message", "action"}). - AddRow(podRecord0.ID, podRecord0.CreatedAt, podRecord0.UpdatedAt, podRecord0.DeletedAt, podRecord0.EventID, - podRecord0.PodIP, podRecord0.PodName, podRecord0.Namespace, podRecord0.Message, podRecord0.Action) - - sqlSelect = `SELECT * FROM "pod_records" WHERE "pod_records"."deleted_at" IS NULL AND ((event_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(podRecord0.EventID).WillReturnRows(rows) - - events, err := es.ListByFilter(context.TODO(), filter) - Expect(err).ShouldNot(HaveOccurred()) - Expect(len(events)).Should(Equal(0)) - }) - }) - - Context("dryListByFilter", func() { - It("limitStr wrong", func() { - filter := core.Filter{ - LimitStr: "testWrong", - } - _, err := es.DryListByFilter(context.TODO(), filter) - Expect(err).Should(HaveOccurred()) - Expect(strings.Contains(err.Error(), "the format of the limitStr is wrong")).To(Equal(true)) - }) - - It("startTimeStr wrong", func() { - filter := core.Filter{ - StartTimeStr: "testWrong", - } - _, err := es.DryListByFilter(context.TODO(), filter) - Expect(err).Should(HaveOccurred()) - Expect(strings.Contains(err.Error(), "the format of the startTime is wrong")).To(Equal(true)) - }) - - It("finishTimeStr wrong", func() { - filter := core.Filter{ - FinishTimeStr: "testWrong", - } - _, err := es.DryListByFilter(context.TODO(), filter) - Expect(err).Should(HaveOccurred()) - Expect(strings.Contains(err.Error(), "the format of the finishTime is wrong")).To(Equal(true)) - }) - - It("empty args", func() { - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID) - sqlSelect := `SELECT * FROM "events"` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WillReturnRows(rows) - - filter := core.Filter{} - events, err := es.DryListByFilter(context.TODO(), filter) - Expect(err).ShouldNot(HaveOccurred()) - Expect(events[0].ID).Should(Equal(event0.ID)) - }) - - It("test args", func() { - filter := core.Filter{ - ExperimentName: "testExperiment0", - UID: "testID0", - } - rows := sqlmock. - NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID) - sqlSelect := `SELECT * FROM "events" WHERE "events"."deleted_at" IS NULL AND ((experiment = ? AND experiment_id = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(filter.ExperimentName, filter.UID).WillReturnRows(rows) - - events, err := es.DryListByFilter(context.TODO(), filter) - Expect(err).ShouldNot(HaveOccurred()) - Expect(events[0].ID).Should(Equal(event0.ID)) - }) - - It("not found", func() { - filter := core.Filter{} - mock.ExpectQuery(`.+`).WillReturnRows(sqlmock.NewRows(nil)) - events, err := es.DryListByFilter(context.TODO(), filter) - Expect(err).ShouldNot(HaveOccurred()) - Expect(len(events)).Should(Equal(0)) - }) - }) - - Context("getUID", func() { - It("found", func() { - mockedRow := sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "experiment", "namespace", "kind", - "message", "start_time", "finish_time", "duration", "experiment_id"}). - AddRow(event0.ID, event0.CreatedAt, event0.UpdatedAt, event0.DeletedAt, event0.Experiment, event0.Namespace, - event0.Kind, event0.Message, event0.StartTime, event0.FinishTime, event0.Duration, event0.ExperimentID). - AddRow(event1.ID, event1.CreatedAt, event1.UpdatedAt, event1.DeletedAt, event1.Experiment, event1.Namespace, - event1.Kind, event1.Message, event1.StartTime, event1.FinishTime, event1.Duration, event1.ExperimentID) - - sqlSelect := `SELECT * FROM "events" WHERE "events"."deleted_at" IS NULL AND (("events"."experiment" = ?) AND ("events"."namespace" = ?))` - mock.ExpectQuery(regexp.QuoteMeta(sqlSelect)).WithArgs(event0.Experiment, event0.Namespace).WillReturnRows(mockedRow) - uid, err := es.getUID(context.TODO(), event0.Namespace, event0.Experiment) - Expect(err).ShouldNot(HaveOccurred()) - Expect(uid).Should(Equal(event1.ExperimentID)) - }) - - It("not found", func() { - mock.ExpectQuery(`.+`).WillReturnRows(sqlmock.NewRows(nil)) - uid, err := es.getUID(context.TODO(), "NamespaceNotFound", "NameNotFound") - Expect(strings.Contains(err.Error(), "get UID failure")).To(Equal(true)) - Expect(uid).Should(Equal("")) - }) - }) -}) - -func TestConstructQueryArgs(t *testing.T) { - cases := []struct { - kind string - ns string - name string - uid string - startTime string - finishTime string - expectedQuery string - expectedArgs []string - }{ - { - name: "", - ns: "", - uid: "", - kind: "", - startTime: "", - finishTime: "", - expectedQuery: "", - expectedArgs: []string{}, - }, - { - name: "testName", - ns: "", - uid: "", - kind: "", - startTime: "", - finishTime: "", - expectedQuery: "experiment = ?", - expectedArgs: []string{"testName"}, - }, - { - name: "", - ns: "testNamespace", - uid: "", - kind: "", - startTime: "", - finishTime: "", - expectedQuery: "namespace = ?", - expectedArgs: []string{"testNamespace"}, - }, - { - name: "", - ns: "", - uid: "testUID", - kind: "", - startTime: "", - finishTime: "", - expectedQuery: "experiment_id = ?", - expectedArgs: []string{"testUID"}, - }, - { - name: "", - ns: "", - uid: "", - kind: "testKind", - startTime: "", - finishTime: "", - expectedQuery: "kind = ?", - expectedArgs: []string{"testKind"}, - }, - { - name: "", - ns: "", - uid: "", - kind: "", - startTime: "20200101", - finishTime: "", - expectedQuery: "start_time >= ?", - expectedArgs: []string{"20200101"}, - }, - { - name: "", - ns: "", - uid: "", - kind: "", - startTime: "", - finishTime: "20200102", - expectedQuery: "finish_time <= ?", - expectedArgs: []string{"20200102"}, - }, - { - name: "testName", - ns: "testNamespace", - uid: "", - kind: "", - startTime: "", - finishTime: "", - expectedQuery: "experiment = ? AND namespace = ?", - expectedArgs: []string{"testName", "testNamespace"}, - }, - { - name: "testName", - ns: "testNamespace", - uid: "testUID", - kind: "", - startTime: "", - finishTime: "", - expectedQuery: "experiment = ? AND namespace = ? AND experiment_id = ?", - expectedArgs: []string{"testName", "testNamespace", "testUID"}, - }, - { - name: "testName", - ns: "testNamespace", - uid: "testUID", - kind: "testKind", - startTime: "", - finishTime: "", - expectedQuery: "experiment = ? AND namespace = ? AND experiment_id = ? AND kind = ?", - expectedArgs: []string{"testName", "testNamespace", "testUID", "testKind"}, - }, - { - name: "testName", - ns: "testNamespace", - uid: "testUID", - kind: "testKind", - startTime: "20200101", - finishTime: "", - expectedQuery: "experiment = ? AND namespace = ? AND experiment_id = ? AND kind = ? AND start_time >= ?", - expectedArgs: []string{"testName", "testNamespace", "testUID", "testKind", "20200101"}, - }, - { - name: "testName", - ns: "testNamespace", - uid: "testUID", - kind: "testKind", - startTime: "20200101", - finishTime: "20200102", - expectedQuery: "experiment = ? AND namespace = ? AND experiment_id = ? AND kind = ? AND start_time >= ? AND finish_time <= ?", - expectedArgs: []string{"testName", "testNamespace", "testUID", "testKind", "20200101", "20200102"}, - }, - } - - for _, c := range cases { - query, args := constructQueryArgs(c.name, c.ns, c.uid, c.kind, c.startTime, c.finishTime) - argString := []string{} - for _, arg := range args { - argString = append(argString, arg.(string)) - } - if query != c.expectedQuery { - t.Errorf("expected query %s but got %s", c.expectedQuery, query) - } - if !reflect.DeepEqual(c.expectedArgs, argString) { - t.Errorf("expected args %v but got %v", c.expectedArgs, argString) - } - } -} diff --git a/pkg/store/experiment/experiment.go b/pkg/store/experiment/experiment.go deleted file mode 100644 index 65c0cf7958..0000000000 --- a/pkg/store/experiment/experiment.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package experiment - -import ( - "context" - "time" - - "github.com/jinzhu/gorm" - - "github.com/chaos-mesh/chaos-mesh/pkg/core" - "github.com/chaos-mesh/chaos-mesh/pkg/store/dbstore" - - ctrl "sigs.k8s.io/controller-runtime" -) - -var log = ctrl.Log.WithName("store/experiment") - -// NewStore returns a new ExperimentStore. -func NewStore(db *dbstore.DB) core.ExperimentStore { - db.AutoMigrate(&core.Experiment{}) - - es := &experimentStore{db} - - return es -} - -// DeleteIncompleteExperiments call core.ExperimentStore.DeleteIncompleteExperiments to deletes all incomplete experiments. -func DeleteIncompleteExperiments(es core.ExperimentStore, _ core.EventStore) { - if err := es.DeleteIncompleteExperiments(context.Background()); err != nil && !gorm.IsRecordNotFoundError(err) { - log.Error(err, "failed to delete all incomplete experiments") - } -} - -type experimentStore struct { - db *dbstore.DB -} - -// ListMeta implements the core.ExperimentStore.ListMeta method. -func (e *experimentStore) ListMeta(_ context.Context, kind, namespace, name string, archived bool) ([]*core.ExperimentMeta, error) { - db := e.db.Table("experiments") - experiments := make([]*core.ExperimentMeta, 0) - query, args := constructQueryArgs(kind, namespace, name, "") - - if err := db.Where(query, args).Where(query, args).Where("archived = ?", archived).Find(&experiments).Error; err != nil && !gorm.IsRecordNotFoundError(err) { - return nil, err - } - - return experiments, nil -} - -// FindByUID implements the core.ExperimentStore.FindByUID method. -func (e *experimentStore) FindByUID(_ context.Context, uid string) (*core.Experiment, error) { - experiment := new(core.Experiment) - - if err := e.db.Where("uid = ?", uid).First(experiment).Error; err != nil { - return nil, err - } - - return experiment, nil -} - -// FindMetaByUID implements the core.ExperimentStore.FindMetaByUID method. -func (e *experimentStore) FindMetaByUID(_ context.Context, uid string) (*core.ExperimentMeta, error) { - db := e.db.Table("experiments") - experiment := new(core.ExperimentMeta) - - if err := db.Where("uid = ?", uid).First(experiment).Error; err != nil { - return nil, err - } - - return experiment, nil -} - -// Set implements the core.ExperimentStore.Set method. -func (e *experimentStore) Set(_ context.Context, experiment *core.Experiment) error { - return e.db.Model(core.Experiment{}).Save(experiment).Error -} - -// Archive implements the core.ExperimentStore.Archive method. -func (e *experimentStore) Archive(_ context.Context, ns, name string) error { - if err := e.db.Model(core.Experiment{}). - Where("namespace = ? AND name = ? AND archived = ?", ns, name, false). - Updates(map[string]interface{}{"archived": true, "finish_time": time.Now()}).Error; err != nil && !gorm.IsRecordNotFoundError(err) { - return err - } - - return nil -} - -// Delete deletes the experiment from the datastore. -func (e *experimentStore) Delete(_ context.Context, exp *core.Experiment) error { - err := e.db.Table("experiments").Unscoped().Delete(*exp).Error - return err -} - -// DeleteByFinishTime deletes experiments whose time difference is greater than the given time from FinishTime. -func (e *experimentStore) DeleteByFinishTime(_ context.Context, ttl time.Duration) error { - experiments, err := e.ListMeta(context.Background(), "", "", "", true) - if err != nil { - return err - } - - nowTime := time.Now() - for _, exp := range experiments { - if exp.FinishTime.Add(ttl).Before(nowTime) { - if err := e.db.Table("experiments").Unscoped().Delete(*exp).Error; err != nil { - return err - } - } - } - - return nil -} - -// DeleteByUIDs deletes archives by the uid list. -func (e *experimentStore) DeleteByUIDs(_ context.Context, uids []string) error { - return e.db.Table("experiments").Where("uid IN (?)", uids).Unscoped().Delete(core.Experiment{}).Error -} - -// DeleteIncompleteExperiments implements the core.ExperimentStore.DeleteIncompleteExperiments method. -func (e *experimentStore) DeleteIncompleteExperiments(_ context.Context) error { - return e.db.Where("finish_time IS NULL").Unscoped().Delete(core.Event{}).Error -} - -func constructQueryArgs(kind, ns, name, uid string) (string, []string) { - query := "" - args := make([]string, 0) - - if kind != "" { - query += "kind = ?" - args = append(args, kind) - } - - if ns != "" { - if len(args) > 0 { - query += " AND namespace = ?" - } else { - query += "namespace = ?" - } - args = append(args, ns) - } - - if name != "" { - if len(args) > 0 { - query += " AND name = ?" - } else { - query += "name = ?" - } - args = append(args, name) - } - - if uid != "" { - if len(args) > 0 { - query += " AND uid = ?" - } else { - query += "uid = ?" - } - args = append(args, uid) - } - - return query, args -} diff --git a/pkg/store/store.go b/pkg/store/store.go deleted file mode 100644 index 30ff9c0dda..0000000000 --- a/pkg/store/store.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package store - -import ( - "go.uber.org/fx" - - "github.com/chaos-mesh/chaos-mesh/pkg/store/event" - "github.com/chaos-mesh/chaos-mesh/pkg/store/experiment" -) - -// Module includes the providers provided by store. -var Module = fx.Options( - fx.Provide( - experiment.NewStore, - event.NewStore, - ), - fx.Invoke(experiment.DeleteIncompleteExperiments), -) diff --git a/pkg/swaggerserver/empty_handler.go b/pkg/swaggerserver/empty_handler.go deleted file mode 100644 index b2e657e231..0000000000 --- a/pkg/swaggerserver/empty_handler.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build !swagger_server - -package swaggerserver - -import ( - "net/http" - - "github.com/gin-gonic/gin" -) - -// Handler returns an empty `http.Handler`. -func Handler() gin.HandlerFunc { - return func(c *gin.Context) { - c.String(http.StatusOK, "Swagger UI is not built. Please run `SWAGGER=1 make`.") - } -} diff --git a/pkg/swaggerserver/swagger_handler.go b/pkg/swaggerserver/swagger_handler.go deleted file mode 100644 index e7d8cc7d1f..0000000000 --- a/pkg/swaggerserver/swagger_handler.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build swagger_server - -package swaggerserver - -import ( - "github.com/gin-gonic/gin" - swaggerFiles "github.com/swaggo/files" - ginSwagger "github.com/swaggo/gin-swagger" - - _ "github.com/chaos-mesh/chaos-mesh/docs" // for swagger api -) - -// Handler returns a swagger `http.Handler`. -func Handler() gin.HandlerFunc { - return ginSwagger.WrapHandler( - swaggerFiles.Handler, - ginSwagger.URL("doc.json"), - ) -} diff --git a/pkg/swaggerserver/swaggerserver.go b/pkg/swaggerserver/swaggerserver.go deleted file mode 100644 index 2e3f7c4f44..0000000000 --- a/pkg/swaggerserver/swaggerserver.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package swaggerserver diff --git a/pkg/sysfs/remount_darwin.go b/pkg/sysfs/remount_darwin.go new file mode 100644 index 0000000000..47539d5dad --- /dev/null +++ b/pkg/sysfs/remount_darwin.go @@ -0,0 +1,24 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package sysfs + +import ( + "github.com/pkg/errors" +) + +func RemountWithOption(options ...func(uintptr) uintptr) error { + return errors.New("remount is not supported on darwin for now") +} diff --git a/pkg/sysfs/remount_linux.go b/pkg/sysfs/remount_linux.go new file mode 100644 index 0000000000..1c9c40e015 --- /dev/null +++ b/pkg/sysfs/remount_linux.go @@ -0,0 +1,26 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package sysfs + +import "syscall" + +func RemountWithOption(options ...func(uintptr) uintptr) error { + flag := uintptr(syscall.MS_REMOUNT) + for _, opt := range options { + flag = opt(flag) + } + return syscall.Mount("sysfs", "/sys", "sysfs", flag, "") +} diff --git a/pkg/testutils/generate.go b/pkg/testutils/generate.go index 9e012ca16d..6590164993 100644 --- a/pkg/testutils/generate.go +++ b/pkg/testutils/generate.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package testutils @@ -19,6 +21,8 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" ) // PodArg by default use `Status=corev1.PodRunning` and `Namespace=metav1.NamespaceDefault`. @@ -109,3 +113,51 @@ func GenerateNNodes( } return nodeObjects, nodes } + +// PhysicalMachineArg by default use `Namespace=metav1.NamespaceDefault`. +// For the others, the default values are empty. +type PhysicalMachineArg struct { + Name string + Namespace string + Ans map[string]string + Labels map[string]string + Address string +} + +func NewPhysicalMachine(p PhysicalMachineArg) v1alpha1.PhysicalMachine { + if p.Namespace == "" { + p.Namespace = metav1.NamespaceDefault + } + return v1alpha1.PhysicalMachine{ + TypeMeta: metav1.TypeMeta{ + Kind: "PhysicalMachine", + APIVersion: "v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: p.Name, + Namespace: p.Namespace, + Labels: p.Labels, + Annotations: p.Ans, + }, + Spec: v1alpha1.PhysicalMachineSpec{ + Address: p.Address, + }, + } +} + +func GenerateNPhysicalMachines( + namePrefix string, + n int, + arg PhysicalMachineArg, +) ([]runtime.Object, []v1alpha1.PhysicalMachine) { + var physicalMachineObjects []runtime.Object + var physicalMachines []v1alpha1.PhysicalMachine + for i := 0; i < n; i++ { + arg.Name = fmt.Sprintf("%s%d", namePrefix, i) + physicalMachine := NewPhysicalMachine(arg) + physicalMachineObjects = append(physicalMachineObjects, &physicalMachine) + physicalMachines = append(physicalMachines, physicalMachine) + } + + return physicalMachineObjects, physicalMachines +} diff --git a/pkg/time/asset_linux.go b/pkg/time/asset_linux.go new file mode 100644 index 0000000000..ac64419fad --- /dev/null +++ b/pkg/time/asset_linux.go @@ -0,0 +1,104 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package time + +import ( + "bytes" + "debug/elf" + "embed" + "encoding/binary" + + "github.com/go-logr/logr" + "github.com/pkg/errors" +) + +//go:embed fakeclock/*.o +var fakeclock embed.FS + +const textSection = ".text" +const relocationSection = ".rela.text" + +// LoadFakeImageFromEmbedFs builds FakeImage from the embed filesystem. It parses the ELF file and extract the variables from the relocation section, reserves the space for them at the end of content, then calculates and saves offsets as "manually relocation" +func LoadFakeImageFromEmbedFs(filename string, symbolName string, logger logr.Logger) (*FakeImage, error) { + path := "fakeclock/" + filename + object, err := fakeclock.ReadFile(path) + if err != nil { + return nil, errors.Wrapf(err, "read file from embedded fs %s", path) + } + + elfFile, err := elf.NewFile(bytes.NewReader(object)) + if err != nil { + return nil, errors.Wrapf(err, "parse elf file %s", path) + } + + syms, err := elfFile.Symbols() + if err != nil { + return nil, errors.Wrapf(err, "get symbols %s", path) + } + + var imageContent []byte + imageOffset := make(map[string]int) + + for _, r := range elfFile.Sections { + + if r.Type == elf.SHT_PROGBITS && r.Name == textSection { + imageContent, err = r.Data() + if err != nil { + return nil, errors.Wrapf(err, "read text section data %s", path) + } + break + } + } + + for _, r := range elfFile.Sections { + if r.Type == elf.SHT_RELA && r.Name == relocationSection { + rela_section, err := r.Data() + if err != nil { + return nil, errors.Wrapf(err, "read rela section data %s", path) + } + rela_section_reader := bytes.NewReader(rela_section) + + var rela elf.Rela64 + for rela_section_reader.Len() > 0 { + err := binary.Read(rela_section_reader, elfFile.ByteOrder, &rela) + if err != nil { + return nil, errors.Wrapf(err, "read rela section rela64 entry %s", path) + } + + symNo := rela.Info >> 32 + if symNo == 0 || symNo > uint64(len(syms)) { + continue + } + + sym := syms[symNo-1] + byteorder := elfFile.ByteOrder + if elfFile.Machine == elf.EM_X86_64 || elfFile.Machine == elf.EM_AARCH64 { + AssetLD(rela, imageOffset, &imageContent, sym, byteorder) + } else { + return nil, errors.Errorf("unsupported architecture") + } + } + + break + } + } + return NewFakeImage( + symbolName, + imageContent, + imageOffset, + logger, + ), nil +} diff --git a/pkg/time/asset_linux_amd64.go b/pkg/time/asset_linux_amd64.go new file mode 100644 index 0000000000..863d0d9a4f --- /dev/null +++ b/pkg/time/asset_linux_amd64.go @@ -0,0 +1,41 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package time + +import ( + "debug/elf" + "encoding/binary" +) + +func AssetLD(rela elf.Rela64, imageOffset map[string]int, imageContent *[]byte, sym elf.Symbol, byteorder binary.ByteOrder) { + // The relocation of a X86 image is like: + // Relocation section '.rela.text' at offset 0x288 contains 3 entries: + // Offset Info Type Sym. Value Sym. Name + Addend + // 000000000016 000900000002 R_X86_64_PC32 0000000000000000 CLOCK_IDS_MASK - 4 + // 00000000001f 000a00000002 R_X86_64_PC32 0000000000000008 TV_NSEC_DELTA - 4 + // 00000000002a 000b00000002 R_X86_64_PC32 0000000000000010 TV_SEC_DELTA - 4 + // + // For example, we need to write the offset of `CLOCK_IDS_MASK` - 4 in 0x16 of the section + // If we want to put the `CLOCK_IDS_MASK` at the end of the section, it will be + // len(imageContent) - 4 - 0x16 + + imageOffset[sym.Name] = len(*imageContent) + targetOffset := uint32(len(*imageContent)) - uint32(rela.Off) + uint32(rela.Addend) + byteorder.PutUint32((*imageContent)[rela.Off:rela.Off+4], targetOffset) + + // TODO: support other length besides uint64 (which is 8 bytes) + *imageContent = append(*imageContent, make([]byte, varLength)...) +} diff --git a/pkg/time/asset_linux_arm64.go b/pkg/time/asset_linux_arm64.go new file mode 100644 index 0000000000..2d648c35d7 --- /dev/null +++ b/pkg/time/asset_linux_arm64.go @@ -0,0 +1,67 @@ +// Copyright 2022 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package time + +import ( + "debug/elf" + "encoding/binary" +) + +func AssetLD(rela elf.Rela64, imageOffset map[string]int, imageContent *[]byte, sym elf.Symbol, byteorder binary.ByteOrder) { + imageOffset[sym.Name] = len(*imageContent) + + targetOffset := uint32(len(*imageContent)) - uint32(rela.Off) + uint32(rela.Addend) + + // The relocation of a aarch64 image is like: + // Offset Info Type Sym. Value Sym. Name + Addend + // 000000000010 000b00000135 R_AARCH64_GOT_LD_ 0000000000000000 CLOCK_IDS_MASK + 0 + // 00000000002c 000c00000135 R_AARCH64_GOT_LD_ 0000000000000000 TV_NSEC_DELTA + 0 + // 000000000034 000d00000135 R_AARCH64_GOT_LD_ 0000000000000000 TV_SEC_DELTA + 0 + + // we assume the type is always R_AARCH64_GOT_LD_PREL19, with `-mcmodel=tiny` + + // In this situation, we need to push two uint64 to the end: + // One for the location of variable, and one for the variable + + // For example, if the entry starts at 0x00, and we have two variables whose value are + // 0xFF and 0xFE. We will have 32 bytes after the content: + // | 0x00 | 0x08 | 0x10 | 0x18 | + // | 0x08 | 0xFF | 0x18 | 0xFE | + + // See the manual of LDR (literal) and LDR (register) to understand the + // relocation based on the following assemblies: + // + // ldr x1, #OFFSET_OF_ADDR ; in this step, the address of variable is loaded + // into the x1 register + // ldr x1, [x1] ; in this step, the variable itself is loaded into + // the register + + targetOffset >>= 2 + instr := byteorder.Uint32((*imageContent)[rela.Off : rela.Off+4]) + + // See the document of instruction + // [ldr](https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/LDR--literal---Load-Register--literal--?lang=en) + // the offset is saved in `imm19`, and the max length is 19 (bit) + // + // 1. cut `instr` at [0:4] and [23:31] + // 2. cut the little 19 bit of `targetOffset`, and shift it to [5:23] + // 3. concat them + instr = uint32(int(instr) & ^((1<<19-1)<<5)) | ((targetOffset & (1<<19 - 1)) << 5) + byteorder.PutUint32((*imageContent)[rela.Off:rela.Off+4], instr) + + // TODO: support other length besides uint64 (which is 8 bytes) + *imageContent = append(*imageContent, make([]byte, varLength)...) +} diff --git a/pkg/time/fake_image_linux.go b/pkg/time/fake_image_linux.go new file mode 100644 index 0000000000..83380bd5bc --- /dev/null +++ b/pkg/time/fake_image_linux.go @@ -0,0 +1,236 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package time + +import ( + "bytes" + "runtime" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/pkg/cerr" + "github.com/chaos-mesh/chaos-mesh/pkg/mapreader" + "github.com/chaos-mesh/chaos-mesh/pkg/ptrace" +) + +// vdsoEntryName is the name of the vDSO entry +const vdsoEntryName = "[vdso]" + +// FakeImage introduce the replacement of VDSO ELF entry and customizable variables. +// FakeImage could be constructed by LoadFakeImageFromEmbedFs(), and then used by FakeClockInjector. +type FakeImage struct { + // symbolName is the name of the symbol to be replaced. + symbolName string + // content presents .text section which has been "manually relocation", the address of extern variables have been calculated manually + content []byte + // offset stores the table with variable name, and it's address in content. + // the key presents extern variable name, ths value is the address/offset within the content. + offset map[string]int + // OriginFuncCode stores the raw func code like getTimeOfDay & ClockGetTime. + OriginFuncCode []byte + // OriginAddress stores the origin address of OriginFuncCode. + OriginAddress uint64 + // fakeEntry stores the fake entry + fakeEntry *mapreader.Entry + + logger logr.Logger +} + +func NewFakeImage(symbolName string, content []byte, offset map[string]int, logger logr.Logger) *FakeImage { + return &FakeImage{symbolName: symbolName, content: content, offset: offset, logger: logger} +} + +// AttachToProcess would use ptrace to replace the VDSO ELF entry with FakeImage. +// Each item in parameter "variables" needs a corresponding entry in FakeImage.offset. +func (it *FakeImage) AttachToProcess(pid int, variables map[string]uint64) (err error) { + if len(variables) != len(it.offset) { + return errors.New("fake image: extern variable number not match") + } + + runtime.LockOSThread() + defer func() { + runtime.UnlockOSThread() + }() + + program, err := ptrace.Trace(pid, it.logger.WithName("ptrace").WithValues("pid", pid)) + if err != nil { + return errors.Wrapf(err, "ptrace on target process, pid: %d", pid) + } + defer func() { + err = program.Detach() + if err != nil { + it.logger.Error(err, "fail to detach program", "pid", program.Pid()) + } + }() + + vdsoEntry, err := FindVDSOEntry(program) + if err != nil { + return errors.Wrapf(err, "PID : %d", pid) + } + + fakeEntry, err := it.FindInjectedImage(program, len(variables)) + if err != nil { + return errors.Wrapf(err, "PID : %d", pid) + } + // target process has not been injected yet + if fakeEntry == nil { + fakeEntry, err = it.InjectFakeImage(program, vdsoEntry) + if err != nil { + return errors.Wrapf(err, "injecting fake image , PID : %d", pid) + } + defer func() { + if err != nil { + errIn := it.TryReWriteFakeImage(program) + if errIn != nil { + it.logger.Error(errIn, "rewrite fail, recover fail") + } + it.OriginFuncCode = nil + it.OriginAddress = 0 + } + }() + } + + for k, v := range variables { + err = it.SetVarUint64(program, fakeEntry, k, v) + + if err != nil { + return errors.Wrapf(err, "set %s for time skew, pid: %d", k, pid) + } + } + + return +} + +func FindVDSOEntry(program *ptrace.TracedProgram) (*mapreader.Entry, error) { + var vdsoEntry *mapreader.Entry + for index := range program.Entries { + // reverse loop is faster + e := program.Entries[len(program.Entries)-index-1] + if e.Path == vdsoEntryName { + vdsoEntry = &e + break + } + } + if vdsoEntry == nil { + return nil, cerr.NotFound("VDSOEntry").Err() + } + return vdsoEntry, nil +} + +// FindInjectedImage find injected image to avoid redundant inject. +func (it *FakeImage) FindInjectedImage(program *ptrace.TracedProgram, varNum int) (*mapreader.Entry, error) { + it.logger.Info("finding injected image") + + // minus tailing variable part + // every variable has 8 bytes + if it.fakeEntry != nil { + content, err := program.ReadSlice(it.fakeEntry.StartAddress, it.fakeEntry.EndAddress-it.fakeEntry.StartAddress) + if err != nil { + it.logger.Info("ReadSlice fail") + return nil, nil + } + if varNum*8 > len(it.content) { + return nil, errors.New("variable num bigger than content num") + } + contentWithoutVariable := (*content)[:len(it.content)-varNum*varLength] + expectedContentWithoutVariable := it.content[:len(it.content)-varNum*varLength] + it.logger.Info("successfully read slice", "content", contentWithoutVariable, "expected content", expectedContentWithoutVariable) + + if bytes.Equal(contentWithoutVariable, expectedContentWithoutVariable) { + it.logger.Info("slice found") + return it.fakeEntry, nil + } + it.logger.Info("slice not found") + } + return nil, nil +} + +// InjectFakeImage Usage CheckList: +// When error : TryReWriteFakeImage after InjectFakeImage. +func (it *FakeImage) InjectFakeImage(program *ptrace.TracedProgram, + vdsoEntry *mapreader.Entry) (*mapreader.Entry, error) { + fakeEntry, err := program.MmapSlice(it.content) + if err != nil { + return nil, errors.Wrapf(err, "mmap fake image") + } + it.fakeEntry = fakeEntry + originAddr, size, err := program.FindSymbolInEntry(it.symbolName, vdsoEntry) + if err != nil { + return nil, errors.Wrapf(err, "find origin %s in vdso", it.symbolName) + } + funcBytes, err := program.ReadSlice(originAddr, size) + if err != nil { + return nil, errors.Wrapf(err, "ReadSlice failed") + } + err = program.JumpToFakeFunc(originAddr, fakeEntry.StartAddress) + if err != nil { + errIn := it.TryReWriteFakeImage(program) + if errIn != nil { + it.logger.Error(errIn, "rewrite fail, recover fail") + } + return nil, errors.Wrapf(err, "override origin %s", it.symbolName) + } + + it.OriginFuncCode = *funcBytes + it.OriginAddress = originAddr + return fakeEntry, nil +} + +func (it *FakeImage) TryReWriteFakeImage(program *ptrace.TracedProgram) error { + if it.OriginFuncCode != nil { + err := program.PtraceWriteSlice(it.OriginAddress, it.OriginFuncCode) + if err != nil { + return err + } + it.OriginFuncCode = nil + it.OriginAddress = 0 + } + return nil +} + +// Recover the injected image. If injected image not found , +// Recover will not return error. +func (it *FakeImage) Recover(pid int, vars map[string]uint64) error { + runtime.LockOSThread() + defer func() { + runtime.UnlockOSThread() + }() + if it.OriginFuncCode == nil { + return nil + } + program, err := ptrace.Trace(pid, it.logger.WithName("ptrace").WithValues("pid", pid)) + if err != nil { + return errors.Wrapf(err, "ptrace on target process, pid: %d", pid) + } + defer func() { + err = program.Detach() + if err != nil { + it.logger.Error(err, "fail to detach program", "pid", program.Pid()) + } + }() + + fakeEntry, err := it.FindInjectedImage(program, len(vars)) + if err != nil { + return errors.Wrapf(err, "FindInjectedImage , pid: %d", pid) + } + if fakeEntry == nil { + return nil + } + + err = it.TryReWriteFakeImage(program) + return err +} diff --git a/pkg/time/fake_image_linux_amd64.go b/pkg/time/fake_image_linux_amd64.go new file mode 100644 index 0000000000..45a1ce36f3 --- /dev/null +++ b/pkg/time/fake_image_linux_amd64.go @@ -0,0 +1,34 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package time + +import ( + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/pkg/mapreader" + "github.com/chaos-mesh/chaos-mesh/pkg/ptrace" +) + +const varLength = 8 + +func (it *FakeImage) SetVarUint64(program *ptrace.TracedProgram, entry *mapreader.Entry, symbol string, value uint64) error { + if offset, ok := it.offset[symbol]; ok { + err := program.WriteUint64ToAddr(entry.StartAddress+uint64(offset), value) + return err + } + + return errors.New("symbol not found") +} diff --git a/pkg/time/fake_image_linux_arm64.go b/pkg/time/fake_image_linux_arm64.go new file mode 100644 index 0000000000..8d9be95b66 --- /dev/null +++ b/pkg/time/fake_image_linux_arm64.go @@ -0,0 +1,42 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package time + +import ( + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/pkg/mapreader" + "github.com/chaos-mesh/chaos-mesh/pkg/ptrace" +) + +// one variable will use two pointers place +const varLength = 16 + +func (it *FakeImage) SetVarUint64(program *ptrace.TracedProgram, entry *mapreader.Entry, symbol string, value uint64) error { + if offset, ok := it.offset[symbol]; ok { + variableOffset := entry.StartAddress + uint64(offset) + 8 + + err := program.WriteUint64ToAddr(entry.StartAddress+uint64(offset), variableOffset) + if err != nil { + return err + } + + err = program.WriteUint64ToAddr(variableOffset, value) + return err + } + + return errors.New("symbol not found") +} diff --git a/pkg/time/fakeclock/.embed.o b/pkg/time/fakeclock/.embed.o new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pkg/time/fakeclock/fake_clock_gettime.c b/pkg/time/fakeclock/fake_clock_gettime.c new file mode 100644 index 0000000000..1ed7fa8e56 --- /dev/null +++ b/pkg/time/fakeclock/fake_clock_gettime.c @@ -0,0 +1,80 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include +#include +#include + +extern int64_t TV_SEC_DELTA; +extern int64_t TV_NSEC_DELTA; +extern uint64_t CLOCK_IDS_MASK; + +#if defined(__amd64__) +inline int real_clock_gettime(clockid_t clk_id, struct timespec *tp) { + int ret; + asm volatile + ( + "syscall" + : "=a" (ret) + : "0"(__NR_clock_gettime), "D"(clk_id), "S"(tp) + : "rcx", "r11", "memory" + ); + + return ret; +} +#elif defined(__aarch64__) +inline int real_clock_gettime(clockid_t clk_id, struct timespec *tp) { + register clockid_t x0 __asm__ ("x0") = clk_id; + register struct timespec *x1 __asm__ ("x1") = tp; + register uint64_t w8 __asm__ ("w8") = __NR_clock_gettime; /* syscall number */ + __asm__ __volatile__ ( + "svc 0;" + : "+r" (x0) + : "r" (x0), "r" (x1), "r" (w8) + : "memory" + ); + + return x0; +} +#endif + +int fake_clock_gettime(clockid_t clk_id, struct timespec *tp) { + int ret = real_clock_gettime(clk_id, tp); + + int64_t sec_delta = TV_SEC_DELTA; + int64_t nsec_delta = TV_NSEC_DELTA; + uint64_t clock_ids_mask = CLOCK_IDS_MASK; + + int64_t billion = 1000000000; + + uint64_t clk_id_mask = 1 << clk_id; + if((clk_id_mask & clock_ids_mask) != 0) { + while (nsec_delta + tp->tv_nsec > billion) { + sec_delta += 1; + nsec_delta -= billion; + } + + while (nsec_delta + tp->tv_nsec < 0) { + sec_delta -= 1; + nsec_delta += billion; + } + + tp->tv_sec += sec_delta; + tp->tv_nsec += nsec_delta; + } + + return ret; +} \ No newline at end of file diff --git a/pkg/time/fakeclock/fake_gettimeofday.c b/pkg/time/fakeclock/fake_gettimeofday.c new file mode 100644 index 0000000000..54bddc5fec --- /dev/null +++ b/pkg/time/fakeclock/fake_gettimeofday.c @@ -0,0 +1,81 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include +#include +#include +#include +#include + +extern int64_t TV_SEC_DELTA; +extern int64_t TV_NSEC_DELTA; + +#if defined(__amd64__) +inline int real_gettimeofday(struct timeval *tv, struct timezone *tz) +{ + int ret; + asm volatile( + "syscall" + : "=a"(ret) + : "0"(__NR_gettimeofday), "D"(tv), "S"(tz) + : "memory"); + + return ret; +} + +#elif defined(__aarch64__) +inline int real_gettimeofday(struct timeval *tv, struct timezone *tz) +{ + register int w0 __asm__("w0"); + + register struct timeval *x0 __asm__("x0") = tv; + register struct timezone *x1 __asm__("x1") = tz; + register uint64_t w8 __asm__("w8") = __NR_gettimeofday; /* syscall number */ + __asm__ __volatile__( + "svc 0;" + : "+r"(w0) + : "r"(x0), "r" (x1), "r"(w8) + : "memory"); + + return w0; +} +#endif + +int fake_gettimeofday(struct timeval *tv, struct timezone *tz) +{ + int ret = real_gettimeofday(tv, tz); + + int64_t sec_delta = TV_SEC_DELTA; + int64_t nsec_delta = TV_NSEC_DELTA; + int64_t billion = 1000000000; + + while (nsec_delta + tv->tv_usec*1000 > billion) + { + sec_delta += 1; + nsec_delta -= billion; + } + + while (nsec_delta + tv->tv_usec*1000 < 0) + { + sec_delta -= 1; + nsec_delta += billion; + } + + tv->tv_sec += sec_delta; + tv->tv_usec += round(nsec_delta/1000); + + return ret; +} diff --git a/pkg/time/time_darwin.go b/pkg/time/time_darwin.go deleted file mode 100644 index 729b3afdc2..0000000000 --- a/pkg/time/time_darwin.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package time - -import ( - "errors" - - "github.com/chaos-mesh/chaos-mesh/pkg/mock" -) - -// ModifyTime modifies time of target process -func ModifyTime(pid int, deltaSec int64, deltaNsec int64, clockIdsMask uint64) error { - // Mock point to return error in unit test - if err := mock.On("ModifyTimeError"); err != nil { - if e, ok := err.(error); ok { - return e - } - if ignore, ok := err.(bool); ok && ignore { - return nil - } - } - return errors.New("darwin is not supported") -} diff --git a/pkg/time/time_linux_amd64.go b/pkg/time/time_linux_amd64.go deleted file mode 100644 index 286a14f8db..0000000000 --- a/pkg/time/time_linux_amd64.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package time - -import ( - "bytes" - "errors" - "runtime" - - "github.com/chaos-mesh/chaos-mesh/pkg/mapreader" - "github.com/chaos-mesh/chaos-mesh/pkg/mock" - "github.com/chaos-mesh/chaos-mesh/pkg/ptrace" -) - -// TODO: support more cpu architecture -// TODO: auto generate these codes -var fakeImage = []byte{ - 0xb8, 0xe4, 0x00, 0x00, 0x00, //mov $0xe4,%eax - 0x0f, 0x05, //syscall - 0xba, 0x01, 0x00, 0x00, 0x00, //mov $0x1,%edx - 0x89, 0xf9, //mov %edi,%ecx - 0xd3, 0xe2, //shl %cl,%edx - 0x48, 0x8d, 0x0d, 0x74, 0x00, 0x00, 0x00, //lea 0x74(%rip),%rcx # - 0x48, 0x63, 0xd2, //movslq %edx,%rdx - 0x48, 0x85, 0x11, //test %rdx,(%rcx) - 0x74, 0x6b, //je 108a - 0x48, 0x8d, 0x15, 0x6d, 0x00, 0x00, 0x00, //lea 0x6d(%rip),%rdx # - 0x4c, 0x8b, 0x46, 0x08, //mov 0x8(%rsi),%r8 - 0x48, 0x8b, 0x0a, //mov (%rdx),%rcx - 0x48, 0x8d, 0x15, 0x67, 0x00, 0x00, 0x00, //lea 0x67(%rip),%rdx # - 0x48, 0x8b, 0x3a, //mov (%rdx),%rdi - 0x4a, 0x8d, 0x14, 0x07, //lea (%rdi,%r8,1),%rdx - 0x48, 0x81, 0xfa, 0x00, 0xca, 0x9a, 0x3b, //cmp $0x3b9aca00,%rdx - 0x7e, 0x1c, //jle - 0x0f, 0x1f, 0x40, 0x00, //nopl 0x0(%rax) - 0x48, 0x81, 0xef, 0x00, 0xca, 0x9a, 0x3b, //sub $0x3b9aca00,%rdi - 0x48, 0x83, 0xc1, 0x01, //add $0x1,%rcx - 0x49, 0x8d, 0x14, 0x38, //lea (%r8,%rdi,1),%rdx - 0x48, 0x81, 0xfa, 0x00, 0xca, 0x9a, 0x3b, //cmp $0x3b9aca00,%rdx - 0x7f, 0xe8, //jg - 0x48, 0x85, 0xd2, //test %rdx,%rdx - 0x79, 0x1e, //jns - 0x4a, 0x8d, 0xbc, 0x07, 0x00, 0xca, 0x9a, //lea 0x3b9aca00(%rdi,%r8,1),%rdi - 0x3b, // - 0x0f, 0x1f, 0x00, //nopl (%rax) - 0x48, 0x89, 0xfa, //mov %rdi,%rdx - 0x48, 0x83, 0xe9, 0x01, //sub $0x1,%rcx - 0x48, 0x81, 0xc7, 0x00, 0xca, 0x9a, 0x3b, //add $0x3b9aca00,%rdi - 0x48, 0x85, 0xd2, //test %rdx,%rdx - 0x78, 0xed, //js - 0x48, 0x01, 0x0e, //add %rcx,(%rsi) - 0x48, 0x89, 0x56, 0x08, //mov %rdx,0x8(%rsi) - 0xc3, //retq - // constant - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //CLOCK_IDS_MASK - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //TV_SEC_DELTA - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //TV_NSEC_DELTA -} - -// ModifyTime modifies time of target process -func ModifyTime(pid int, deltaSec int64, deltaNsec int64, clockIdsMask uint64) error { - // Mock point to return error in unit test - if err := mock.On("ModifyTimeError"); err != nil { - if e, ok := err.(error); ok { - return e - } - if ignore, ok := err.(bool); ok && ignore { - return nil - } - } - - runtime.LockOSThread() - - program, err := ptrace.Trace(pid) - if err != nil { - return err - } - defer func() { - err = program.Detach() - if err != nil { - log.Error(err, "fail to detach program", "pid", program.Pid()) - } - - runtime.UnlockOSThread() - }() - - var vdsoEntry *mapreader.Entry - for index := range program.Entries { - // reverse loop is faster - e := program.Entries[len(program.Entries)-index-1] - if e.Path == "[vdso]" { - vdsoEntry = &e - break - } - } - if vdsoEntry == nil { - return errors.New("cannot find [vdso] entry") - } - - // minus tailing variable part - // 24 = 3 * 8 because we have three variables - constImageLen := len(fakeImage) - 24 - var fakeEntry *mapreader.Entry - - // find injected image to avoid redundant inject (which will lead to memory leak) - for _, e := range program.Entries { - e := e - - image, err := program.ReadSlice(e.StartAddress, uint64(constImageLen)) - if err != nil { - continue - } - - if bytes.Equal(*image, fakeImage[0:constImageLen]) { - fakeEntry = &e - log.Info("found injected image", "addr", fakeEntry.StartAddress) - break - } - } - if fakeEntry == nil { - fakeEntry, err = program.MmapSlice(fakeImage) - if err != nil { - return err - } - } - fakeAddr := fakeEntry.StartAddress - - // 139 is the index of CLOCK_IDS_MASK in fakeImage - err = program.WriteUint64ToAddr(fakeAddr+139, clockIdsMask) - if err != nil { - return err - } - - // 147 is the index of TV_SEC_DELTA in fakeImage - err = program.WriteUint64ToAddr(fakeAddr+147, uint64(deltaSec)) - if err != nil { - return err - } - - // 155 is the index of TV_NSEC_DELTA in fakeImage - err = program.WriteUint64ToAddr(fakeAddr+155, uint64(deltaNsec)) - if err != nil { - return err - } - - originAddr, err := program.FindSymbolInEntry("clock_gettime", vdsoEntry) - if err != nil { - return err - } - - err = program.JumpToFakeFunc(originAddr, fakeAddr) - if err != nil { - return err - } - - return nil -} diff --git a/pkg/time/time_linux_arm64.go b/pkg/time/time_linux_arm64.go deleted file mode 100644 index 5296dcd5d9..0000000000 --- a/pkg/time/time_linux_arm64.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package time - -import ( - "errors" - - "github.com/chaos-mesh/chaos-mesh/pkg/mock" -) - -// ModifyTime modifies time of target process -func ModifyTime(pid int, deltaSec int64, deltaNsec int64, clockIdsMask uint64) error { - // Mock point to return error in unit test - if err := mock.On("ModifyTimeError"); err != nil { - if e, ok := err.(error); ok { - return e - } - if ignore, ok := err.(bool); ok && ignore { - return nil - } - } - return errors.New("arm64 is not supported") -} diff --git a/pkg/time/time_linux_test.go b/pkg/time/time_linux_test.go deleted file mode 100644 index 0572173ef3..0000000000 --- a/pkg/time/time_linux_test.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package time - -import ( - "os" - "testing" - - "github.com/go-logr/zapr" - "go.uber.org/zap" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "sigs.k8s.io/controller-runtime/pkg/envtest" - - "github.com/chaos-mesh/chaos-mesh/test/pkg/timer" -) - -func TestModifyTime(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "Time Suit", - []Reporter{envtest.NewlineReporter{}}) -} - -var _ = BeforeSuite(func(done Done) { - By("change working directory") - - err := os.Chdir("../../") - Expect(err).NotTo(HaveOccurred()) - - By("register logger") - zapLog, err := zap.NewDevelopment() - Expect(err).NotTo(HaveOccurred()) - log := zapr.NewLogger(zapLog) - RegisterLogger(log) - - close(done) -}) - -// These tests are written in BDD-style using Ginkgo framework. Refer to -// http://onsi.github.io/ginkgo to learn more. - -var _ = Describe("ModifyTime", func() { - - var t *timer.Timer - - BeforeEach(func() { - var err error - - t, err = timer.StartTimer() - Expect(err).ShouldNot(HaveOccurred()) - }) - - AfterEach(func() { - err := t.Stop() - Expect(err).ShouldNot(HaveOccurred()) - }) - - Context("Modify Time", func() { - It("should move forward successfully", func() { - Expect(t).NotTo(BeNil()) - - now, err := t.GetTime() - Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) - - sec := now.Unix() - - err = ModifyTime(t.Pid(), 10000, 0, 1) - Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) - - newTime, err := t.GetTime() - Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) - - newSec := newTime.Unix() - - Expect(newSec-sec).Should(BeNumerically(">=", 10000), "sec %d newSec %d", sec, newSec) - }) - - It("should move backward successfully", func() { - Expect(t).NotTo(BeNil()) - - now, err := t.GetTime() - Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) - - sec := now.Unix() - - err = ModifyTime(t.Pid(), -10000, 0, 1) - Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) - - newTime, err := t.GetTime() - Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) - - newSec := newTime.Unix() - - Expect(10000-(sec-newSec)).Should(BeNumerically("<=", 1), "sec %d newSec %d", sec, newSec) - }) - - It("should handle nsec overflow", func() { - Expect(t).NotTo(BeNil()) - - now, err := t.GetTime() - Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) - - sec := now.Unix() - - err = ModifyTime(t.Pid(), 0, 1000000000, 1) - Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) - - newTime, err := t.GetTime() - Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) - - newSec := newTime.Unix() - - Expect(newSec-sec).Should(BeNumerically(">=", 1), "sec %d newSec %d", sec, newSec) - }) - }) -}) diff --git a/pkg/time/time_skew_linux.go b/pkg/time/time_skew_linux.go new file mode 100644 index 0000000000..7fd112f563 --- /dev/null +++ b/pkg/time/time_skew_linux.go @@ -0,0 +1,252 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package time + +import ( + "fmt" + "sync" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + + "github.com/chaos-mesh/chaos-mesh/pkg/cerr" + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/tasks" +) + +// clockGettimeSkewFakeImage is the filename of fake image after compiling +const clockGettimeSkewFakeImage = "fake_clock_gettime.o" + +// clockGettime is the target function would be replaced +const clockGettime = "clock_gettime" + +// These three consts corresponding to the three extern variables in the fake_clock_gettime.c +const ( + externVarClockIdsMask = "CLOCK_IDS_MASK" + externVarTvSecDelta = "TV_SEC_DELTA" + externVarTvNsecDelta = "TV_NSEC_DELTA" +) + +// timeofdaySkewFakeImage is the filename of fake image after compiling +const timeOfDaySkewFakeImage = "fake_gettimeofday.o" + +// getTimeOfDay is the target function would be replaced +const getTimeOfDay = "gettimeofday" + +// Config is the summary config of get_time_of_day and clock_get_time. +// Config here is only for injector of k8s pod. +// We divide group injector on linux process , pod injector for k8s and +// the base injector , so we can simply create another config struct just +// for linux process for chaos-mesh/chaosd or watchmaker. +type Config struct { + deltaSeconds int64 + deltaNanoSeconds int64 + clockIDsMask uint64 +} + +func NewConfig(deltaSeconds int64, deltaNanoSeconds int64, clockIDsMask uint64) Config { + return Config{ + deltaSeconds: deltaSeconds, + deltaNanoSeconds: deltaNanoSeconds, + clockIDsMask: clockIDsMask, + } +} + +func (c *Config) DeepCopy() tasks.Object { + return &Config{ + c.deltaSeconds, + c.deltaNanoSeconds, + c.clockIDsMask, + } +} + +// Merge implement how to merge time skew tasks. +func (c *Config) Merge(a tasks.Mergeable) error { + A, OK := a.(*Config) + if OK { + // TODO: Add more reasonable merge method + c.deltaSeconds += A.deltaSeconds + c.deltaNanoSeconds += A.deltaNanoSeconds + c.clockIDsMask |= A.clockIDsMask + return nil + } + return cerr.NotType[*Config]().WrapInput(a).Err() +} + +type ConfigCreatorParas struct { + Logger logr.Logger + Config Config + PodProcessMap *tasks.PodContainerNameProcessMap +} + +// New assumes we get ConfigCreatorParas from values. +// New will init a struct just like PodHandler(ProcessGroupHandler(Skew)) +func (c *Config) New(values interface{}) (tasks.Injectable, error) { + paras, ok := values.(ConfigCreatorParas) + if !ok { + return nil, errors.New("not ConfigCreatorParas") + } + + skew, err := GetSkew(paras.Logger, paras.Config) + if err != nil { + return nil, err + } + + newGroupProcessHandler := + tasks.NewProcessGroupHandler(paras.Logger, &skew) + newPodHandler := tasks.NewPodHandler(paras.PodProcessMap, + &newGroupProcessHandler, paras.Logger) + return &newPodHandler, nil +} + +// Assign assumes the input injectable is *tasks.PodHandler. +// We also assume the SubProcess of podHandler is *tasks.ProcessGroupHandler +// and the LeaderProcess of ProcessGroupHandler is *Skew. +func (c *Config) Assign(injectable tasks.Injectable) error { + podHandler, ok := injectable.(*tasks.PodHandler) + if !ok { + return errors.New(fmt.Sprintf("type %T is not *tasks.PodHandler", injectable)) + } + groupProcessHandler, ok := podHandler.SubProcess.(*tasks.ProcessGroupHandler) + if !ok { + return errors.New(fmt.Sprintf("type %T is not *tasks.ProcessGroupHandler", podHandler.SubProcess)) + } + I, ok := groupProcessHandler.LeaderProcess.(*Skew) + if !ok { + return errors.New(fmt.Sprintf("type %T is not *Skew", groupProcessHandler.LeaderProcess)) + } + + I.SkewConfig = *c + return nil +} + +// Skew implements ChaosOnProcessGroup. +// We locked Skew injecting and recovering to avoid conflict. +type Skew struct { + SkewConfig Config + clockGetTime *FakeImage + getTimeOfDay *FakeImage + + locker sync.Mutex + logger logr.Logger +} + +func GetSkew(logger logr.Logger, c Config) (Skew, error) { + clockGetTimeImage, err := LoadFakeImageFromEmbedFs(clockGettimeSkewFakeImage, clockGettime, logger) + if err != nil { + return Skew{}, errors.Wrap(err, "load fake image") + } + + getTimeOfDayimage, err := LoadFakeImageFromEmbedFs(timeOfDaySkewFakeImage, getTimeOfDay, logger) + if err != nil { + return Skew{}, errors.Wrap(err, "load fake image") + } + + return Skew{ + SkewConfig: c, + clockGetTime: clockGetTimeImage, + getTimeOfDay: getTimeOfDayimage, + locker: sync.Mutex{}, + logger: logger, + }, nil +} + +func (s *Skew) Fork() (tasks.ChaosOnProcessGroup, error) { + // TODO : to KEAO can I share FakeImage between threads? + skew, err := GetSkew(s.logger, s.SkewConfig) + if err != nil { + return nil, err + } + + return &skew, nil +} + +func (s *Skew) Assign(injectable tasks.Injectable) error { + I, OK := injectable.(*Skew) + if OK { + I.SkewConfig = *s.SkewConfig.DeepCopy().(*Config) + return nil + } + return cerr.NotType[*Skew]().WrapInput(injectable).Err() +} + +func (s *Skew) Inject(pid tasks.IsID) error { + s.locker.Lock() + defer s.locker.Unlock() + sysPID, ok := pid.(tasks.SysPID) + if !ok { + return tasks.ErrNotTypeSysID.WrapInput(pid).Err() + } + + s.logger.Info("injecting time skew", "pid", pid) + + err := s.clockGetTime.AttachToProcess(int(sysPID), map[string]uint64{ + externVarClockIdsMask: s.SkewConfig.clockIDsMask, + externVarTvSecDelta: uint64(s.SkewConfig.deltaSeconds), + externVarTvNsecDelta: uint64(s.SkewConfig.deltaNanoSeconds), + }) + if err != nil { + return err + } + + err = s.getTimeOfDay.AttachToProcess(int(sysPID), map[string]uint64{ + externVarTvSecDelta: uint64(s.SkewConfig.deltaSeconds), + externVarTvNsecDelta: uint64(s.SkewConfig.deltaNanoSeconds), + }) + if err != nil { + return err + } + return nil +} + +// Recover clock_get_time & get_time_of_day one by one , +// if error comes from clock_get_time.Recover we will continue recover another fake image +// and merge errors. +func (s *Skew) Recover(pid tasks.IsID) error { + s.locker.Lock() + defer s.locker.Unlock() + sysPID, ok := pid.(tasks.SysPID) + if !ok { + return tasks.ErrNotTypeSysID.WrapInput(pid).Err() + } + + s.logger.Info("recovering time skew", "pid", pid) + + err1 := s.clockGetTime.Recover(int(sysPID), map[string]uint64{ + externVarClockIdsMask: s.SkewConfig.clockIDsMask, + externVarTvSecDelta: uint64(s.SkewConfig.deltaSeconds), + externVarTvNsecDelta: uint64(s.SkewConfig.deltaNanoSeconds), + }) + if err1 != nil { + err2 := s.getTimeOfDay.Recover(int(sysPID), map[string]uint64{ + externVarTvSecDelta: uint64(s.SkewConfig.deltaSeconds), + externVarTvNsecDelta: uint64(s.SkewConfig.deltaNanoSeconds), + }) + if err2 != nil { + return errors.Wrapf(err1, "time skew all failed %v", err2) + } + return err1 + } + + err2 := s.getTimeOfDay.Recover(int(sysPID), map[string]uint64{ + externVarTvSecDelta: uint64(s.SkewConfig.deltaSeconds), + externVarTvNsecDelta: uint64(s.SkewConfig.deltaNanoSeconds), + }) + if err2 != nil { + return err2 + } + + return nil +} diff --git a/pkg/time/time_skew_linux_amd64_test.go b/pkg/time/time_skew_linux_amd64_test.go new file mode 100644 index 0000000000..8b4b5047b2 --- /dev/null +++ b/pkg/time/time_skew_linux_amd64_test.go @@ -0,0 +1,135 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package time + +import ( + "os" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/tasks" + "github.com/chaos-mesh/chaos-mesh/pkg/log" + "github.com/chaos-mesh/chaos-mesh/test/pkg/timer" +) + +// These test cases required bin/test/timer as its workload. +// You could use make test-utils to build it. + +func TestModifyTime(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Time Suit") +} + +var _ = BeforeSuite(func(done Done) { + By("change working directory") + + err := os.Chdir("../../") + Expect(err).NotTo(HaveOccurred()) + + close(done) +}) + +// These tests are written in BDD-style using Ginkgo framework. Refer to +// http://onsi.github.io/ginkgo to learn more. + +var _ = Describe("ModifyTime", func() { + var t *timer.Timer + logger, err := log.NewDefaultZapLogger() + Expect(err).ShouldNot(HaveOccurred()) + BeforeEach(func() { + var err error + + t, err = timer.StartTimer() + Expect(err).ShouldNot(HaveOccurred()) + }) + + AfterEach(func() { + err := t.Stop() + Expect(err).ShouldNot(HaveOccurred()) + }) + + Context("Modify Time", func() { + It("should move forward successfully", func() { + + Expect(t).NotTo(BeNil()) + s, err := GetSkew(logger, NewConfig(10000, 0, 1)) + Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) + + now, err := t.GetTime() + Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) + + sec := now.Unix() + + err = s.Inject(tasks.SysPID(t.Pid())) + Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) + + newTime, err := t.GetTime() + Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) + + newSec := newTime.Unix() + + Expect(newSec-sec).Should(BeNumerically(">=", 10000), "sec %d newSec %d", sec, newSec) + Expect(newSec-sec).Should(BeNumerically("<=", 10010), "sec %d newSec %d", sec, newSec) + }) + + It("should move backward successfully", func() { + Expect(t).NotTo(BeNil()) + s, err := GetSkew(logger, NewConfig(10000, 0, 1)) + Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) + + err = s.Inject(tasks.SysPID(t.Pid())) + Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) + + now, err := t.GetTime() + Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) + + sec := now.Unix() + + err = s.Recover(tasks.SysPID(t.Pid())) + Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) + + newTime, err := t.GetTime() + Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) + + newSec := newTime.Unix() + Expect(10000-(sec-newSec)).Should(BeNumerically("<=", 1), "sec %d newSec %d", sec, newSec) + }) + + It("should handle nsec overflow", func() { + Expect(t).NotTo(BeNil()) + + s, err := GetSkew(logger, NewConfig(0, 1000000000, 1)) + Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) + + now, err := t.GetTime() + Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) + + sec := now.Unix() + + err = s.Inject(tasks.SysPID(t.Pid())) + Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) + + newTime, err := t.GetTime() + Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) + + newSec := newTime.Unix() + Expect(newSec-sec).Should(BeNumerically(">=", 1), "sec %d newSec %d", sec, newSec) + }) + }) +}) diff --git a/pkg/time/utils.go b/pkg/time/utils.go deleted file mode 100644 index 0650c27b2f..0000000000 --- a/pkg/time/utils.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package time - -import ( - "github.com/go-logr/logr" - - ctrl "sigs.k8s.io/controller-runtime" -) - -var log = ctrl.Log.WithName("time") - -// RegisterLogger registers a logger on time pkg -func RegisterLogger(logger logr.Logger) { - log = logger -} diff --git a/pkg/time/utils/utils.go b/pkg/time/utils/utils.go index 21e07cbc18..6d9249fd29 100644 --- a/pkg/time/utils/utils.go +++ b/pkg/time/utils/utils.go @@ -1,19 +1,21 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package utils -import "fmt" +import "github.com/pkg/errors" // EncodeClkIds will convert array of clk ids into a mask func EncodeClkIds(clkIds []string) (uint64, error) { @@ -43,7 +45,7 @@ func EncodeClkIds(clkIds []string) (uint64, error) { case "CLOCK_BOOTTIME_ALARM": mask |= 1 << 9 default: - return 0, fmt.Errorf("unknown clock id %s", id) + return 0, errors.Errorf("unknown clock id %s", id) } } diff --git a/pkg/time/utils/utils_test.go b/pkg/time/utils/utils_test.go index 5b6fef113f..f2797934cd 100644 --- a/pkg/time/utils/utils_test.go +++ b/pkg/time/utils/utils_test.go @@ -1,22 +1,24 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package utils import ( - . "github.com/onsi/gomega" - "testing" + + . "github.com/onsi/gomega" ) func TestEncodeClkIds(t *testing.T) { diff --git a/pkg/ttlcontroller/ttlcontroller.go b/pkg/ttlcontroller/ttlcontroller.go deleted file mode 100644 index 7022b368a1..0000000000 --- a/pkg/ttlcontroller/ttlcontroller.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package ttlcontroller - -import ( - "context" - "time" - - "github.com/chaos-mesh/chaos-mesh/pkg/core" - - runtimeutil "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/wait" - ctrl "sigs.k8s.io/controller-runtime" -) - -var ( - log = ctrl.Log.WithName("database ttl controller") -) - -// Controller defines the database ttl controller -type Controller struct { - experiment core.ExperimentStore - event core.EventStore - ttlconfig *TTLconfig -} - -// TTLconfig defines the ttl -type TTLconfig struct { - // databaseTTLResyncPeriod defines the time interval to cleanup data in the database. - DatabaseTTLResyncPeriod time.Duration - // EventTTL defines the ttl of events - EventTTL time.Duration - // ArchiveExperimentTTL defines the ttl of archive experiments - ArchiveExperimentTTL time.Duration -} - -// NewController returns a new database ttl controller -func NewController( - experiment core.ExperimentStore, - event core.EventStore, - ttlc *TTLconfig, -) *Controller { - return &Controller{ - experiment: experiment, - event: event, - ttlconfig: ttlc, - } -} - -// Register periodically calls function runWorker to delete the data. -func Register(c *Controller, controllerRuntimeStopCh <-chan struct{}) { - defer runtimeutil.HandleCrash() - log.Info("starting database TTL controller") - go wait.Until(c.runWorker, c.ttlconfig.DatabaseTTLResyncPeriod, controllerRuntimeStopCh) -} - -// runWorker is a long-running function that will call the -// function in order to delete the events and archives. -func (c *Controller) runWorker() { - log.Info("deleting expired data from the database") - c.event.DeleteByFinishTime(context.Background(), c.ttlconfig.EventTTL) - c.experiment.DeleteByFinishTime(context.Background(), c.ttlconfig.ArchiveExperimentTTL) -} diff --git a/pkg/uiserver/empty_assets_handler.go b/pkg/uiserver/empty_assets_handler.go deleted file mode 100644 index cb3c33c844..0000000000 --- a/pkg/uiserver/empty_assets_handler.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build !ui_server - -package uiserver - -import "net/http" - -var assets http.FileSystem diff --git a/pkg/uiserver/server.go b/pkg/uiserver/server.go deleted file mode 100644 index abe69825f5..0000000000 --- a/pkg/uiserver/server.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package uiserver - -import "net/http" - -// AssetsFS returns assets. -func AssetsFS() http.FileSystem { - return assets -} diff --git a/pkg/utils/generate.go b/pkg/utils/generate.go index 95fd28218d..1b52b3a453 100644 --- a/pkg/utils/generate.go +++ b/pkg/utils/generate.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package utils diff --git a/pkg/version/types.go b/pkg/version/types.go index ec1546f148..190fcbf81c 100644 --- a/pkg/version/types.go +++ b/pkg/version/types.go @@ -1,15 +1,17 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package version diff --git a/pkg/version/version.go b/pkg/version/version.go index 595bf3f97a..e2d4cf631a 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -1,15 +1,17 @@ -// Copyright 2019 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package version diff --git a/pkg/webhook/affected_namespaces.go b/pkg/webhook/affected_namespaces.go new file mode 100644 index 0000000000..2e265cef4f --- /dev/null +++ b/pkg/webhook/affected_namespaces.go @@ -0,0 +1,60 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package webhook + +import ( + "reflect" + + "k8s.io/apimachinery/pkg/util/validation/field" + + "github.com/chaos-mesh/chaos-mesh/api/genericwebhook" + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +func affectedNamespaces(obj interface{}) (bool, map[string]struct{}) { + clusterScoped := false + namespaces := make(map[string]struct{}) + + walker := genericwebhook.NewFieldWalker(obj, func(path *field.Path, obj interface{}, field *reflect.StructField) bool { + + // These are some trivial rules to cut a lot of edges. + if field != nil && (field.Name == "Status" || field.Name == "TypeMeta" || field.Name == "ObjectMeta") { + return false + } + + if selector, ok := obj.(*v1alpha1.PodSelector); ok { + if selector == nil { + return false + } + + for _, ns := range selector.Selector.Namespaces { + namespaces[ns] = struct{}{} + } + for namespace := range selector.Selector.Pods { + namespaces[namespace] = struct{}{} + } + if selector.Selector.ClusterScoped() { + clusterScoped = true + } + + return true + } + return true + }) + walker.Walk() + + return clusterScoped, namespaces +} diff --git a/pkg/webhook/affected_namespaces_test.go b/pkg/webhook/affected_namespaces_test.go new file mode 100644 index 0000000000..d32967457b --- /dev/null +++ b/pkg/webhook/affected_namespaces_test.go @@ -0,0 +1,142 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package webhook + +import ( + "testing" + + "github.com/onsi/gomega" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +func TestAffectedNamespaces(t *testing.T) { + g := gomega.NewGomegaWithT(t) + + _, namespaces := affectedNamespaces(&v1alpha1.Schedule{ + Spec: v1alpha1.ScheduleSpec{ + ScheduleItem: v1alpha1.ScheduleItem{ + EmbedChaos: v1alpha1.EmbedChaos{ + PodChaos: &v1alpha1.PodChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{"ns1", "ns2"}, + }, + }, + }, + }, + }, + }, + }, + }, + }) + g.Expect(namespaces).To(gomega.Equal(map[string]struct{}{ + "ns1": {}, + "ns2": {}, + })) + + _, namespaces = affectedNamespaces(&v1alpha1.Workflow{ + Spec: v1alpha1.WorkflowSpec{ + Templates: []v1alpha1.Template{ + { + EmbedChaos: &v1alpha1.EmbedChaos{ + NetworkChaos: &v1alpha1.NetworkChaosSpec{ + Target: &v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{"ns1", "ns2"}, + }, + }, + }, + }, + }, + }, + }, + }, + }) + g.Expect(namespaces).To(gomega.Equal(map[string]struct{}{ + "ns1": {}, + "ns2": {}, + })) + + clusterScoped, _ := affectedNamespaces(&v1alpha1.NetworkChaos{ + Spec: v1alpha1.NetworkChaosSpec{ + Target: &v1alpha1.PodSelector{}, + }, + }) + g.Expect(clusterScoped).To(gomega.BeTrue()) + + clusterScoped, _ = affectedNamespaces(&v1alpha1.NetworkChaos{}) + g.Expect(clusterScoped).To(gomega.BeTrue()) + + _, namespaces = affectedNamespaces(&v1alpha1.Workflow{ + Spec: v1alpha1.WorkflowSpec{ + Templates: []v1alpha1.Template{ + { + EmbedChaos: &v1alpha1.EmbedChaos{ + NetworkChaos: &v1alpha1.NetworkChaosSpec{ + Target: &v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{"ns1", "ns2"}, + }, + }, + }, + }, + }, + }, + { + EmbedChaos: &v1alpha1.EmbedChaos{ + NetworkChaos: &v1alpha1.NetworkChaosSpec{ + Target: &v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{"ns3", "ns4"}, + }, + }, + }, + }, + }, + }, + }, + }, + }) + g.Expect(namespaces).To(gomega.Equal(map[string]struct{}{ + "ns1": {}, + "ns2": {}, + "ns3": {}, + "ns4": {}, + })) + + _, namespaces = affectedNamespaces(&v1alpha1.NetworkChaos{ + Spec: v1alpha1.NetworkChaosSpec{ + Target: &v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + Pods: map[string][]string{ + "ns1": {"pod1", "pod2"}, + "ns2": {"pod3", "pod4"}, + }, + }, + }, + }, + }) + g.Expect(namespaces).To(gomega.Equal(map[string]struct{}{ + "ns1": {}, + "ns2": {}, + })) +} diff --git a/pkg/webhook/config/config.go b/pkg/webhook/config/config.go deleted file mode 100644 index bcfa43d26d..0000000000 --- a/pkg/webhook/config/config.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package config - -import ( - "fmt" - "io" - "io/ioutil" - "sync" - - "github.com/ghodss/yaml" - - corev1 "k8s.io/api/core/v1" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -var ( - errMissingName = fmt.Errorf(`name field is required for template args config`) - errMissingTemplateName = fmt.Errorf(`template field is required for template args config`) -) - -const ( - annotationNamespaceDefault = "admission-webhook.chaos-mesh.org" -) - -// ExecAction describes a "run in container" action. -type ExecAction struct { - // Command is the command line to execute inside the container, the working directory for the - // command is root ('/') in the container's filesystem. The command is simply exec'd, it is - // not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - // a shell, you need to explicitly call out to that shell. - // Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - // +optional - Command []string `json:"command,omitempty"` -} - -// InjectionConfig is a specific instance of an injected config, for a given annotation -type InjectionConfig struct { - Name string - // Selector is used to select pods that are used to inject sidecar. - Selector *v1alpha1.SelectorSpec - - Containers []corev1.Container `json:"containers"` - Volumes []corev1.Volume `json:"volumes"` - Environment []corev1.EnvVar `json:"env"` - VolumeMounts []corev1.VolumeMount `json:"volumeMounts"` - HostAliases []corev1.HostAlias `json:"hostAliases"` - InitContainers []corev1.Container `json:"initContainers"` - ShareProcessNamespace bool `json:"shareProcessNamespace"` - // PostStart is called after a container is created first. - // If the handler fails, the containers will failed. - // Key defines for the name of deployment container. - // Value defines for the Commands for stating container. - // +optional - PostStart map[string]ExecAction `json:"postStart,omitempty"` -} - -// Config is a struct indicating how a given injection should be configured -type Config struct { - sync.RWMutex - AnnotationNamespace string - Injections map[string][]*InjectionConfig -} - -// TemplateArgs is a set of arguments to render template -type TemplateArgs struct { - Namespace string - Name string `yaml:"name"` - // Name of the template - Template string `yaml:"template"` - Arguments map[string]string `yaml:"arguments"` - // Selector is used to select pods that are used to inject sidecar. - Selector *v1alpha1.SelectorSpec `json:"selector,omitempty"` -} - -// NewConfigWatcherConf creates a configuration for watcher -func NewConfigWatcherConf() *Config { - return &Config{ - AnnotationNamespace: annotationNamespaceDefault, - Injections: make(map[string][]*InjectionConfig), - } -} - -func (c *Config) RequestAnnotationKey() string { - return c.AnnotationNamespace + "/request" -} - -func (c *Config) StatusAnnotationKey() string { - return c.AnnotationNamespace + "/status" -} - -func (c *Config) RequestInitAnnotationKey() string { - return c.AnnotationNamespace + "/init-request" -} - -// GetRequestedConfig returns the InjectionConfig given a requested key -func (c *Config) GetRequestedConfig(namespace, key string) (*InjectionConfig, error) { - c.RLock() - defer c.RUnlock() - - if _, ok := c.Injections[namespace]; !ok { - return nil, fmt.Errorf("no injection config at ns %s", namespace) - } - - for _, conf := range c.Injections[namespace] { - if key == conf.Name { - return conf, nil - } - } - - return nil, fmt.Errorf("no injection config found for key %s at ns %s", key, namespace) -} - -// LoadTemplateArgs takes an io.Reader and parses out an template args -func LoadTemplateArgs(reader io.Reader) (*TemplateArgs, error) { - data, err := ioutil.ReadAll(reader) - if err != nil { - return nil, err - } - - var cfg TemplateArgs - if err := yaml.Unmarshal(data, &cfg); err != nil { - return nil, err - } - - if cfg.Name == "" { - return nil, errMissingName - } - - if cfg.Template == "" { - return nil, errMissingTemplateName - } - - return &cfg, nil -} - -// ReplaceInjectionConfigs will update the injection configs. -func (c *Config) ReplaceInjectionConfigs(updatedConfigs map[string][]*InjectionConfig) { - c.Lock() - defer c.Unlock() - c.Injections = updatedConfigs -} diff --git a/pkg/webhook/config/config_test.go b/pkg/webhook/config/config_test.go deleted file mode 100644 index 90a3f5a0c7..0000000000 --- a/pkg/webhook/config/config_test.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package config - -import ( - "github.com/ghodss/yaml" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("webhook config", func() { - Context("Test webhook config", func() { - It("unmarshal TemplateArgs", func() { - template := ` -name: chaosfs-etcd -selector: - labelSelectors: - app: etcd -template: chaosfs-sidecar -arguments: - ContainerName: "etcd" - DataPath: "/var/run/etcd/default.etcd" - MountPath: "/var/run/etcd" - VolumeName: "datadir"` - - var cfg TemplateArgs - err := yaml.Unmarshal([]byte(template), &cfg) - Expect(err).To(BeNil()) - }) - - It("unmarshal Injection Config", func() { - template := ` -initContainers: -- name: inject-scripts - image: pingcap/chaos-scripts:latest - imagePullpolicy: Always - command: ["sh", "-c", "/scripts/init.sh -d /var/lib/pd/data -f /var/lib/pd/fuse-data"] -containers: -- name: chaosfs - image: pingcap/chaos-fs:latest - imagePullpolicy: Always - ports: - - containerPort: 65534 - securityContext: - privileged: true - command: - - /usr/local/bin/chaosfs - - -addr=:65534 - - -pidfile=/tmp/fuse/pid - - -original=/var/lib/pd/fuse-data - - -mountpoint=/var/lib/pd/data - volumeMounts: - - name: pd - mountPath: /var/lib/pd - mountPropagation: Bidirectional -volumeMounts: -- name: pd - mountPath: /var/lib/pd - mountPropagation: HostToContainer -- name: scripts - mountPath: /tmp/scripts -- name: fuse - mountPath: /tmp/fuse -volumes: -- name: scripts - emptyDir: {} -- name: fuse - emptyDir: {} -postStart: - pd: - command: - - /tmp/scripts/wait-fuse.sh -` - var cfg InjectionConfig - err := yaml.Unmarshal([]byte(template), &cfg) - Expect(err).To(BeNil()) - }) - - It("should return request on RequestAnnotationKey", func() { - var cfg Config - res := cfg.RequestAnnotationKey() - Expect(res).To(Equal("/request")) - }) - - It("should return status on StatusAnnotationKey", func() { - var cfg Config - res := cfg.StatusAnnotationKey() - Expect(res).To(Equal("/status")) - }) - - It("should return init-request on RequestInitAnnotationKey", func() { - var cfg Config - res := cfg.RequestInitAnnotationKey() - Expect(res).To(Equal("/init-request")) - }) - - }) -}) diff --git a/pkg/webhook/config/setup_test.go b/pkg/webhook/config/setup_test.go deleted file mode 100644 index 7689a234bb..0000000000 --- a/pkg/webhook/config/setup_test.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package config - -import ( - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "sigs.k8s.io/controller-runtime/pkg/envtest" -) - -func TestAPIs(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "webhook config", - []Reporter{envtest.NewlineReporter{}}) -} diff --git a/pkg/webhook/config/watcher/config.go b/pkg/webhook/config/watcher/config.go deleted file mode 100644 index 4bd058c172..0000000000 --- a/pkg/webhook/config/watcher/config.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package watcher - -import ( - "github.com/pingcap/errors" -) - -// Config is a configuration struct for the Watcher type -type Config struct { - // ClusterScoped means control Chaos Object in cluster level(all namespace); - ClusterScoped bool `envconfig:"CLUSTER_SCOPED" default:"true"` - // TemplateNamespace is the namespace which holds the template configmap. - // If controller-manager is running with in-cluster mode. If is set to empty string, it will be overwrite to namespace which the pod belongs. - TemplateNamespace string `envconfig:"TEMPLATE_NAMESPACE" default:""` - // TargetNamespace means configmaps in this namespace will be controlled by this controller. - // It SHOULD be the same with TargetNamespace in config.ChaosControllerConfig while clusterScoped is false. - TargetNamespace string `envconfig:"TARGET_NAMESPACE" default:""` - // TemplateLabels is label pairs used to discover common templates in Kubernetes. These should be key1:value[,key2:val2,...] - TemplateLabels map[string]string `envconfig:"TEMPLATE_LABELS"` - // ConfigLabels is label pairs used to discover ConfigMaps in Kubernetes. These should be key1:value[,key2:val2,...] - ConfigLabels map[string]string `envconfig:"CONFIGMAP_LABELS"` -} - -// NewConfig returns a new initialized Config -func NewConfig() *Config { - return &Config{ - ClusterScoped: true, - TemplateNamespace: "", - TargetNamespace: "", - TemplateLabels: map[string]string{}, - ConfigLabels: map[string]string{}, - } -} - -// Verify will verify the parameter configuration is correct -func (c *Config) Verify() error { - if len(c.TemplateLabels) == 0 { - return errors.New("envconfig:\"TEMPLATE_LABELS\" template labels must be set") - } - if len(c.ConfigLabels) == 0 { - return errors.New("envconfig:\"CONFIGMAP_LABELS\" conf labels must be set") - } - if !c.ClusterScoped && len(c.TargetNamespace) == 0 { - return errors.New("envconfig:\"TARGET_NAMESPACE\" conf labels must be set while CLUSTER_SCOPED is false") - } - return nil -} diff --git a/pkg/webhook/config/watcher/config_test.go b/pkg/webhook/config/watcher/config_test.go deleted file mode 100644 index 82ee25e69b..0000000000 --- a/pkg/webhook/config/watcher/config_test.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package watcher - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("webhook config watcher", func() { - Context("Test webhook config", func() { - It("should return NewConfig", func() { - config := NewConfig() - Expect(config.TemplateNamespace).To(Equal("")) - Expect(config.TargetNamespace).To(Equal("")) - Expect(config.ConfigLabels).To(Equal(map[string]string{})) - Expect(config.TemplateLabels).To(Equal(map[string]string{})) - }) - - It("verift the parameter", func() { - config := NewConfig() - Expect(config.Verify()).Should(HaveOccurred()) - - config.TemplateLabels = make(map[string]string) - config.TemplateLabels["bar"] = "foo" - Expect(config.Verify()).Should(HaveOccurred()) - - config.ConfigLabels = make(map[string]string) - config.ConfigLabels["bar"] = "foo" - Expect(config.Verify()).ShouldNot(HaveOccurred()) - }) - - }) -}) diff --git a/pkg/webhook/config/watcher/message.go b/pkg/webhook/config/watcher/message.go deleted file mode 100644 index 5d45a89c25..0000000000 --- a/pkg/webhook/config/watcher/message.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package watcher - -import ( - "github.com/chaos-mesh/chaos-mesh/pkg/webhook/config" -) - -// Message is a message that describes a change and payload to a sidecar configuration -type Message struct { - Event Event - InjectionConfig config.InjectionConfig -} - -// Event is what happened to the config (add/delete/update) -type Event uint8 - -const ( - // EventAdd is a new ConfigMap - EventAdd Event = iota - // EventUpdate is an Updated ConfigMap - EventUpdate - // EventDelete is a deleted ConfigMap - EventDelete -) diff --git a/pkg/webhook/config/watcher/setup_test.go b/pkg/webhook/config/watcher/setup_test.go deleted file mode 100644 index f13421922e..0000000000 --- a/pkg/webhook/config/watcher/setup_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package watcher - -import ( - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "sigs.k8s.io/controller-runtime/pkg/envtest" - - "k8s.io/client-go/rest" -) - -func TestAPIs(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "webhook config watcher", - []Reporter{envtest.NewlineReporter{}}) -} - -func MockClusterConfig() (*rest.Config, error) { - return &rest.Config{ - Host: "https://testhost:9527", - TLSClientConfig: rest.TLSClientConfig{}, - BearerToken: "testToken", - BearerTokenFile: "/var/run/secrets/kubernetes.io/serviceaccount/token", - }, nil -} diff --git a/pkg/webhook/config/watcher/util.go b/pkg/webhook/config/watcher/util.go deleted file mode 100644 index 122fecf0c7..0000000000 --- a/pkg/webhook/config/watcher/util.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package watcher - -import ( - "bytes" - "html/template" -) - -func renderTemplateWithArgs(tpl *template.Template, args map[string]string) ([]byte, error) { - model := make(map[string]interface{}, len(args)) - for k, v := range args { - model[k] = v - } - buff := new(bytes.Buffer) - if err := tpl.Execute(buff, model); err != nil { - return nil, err - } - return buff.Bytes(), nil -} diff --git a/pkg/webhook/config/watcher/util_test.go b/pkg/webhook/config/watcher/util_test.go deleted file mode 100644 index 4e6a6a5c7d..0000000000 --- a/pkg/webhook/config/watcher/util_test.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package watcher - -import ( - "html/template" - "testing" -) - -func TestRenderTemplateWithArgs(t *testing.T) { - tmpl := template.Must(template.New("common-template").Parse(`initContainers: -- name: inject-scripts - image: pingcap/chaos-scripts:latest - imagePullpolicy: Always - command: ["sh", "-c", "/scripts/init.sh -d {{.DataPath}} -f {{.MountPath}}/fuse-data"] -containers: -- name: chaosfs - image: pingcap/chaos-fs:latest - imagePullpolicy: Always - ports: - - containerPort: 65534 - securityContext: - privileged: true - command: - - /usr/local/bin/chaosfs - - -addr=:65534 - - -pidfile=/tmp/fuse/pid - - -original={{.MountPath}}/fuse-data - - -mountpoint={{.DataPath}} - volumeMounts: - - name: {{.VolumeName}} - mountPath: {{.MountPath}} - mountPropagation: Bidirectional -volumeMounts: -- name: {{.VolumeName}} - mountPath: {{.MountPath}} - mountPropagation: HostToContainer -- name: scripts - mountPath: /tmp/scripts -- name: fuse - mountPath: /tmp/fuse -volumes: -- name: scripts - emptyDir: {} -- name: fuse - emptyDir: {} -postStart: - {{.ContainerName}}: - command: - - /tmp/scripts/wait-fuse.sh`)) - - args := map[string]string{ - "DataPath": "/var/lib/pd/data", - "VolumeName": "pd", - "MountPath": "/var/lib/pd", - "ContainerName": "pd", - } - out, err := renderTemplateWithArgs(tmpl, args) - if err != nil { - t.Error("failed to render template", err) - } - expected := `initContainers: -- name: inject-scripts - image: pingcap/chaos-scripts:latest - imagePullpolicy: Always - command: ["sh", "-c", "/scripts/init.sh -d /var/lib/pd/data -f /var/lib/pd/fuse-data"] -containers: -- name: chaosfs - image: pingcap/chaos-fs:latest - imagePullpolicy: Always - ports: - - containerPort: 65534 - securityContext: - privileged: true - command: - - /usr/local/bin/chaosfs - - -addr=:65534 - - -pidfile=/tmp/fuse/pid - - -original=/var/lib/pd/fuse-data - - -mountpoint=/var/lib/pd/data - volumeMounts: - - name: pd - mountPath: /var/lib/pd - mountPropagation: Bidirectional -volumeMounts: -- name: pd - mountPath: /var/lib/pd - mountPropagation: HostToContainer -- name: scripts - mountPath: /tmp/scripts -- name: fuse - mountPath: /tmp/fuse -volumes: -- name: scripts - emptyDir: {} -- name: fuse - emptyDir: {} -postStart: - pd: - command: - - /tmp/scripts/wait-fuse.sh` - if string(out) != expected { - t.Error("expected to get", expected, "but got", string(out)) - } -} diff --git a/pkg/webhook/config/watcher/watcher.go b/pkg/webhook/config/watcher/watcher.go deleted file mode 100644 index 4daa045297..0000000000 --- a/pkg/webhook/config/watcher/watcher.go +++ /dev/null @@ -1,344 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package watcher - -import ( - "errors" - "fmt" - "html/template" - "io/ioutil" - "os" - "strings" - - "github.com/ghodss/yaml" - - "github.com/chaos-mesh/chaos-mesh/controllers/metrics" - "github.com/chaos-mesh/chaos-mesh/pkg/webhook/config" - - ctrl "sigs.k8s.io/controller-runtime" - - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/kubernetes" - k8sv1 "k8s.io/client-go/kubernetes/typed/core/v1" - ctrlconfig "sigs.k8s.io/controller-runtime/pkg/client/config" -) - -var log = ctrl.Log.WithName("inject-webhook") -var restClusterConfig = ctrlconfig.GetConfig -var kubernetesNewForConfig = kubernetes.NewForConfig - -const ( - serviceAccountNamespaceFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace" - templateItemKey = "data" -) - -// ErrWatchChannelClosed should restart watcher -var ErrWatchChannelClosed = errors.New("watcher channel has closed") - -// K8sConfigMapWatcher is a struct that connects to the API and collects, parses, and emits sidecar configurations -type K8sConfigMapWatcher struct { - Config - client k8sv1.CoreV1Interface - metrics *metrics.ChaosCollector -} - -// New creates a new K8sConfigMapWatcher -func New(cfg Config, metrics *metrics.ChaosCollector) (*K8sConfigMapWatcher, error) { - c := K8sConfigMapWatcher{Config: cfg, metrics: metrics} - if strings.TrimSpace(c.TemplateNamespace) == "" { - // ENHANCEMENT: support downward API/env vars instead? https://github.com/kubernetes/kubernetes/blob/release-1.0/docs/user-guide/downward-api.md - // load from file on disk for serviceaccount: /var/run/secrets/kubernetes.io/serviceaccount/namespace - nsBytes, err := ioutil.ReadFile(serviceAccountNamespaceFilePath) - if err != nil { - if os.IsNotExist(err) { - return nil, fmt.Errorf("%s: maybe you should specify ----template-namespace if you are running outside of kubernetes", err.Error()) - } - return nil, err - } - ns := strings.TrimSpace(string(nsBytes)) - if ns != "" { - c.TemplateNamespace = ns - log.Info("Inferred ConfigMap", - "template namespace", c.TemplateNamespace, "filepath", serviceAccountNamespaceFilePath) - } else { - return nil, errors.New("can not found namespace. maybe you should specify --template-namespace if you are running outside of kubernetes") - } - } - - log.Info("Creating Kubernetes client to talk to the api-server") - k8sConfig, err := restClusterConfig() - if err != nil { - return nil, err - } - - clientset, err := kubernetesNewForConfig(k8sConfig) - if err != nil { - return nil, err - } - - c.client = clientset.CoreV1() - if err = validate(&c); err != nil { - return nil, fmt.Errorf("validation failed for K8sConfigMapWatcher: %s", err.Error()) - } - log.Info("Created ConfigMap watcher", - "apiserver", k8sConfig.Host, "template namespaces", c.TemplateNamespace, - "template labels", c.TemplateLabels, "config labels", c.ConfigLabels) - return &c, nil -} - -func validate(c *K8sConfigMapWatcher) error { - if c == nil { - return errors.New("configmap watcher was nil") - } - if c.TemplateNamespace == "" { - return errors.New("namespace is empty") - } - if c.TemplateLabels == nil { - return errors.New("template labels was an uninitialized map") - } - if c.ConfigLabels == nil { - return errors.New("config labels was an uninitialized map") - } - if c.client == nil { - return errors.New("k8s client was not setup properly") - } - return nil -} - -// Watch watches for events impacting watched ConfigMaps and emits their events across a channel -func (c *K8sConfigMapWatcher) Watch(notifyMe chan<- interface{}, stopCh <-chan struct{}) error { - log.Info("Watching for ConfigMaps for changes", - "template namespace", c.TemplateNamespace, "labels", c.ConfigLabels) - templateWatcher, err := c.client.ConfigMaps(c.TemplateNamespace).Watch(metav1.ListOptions{ - LabelSelector: mapStringStringToLabelSelector(c.TemplateLabels), - }) - if err != nil { - return fmt.Errorf("unable to create template watcher (possible serviceaccount RBAC/ACL failure?): %s", err.Error()) - } - - targetNamespace := "" - if !c.Config.ClusterScoped { - targetNamespace = c.TargetNamespace - } - - configWatcher, err := c.client.ConfigMaps(targetNamespace).Watch(metav1.ListOptions{ - LabelSelector: mapStringStringToLabelSelector(c.ConfigLabels), - }) - if err != nil { - return fmt.Errorf("unable to create config watcher (possible serviceaccount RBAC/ACL failure?): %s", err.Error()) - } - defer func() { - configWatcher.Stop() - templateWatcher.Stop() - }() - for { - select { - case e, ok := <-templateWatcher.ResultChan(): - // channel may closed caused by HTTP timeout, should restart watcher - // detail at https://github.com/kubernetes/client-go/issues/334 - if !ok { - log.V(5).Info("channel has closed, will restart watcher") - return ErrWatchChannelClosed - } - if e.Type == watch.Error { - return apierrs.FromObject(e.Object) - } - log.V(3).Info("type", e.Type, "kind", e.Object.GetObjectKind()) - switch e.Type { - case watch.Added: - fallthrough - case watch.Modified: - fallthrough - case watch.Deleted: - // signal reconciliation of all InjectionConfigs - log.V(3).Info("Signalling event received from watch channel", - "type", e.Type, "kind", e.Object.GetObjectKind()) - notifyMe <- struct{}{} - default: - log.Error(nil, "got unsupported event! skipping", "type", e.Type, "kind", e.Object.GetObjectKind()) - } - case e, ok := <-configWatcher.ResultChan(): - // channel may closed caused by HTTP timeout, should restart watcher - // detail at https://github.com/kubernetes/client-go/issues/334 - if !ok { - log.V(5).Info("channel has closed, will restart watcher") - return ErrWatchChannelClosed - } - if e.Type == watch.Error { - return apierrs.FromObject(e.Object) - } - log.V(3).Info("type", e.Type, "kind", e.Object.GetObjectKind()) - switch e.Type { - case watch.Added: - fallthrough - case watch.Modified: - fallthrough - case watch.Deleted: - // signal reconciliation of all InjectionConfigs - log.V(3).Info("Signalling event received from watch channel", - "type", e.Type, "kind", e.Object.GetObjectKind()) - notifyMe <- struct{}{} - default: - log.Error(nil, "got unsupported event! skipping", "type", e.Type, "kind", e.Object.GetObjectKind()) - } - // events! yay! - case <-stopCh: - log.V(2).Info("Stopping configmap watcher, context indicated we are done") - // clean up, we cancelled the context, so stop the watch - return nil - } - } -} - -func mapStringStringToLabelSelector(m map[string]string) string { - // https://github.com/kubernetes/apimachinery/issues/47 - return labels.Set(m).String() -} - -// GetInjectionConfigs fetches all matching ConfigMaps -func (c *K8sConfigMapWatcher) GetInjectionConfigs() (map[string][]*config.InjectionConfig, error) { - templates, err := c.GetTemplates() - if err != nil { - return nil, err - } - - configs, err := c.GetConfigs() - if err != nil { - return nil, err - } - if len(templates) == 0 || len(configs) == 0 { - log.Info("cannot get injection configs") - return nil, nil - } - - injectionConfigs := make(map[string][]*config.InjectionConfig) - if c.metrics != nil { - c.metrics.InjectionConfigs.Reset() - } - for _, conf := range configs { - temp, ok := templates[conf.Template] - if !ok { - log.Error(errors.New("cannot find the specified template"), "", - "template", conf.Template, "namespace", conf.Namespace, "config", conf.Name) - if c.metrics != nil { - c.metrics.TemplateNotExist.WithLabelValues(conf.Namespace, conf.Template).Inc() - } - continue - } - yamlTemp, err := template.New("").Parse(temp) - if err != nil { - log.Error(err, "failed to parse template", - "template", conf.Template, "config", conf.Name) - continue - } - - result, err := renderTemplateWithArgs(yamlTemp, conf.Arguments) - if err != nil { - log.Error(err, "failed to render template", - "template", conf.Template, "config", conf.Name) - continue - } - - var injectConfig config.InjectionConfig - if err := yaml.Unmarshal(result, &injectConfig); err != nil { - log.Error(err, "failed to unmarshal injection config", "injection config", string(result)) - continue - } - - injectConfig.Selector = conf.Selector - injectConfig.Name = conf.Name - if _, ok := injectionConfigs[conf.Namespace]; !ok { - injectionConfigs[conf.Namespace] = make([]*config.InjectionConfig, 0) - } - injectionConfigs[conf.Namespace] = append(injectionConfigs[conf.Namespace], &injectConfig) - if c.metrics != nil { - c.metrics.InjectionConfigs.WithLabelValues(conf.Namespace, conf.Template).Inc() - } - } - - return injectionConfigs, nil -} - -// GetTemplates returns a map of common templates -func (c *K8sConfigMapWatcher) GetTemplates() (map[string]string, error) { - log.Info("Fetching Template Configs...") - templateList, err := c.client.ConfigMaps(c.TemplateNamespace).List(metav1.ListOptions{ - LabelSelector: mapStringStringToLabelSelector(c.TemplateLabels), - }) - if err != nil { - return nil, err - } - - log.Info("Fetched templates", "templates count", len(templateList.Items)) - templates := make(map[string]string, len(templateList.Items)) - for _, temp := range templateList.Items { - templates[temp.Name] = temp.Data[templateItemKey] - } - if c.metrics != nil { - c.metrics.SidecarTemplates.Set(float64(len(templates))) - } - return templates, nil -} - -// GetConfigs returns the list of template args config -func (c *K8sConfigMapWatcher) GetConfigs() ([]*config.TemplateArgs, error) { - log.Info("Fetching Configs...") - // List all the configs with the required label selector - configList, err := c.client.ConfigMaps("").List(metav1.ListOptions{ - LabelSelector: mapStringStringToLabelSelector(c.ConfigLabels), - }) - if err != nil { - return nil, err - } - - log.Info("Fetched configs", "configs count", len(configList.Items)) - if c.metrics != nil { - c.metrics.ConfigTemplates.Reset() - } - configSet := make(map[string]map[string]struct{}) - result := make([]*config.TemplateArgs, 0) - for _, item := range configList.Items { - for _, payload := range item.Data { - conf, err := config.LoadTemplateArgs(strings.NewReader(payload)) - if err != nil { - log.Error(err, "failed to load template args", "payload", payload) - if c.metrics != nil { - c.metrics.TemplateLoadError.Inc() - } - continue - } - conf.Namespace = item.Namespace - if _, ok := configSet[conf.Namespace]; !ok { - configSet[conf.Namespace] = make(map[string]struct{}) - } - if _, ok := configSet[conf.Namespace][conf.Name]; ok { - log.Error(errors.New("duplicate config name"), "", - "namespace", conf.Namespace, "name", conf.Name) - if c.metrics != nil { - c.metrics.ConfigNameDuplicate.WithLabelValues(conf.Namespace, conf.Name).Inc() - } - continue - } - configSet[conf.Namespace][conf.Name] = struct{}{} - if c.metrics != nil { - c.metrics.ConfigTemplates.WithLabelValues(conf.Namespace, conf.Template).Inc() - } - result = append(result, conf) - } - } - return result, nil -} diff --git a/pkg/webhook/config/watcher/watcher_test.go b/pkg/webhook/config/watcher/watcher_test.go deleted file mode 100644 index cdddb437e7..0000000000 --- a/pkg/webhook/config/watcher/watcher_test.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package watcher - -import ( - "fmt" - - ctrl "sigs.k8s.io/controller-runtime" - - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("webhook config watcher", func() { - Context("New", func() { - It("should return InClusterConfig error", func() { - old := restClusterConfig - defer func() { restClusterConfig = old }() - - restClusterConfig = func() (*rest.Config, error) { - return nil, fmt.Errorf("InClusterConfig error") - } - config := NewConfig() - config.TemplateNamespace = "testNamespace" - configWatcher, err := New(*config, nil) - Expect(configWatcher).To(BeNil()) - Expect(err).ToNot(BeNil()) - Expect(fmt.Sprintf("%s", err)).To(ContainSubstring("InClusterConfig")) - }) - - It("should return NewForConfig error", func() { - restClusterConfig = MockClusterConfig - old := kubernetesNewForConfig - defer func() { kubernetesNewForConfig = old }() - - kubernetesNewForConfig = func(c *rest.Config) (*kubernetes.Clientset, error) { - return nil, fmt.Errorf("NewForConfig error") - } - config := NewConfig() - config.TemplateNamespace = "testNamespace" - configWatcher, err := New(*config, nil) - Expect(configWatcher).To(BeNil()) - Expect(err).ToNot(BeNil()) - Expect(fmt.Sprintf("%s", err)).To(ContainSubstring("NewForConfig")) - }) - - It("should return no error", func() { - restClusterConfig = MockClusterConfig - - config := NewConfig() - config.TemplateNamespace = "testNamespace" - configWatcher, err := New(*config, nil) - Expect(configWatcher).ToNot(BeNil()) - Expect(err).To(BeNil()) - }) - }) - - Context("validate", func() { - It("should return configmap watcher was nil", func() { - err := validate(nil) - Expect(err).ToNot(BeNil()) - Expect(fmt.Sprintf("%s", err)).To(ContainSubstring("configmap watcher was nil")) - }) - - It("should return namespace is empty", func() { - var cmw K8sConfigMapWatcher - err := validate(&cmw) - Expect(err).ToNot(BeNil()) - Expect(fmt.Sprintf("%s", err)).To(ContainSubstring("namespace is empty")) - }) - - It("should return template labels was an uninitialized map", func() { - var cmw K8sConfigMapWatcher - cmw.TemplateNamespace = "testNamespace" - err := validate(&cmw) - Expect(err).ToNot(BeNil()) - Expect(fmt.Sprintf("%s", err)).To(ContainSubstring("template labels was an uninitialized map")) - }) - - It("should return config labels was an uninitialized map", func() { - var cmw K8sConfigMapWatcher - cmw.TemplateNamespace = "testNamespace" - cmw.TemplateLabels = map[string]string{"test": "test"} - err := validate(&cmw) - Expect(err).ToNot(BeNil()) - Expect(fmt.Sprintf("%s", err)).To(ContainSubstring("config labels was an uninitialized map")) - }) - }) - - Context("Watch error", func() { - It("should return unable to create template watcher", func() { - var cmw K8sConfigMapWatcher - cmw.Config = *NewConfig() - cmw.TemplateNamespace = "testNamespace" - k8sConfig, _ := MockClusterConfig() - clientset, _ := kubernetesNewForConfig(k8sConfig) - cmw.client = clientset.CoreV1() - sigChan := make(chan interface{}, 10) - stopCh := ctrl.SetupSignalHandler() - err := cmw.Watch(sigChan, stopCh) - Expect(err).ToNot(BeNil()) - Expect(fmt.Sprintf("%s", err)).To(ContainSubstring("unable to create template watcher")) - }) - }) - - Context("get", func() { - It("should return error when ConfigMaps.List", func() { - var cmw K8sConfigMapWatcher - cmw.Config = *NewConfig() - cmw.TemplateNamespace = "testNamespace" - k8sConfig, _ := MockClusterConfig() - clientset, _ := kubernetesNewForConfig(k8sConfig) - cmw.client = clientset.CoreV1() - _, err := cmw.GetConfigs() - Expect(err).ToNot(BeNil()) - }) - }) -}) diff --git a/pkg/webhook/errors.go b/pkg/webhook/errors.go new file mode 100644 index 0000000000..d18dbe2f49 --- /dev/null +++ b/pkg/webhook/errors.go @@ -0,0 +1,24 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package webhook + +import ( + "github.com/pkg/errors" +) + +var ( + errInvalidValue error = errors.New("invalid value") +) diff --git a/pkg/webhook/inject/command.go b/pkg/webhook/inject/command.go deleted file mode 100644 index 53bd14dd5b..0000000000 --- a/pkg/webhook/inject/command.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package inject - -import "strings" - -// MergeCommands merges injected commands and original commands for injecting commands to containers, -// eg: inject: []string{"bash", "-c", "/check.sh"}, origin: []string{"bash", "-c", "/run.sh"} -// merged commands: []string{"/bin/sh", "-ec", "/check.sh\n/run.sh"} -func MergeCommands(inject []string, origin []string, args []string) []string { - // merge injected commands - scripts := mergeCommandsAction(inject) - - // merge original commands - scripts += mergeOriginCommandsAndArgs(origin, args) - - return []string{"/bin/sh", "-ec", scripts} -} - -func mergeCommandsAction(commands []string) string { - scripts := "" - - for i := 0; i < len(commands); i++ { - cmd := commands[i] - if isCommonScripts(cmd) { - if len(commands) <= i+1 { - scripts += cmd - scripts += "\n" - break - } - - if strings.HasPrefix(commands[i+1], "-") { - i++ - continue - } - - tempScripts := cmd + " " - for j := i + 1; j < len(commands); j++ { - c := commands[j] - if j < len(commands)-1 { - c += " " - } - - tempScripts += c - } - - scripts += tempScripts - scripts += "\n" - break - } - - if len(commands) <= i+1 { - scripts += cmd - scripts += "\n" - break - } - - if strings.HasPrefix(commands[i+1], "-") { - tempScripts := cmd + " " - for j := i + 1; j < len(commands); j++ { - if strings.HasPrefix(commands[j], "-") { - c := commands[j] - if j < len(commands)-1 { - c += " " - } - tempScripts += c - continue - } - } - scripts += tempScripts - scripts += "\n" - break - } - - scripts += cmd - scripts += "\n" - } - - return scripts -} - -func mergeOriginCommandsAndArgs(origin []string, args []string) string { - commands := append(origin, args...) - - return mergeCommandsAction(commands) -} - -func isCommonScripts(cmd string) bool { - if isShellScripts(cmd) || isPythonScripts(cmd) { - return true - } - - return false -} - -func isShellScripts(cmd string) bool { - if cmd == "bash" || cmd == "sh" || - strings.HasPrefix(cmd, "bash ") || strings.HasPrefix(cmd, "sh ") || - strings.HasPrefix(cmd, "/bin/sh") || strings.HasPrefix(cmd, "/bin/bash") || - strings.HasPrefix(cmd, "/usr/bin/sh") || strings.HasPrefix(cmd, "/usr/bin/bash") || - strings.HasPrefix(cmd, "/usr/share/bin/sh") || strings.HasPrefix(cmd, "/usr/share/bin/bash") { - return true - } - - return false -} - -func isPythonScripts(cmd string) bool { - if cmd == "python" || cmd == "python3" || - strings.HasPrefix(cmd, "python ") || strings.HasPrefix(cmd, "python3 ") || - strings.HasPrefix(cmd, "/bin/python") || strings.HasPrefix(cmd, "/bin/python3") || - strings.HasPrefix(cmd, "/usr/bin/python") || strings.HasPrefix(cmd, "/usr/bin/python3") || - strings.HasPrefix(cmd, "/usr/share/bin/python") || strings.HasPrefix(cmd, "/usr/share/bin/python3") { - return true - } - - return false -} diff --git a/pkg/webhook/inject/command_test.go b/pkg/webhook/inject/command_test.go deleted file mode 100644 index 9db788f61f..0000000000 --- a/pkg/webhook/inject/command_test.go +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package inject - -import ( - "testing" - - . "github.com/onsi/gomega" -) - -func TestIsCommonScripts(t *testing.T) { - g := NewGomegaWithT(t) - - type TestCase struct { - name string - cmd string - expectedValue bool - } - - tcs := []TestCase{ - { - name: "command scripts: bash", - cmd: "bash", - expectedValue: true, - }, - { - name: "command scripts: bash -c echo 1", - cmd: "bash -c echo 1", - expectedValue: true, - }, - { - name: "command scripts: sh", - cmd: "sh", - expectedValue: true, - }, - { - name: "command scripts: /bin/sh", - cmd: "/bin/sh", - expectedValue: true, - }, - { - name: "command scripts: /bin/bash", - cmd: "/bin/bash", - expectedValue: true, - }, - { - name: "command scripts: /usr/bin/bash", - cmd: "/usr/bin/bash", - expectedValue: true, - }, - { - name: "not command scripts: /usr/bin/echo", - cmd: "/usr/bin/echo", - expectedValue: false, - }, - { - name: "not command scripts: /chaos-mesh", - cmd: "/chaos-mesh", - expectedValue: false, - }, - } - - for _, tc := range tcs { - g.Expect(isCommonScripts(tc.cmd)).To(Equal(tc.expectedValue), tc.name) - } -} - -func TestIsShellScripts(t *testing.T) { - g := NewGomegaWithT(t) - - type TestCase struct { - name string - cmd string - expectedValue bool - } - - tcs := []TestCase{ - { - name: "bash", - cmd: "bash", - expectedValue: true, - }, - { - name: "bash -c echo 1", - cmd: "bash -c echo 1", - expectedValue: true, - }, - { - name: "/usr/bin/bash", - cmd: "/usr/bin/bash", - expectedValue: true, - }, - { - name: "/usr/bin/echo", - cmd: "/usr/bin/echo", - expectedValue: false, - }, - { - name: "/chaos-mesh", - cmd: "/chaos-mesh", - expectedValue: false, - }, - } - - for _, tc := range tcs { - g.Expect(isShellScripts(tc.cmd)).To(Equal(tc.expectedValue), tc.name) - } -} - -func TestIsPythonScripts(t *testing.T) { - g := NewGomegaWithT(t) - - type TestCase struct { - name string - cmd string - expectedValue bool - } - - tcs := []TestCase{ - { - name: "python", - cmd: "python", - expectedValue: true, - }, - { - name: "bash -c echo 1", - cmd: "bash -c echo 1", - expectedValue: false, - }, - { - name: "/bin/python", - cmd: "/bin/python", - expectedValue: true, - }, - { - name: "/usr/bin/bash", - cmd: "/usr/bin/bash", - expectedValue: false, - }, - { - name: "/usr/bin/echo", - cmd: "/usr/bin/echo", - expectedValue: false, - }, - { - name: "/chaos-mesh", - cmd: "/chaos-mesh", - expectedValue: false, - }, - } - - for _, tc := range tcs { - g.Expect(isPythonScripts(tc.cmd)).To(Equal(tc.expectedValue), tc.name) - } -} - -func TestMergeCommandsAction(t *testing.T) { - g := NewGomegaWithT(t) - - type TestCase struct { - name string - commands []string - expectedValue string - } - - tcs := []TestCase{ - { - name: "scripts files", - commands: []string{ - "/bin/sh", - "start_chaos_mesh.sh", - }, - expectedValue: "/bin/sh start_chaos_mesh.sh\n", - }, - { - name: "common scripts", - commands: []string{ - "bash", - "-ec", - "echo $HOSENAME\n /start_chaos_mesh.sh -s t1 \n -v t2", - }, - expectedValue: "echo $HOSENAME\n /start_chaos_mesh.sh -s t1 \n -v t2\n", - }, - { - name: "common start scripts", - commands: []string{ - "/chaos-mesh", - "--c t", - "--v 2", - "--log stdout", - }, - expectedValue: "/chaos-mesh --c t --v 2 --log stdout\n", - }, - { - name: "one line", - commands: []string{ - "/chaos-mesh --c t --v 2 --log stdout", - }, - expectedValue: "/chaos-mesh --c t --v 2 --log stdout\n", - }, - } - - for _, tc := range tcs { - g.Expect(mergeCommandsAction(tc.commands)).To(Equal(tc.expectedValue), tc.name) - } -} - -func TestMergeOriginCommandsAndArgs(t *testing.T) { - g := NewGomegaWithT(t) - - type TestCase struct { - name string - commands []string - args []string - expectedValue string - } - - tcs := []TestCase{ - { - name: "only commands", - commands: []string{ - "bash", - "-ec", - "echo $HOSENAME\n /start_chaos_mesh.sh -s t1 \n -v t2", - }, - expectedValue: "echo $HOSENAME\n /start_chaos_mesh.sh -s t1 \n -v t2\n", - }, - { - name: "only args", - args: []string{ - "bash", - "-ec", - "echo $HOSENAME\n /start_chaos_mesh.sh -s t1 \n -v t2", - }, - expectedValue: "echo $HOSENAME\n /start_chaos_mesh.sh -s t1 \n -v t2\n", - }, - { - name: "commands and args", - commands: []string{ - "/chaos-mesh", - }, - args: []string{ - "--c t", - "--v 2", - "--log stdout", - }, - expectedValue: "/chaos-mesh --c t --v 2 --log stdout\n", - }, - } - - for _, tc := range tcs { - g.Expect(mergeOriginCommandsAndArgs(tc.commands, tc.args)).To(Equal(tc.expectedValue), tc.name) - } -} - -func TestMergeCommands(t *testing.T) { - g := NewGomegaWithT(t) - - type TestCase struct { - name string - inject []string - origin []string - args []string - expectedValue []string - } - - tcs := []TestCase{ - { - name: "scripts file", - inject: []string{ - "/check.sh -v 1", - }, - origin: []string{ - "/bin/sh", - "/start.sh", - }, - expectedValue: []string{ - "/bin/sh", - "-ec", - "/check.sh -v 1\n/bin/sh /start.sh\n", - }, - }, - { - name: "common scripts", - inject: []string{ - "/check.sh -v 1", - }, - origin: []string{ - "bash", - "-c", - "set -ex\n[[ `hostname` =~ -([0-9]+)$ ]] || exit 1\n/tiflash server --config-file /data/config.toml", - }, - expectedValue: []string{ - "/bin/sh", - "-ec", - "/check.sh -v 1\nset -ex\n[[ `hostname` =~ -([0-9]+)$ ]] || exit 1\n/tiflash server --config-file /data/config.toml\n", - }, - }, - } - - for _, tc := range tcs { - g.Expect(MergeCommands(tc.inject, tc.origin, tc.args)).To(Equal(tc.expectedValue), tc.name) - } -} diff --git a/pkg/webhook/inject/inject.go b/pkg/webhook/inject/inject.go deleted file mode 100644 index dea10ff16e..0000000000 --- a/pkg/webhook/inject/inject.go +++ /dev/null @@ -1,568 +0,0 @@ -// Copyright 2019 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package inject - -import ( - "context" - "encoding/json" - "fmt" - "strings" - - "github.com/chaos-mesh/chaos-mesh/controllers/metrics" - "github.com/chaos-mesh/chaos-mesh/pkg/annotation" - controllerCfg "github.com/chaos-mesh/chaos-mesh/pkg/config" - "github.com/chaos-mesh/chaos-mesh/pkg/selector" - "github.com/chaos-mesh/chaos-mesh/pkg/webhook/config" - - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - "k8s.io/api/admission/v1beta1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" -) - -var log = ctrl.Log.WithName("inject-webhook") - -var ignoredNamespaces = []string{ - metav1.NamespaceSystem, - metav1.NamespacePublic, -} - -const ( - // StatusInjected is the annotation value for /status that indicates an injection was already performed on this pod - StatusInjected = "injected" -) - -// Inject do pod template config inject -func Inject(res *v1beta1.AdmissionRequest, cli client.Client, cfg *config.Config, controllerCfg *controllerCfg.ChaosControllerConfig, metrics *metrics.ChaosCollector) *v1beta1.AdmissionResponse { - var pod corev1.Pod - if err := json.Unmarshal(res.Object.Raw, &pod); err != nil { - log.Error(err, "Could not unmarshal raw object") - return &v1beta1.AdmissionResponse{ - Result: &metav1.Status{ - Message: err.Error(), - }, - } - } - - // Deal with potential empty fields, e.g., when the pod is created by a deployment - podName := potentialPodName(&pod.ObjectMeta) - if pod.ObjectMeta.Namespace == "" { - pod.ObjectMeta.Namespace = res.Namespace - } - - log.Info("AdmissionReview for", - "Kind", res.Kind, "Namespace", res.Namespace, "Name", res.Name, "podName", podName, "UID", res.UID, "patchOperation", res.Operation, "UserInfo", res.UserInfo) - log.V(4).Info("Object", "Object", string(res.Object.Raw)) - log.V(4).Info("OldObject", "OldObject", string(res.OldObject.Raw)) - log.V(4).Info("Pod", "Pod", pod) - - requiredKey, ok := injectRequired(&pod.ObjectMeta, cli, cfg, controllerCfg) - if !ok { - log.Info("Skipping injection due to policy check", "namespace", pod.ObjectMeta.Namespace, "name", podName) - return &v1beta1.AdmissionResponse{ - Allowed: true, - } - } - - if metrics != nil { - metrics.InjectRequired.WithLabelValues(res.Namespace, requiredKey).Inc() - } - injectionConfig, err := cfg.GetRequestedConfig(pod.Namespace, requiredKey) - if err != nil { - log.Error(err, "Error getting injection config, permitting launch of pod with no sidecar injected", "injectionConfig", - injectionConfig) - // dont prevent pods from launching! just return allowed - return &v1beta1.AdmissionResponse{ - Allowed: true, - } - } - - if injectionConfig.Selector != nil { - meet, err := selector.CheckPodMeetSelector(pod, *injectionConfig.Selector) - if err != nil { - log.Error(err, "Failed to check pod selector", "namespace", pod.Namespace) - return &v1beta1.AdmissionResponse{ - Allowed: true, - } - } - - if !meet { - log.Info("Skipping injection, this pod does not meet the selection criteria", - "namespace", pod.Namespace, "name", pod.Name) - return &v1beta1.AdmissionResponse{ - Allowed: true, - } - } - } - - annotations := map[string]string{cfg.StatusAnnotationKey(): StatusInjected} - - patchBytes, err := createPatch(&pod, injectionConfig, annotations) - if err != nil { - return &v1beta1.AdmissionResponse{ - Result: &metav1.Status{ - Message: err.Error(), - }, - } - } - - log.Info("AdmissionResponse: patch", "patchBytes", string(patchBytes)) - if metrics != nil { - metrics.Injections.WithLabelValues(res.Namespace, requiredKey).Inc() - } - return &v1beta1.AdmissionResponse{ - Allowed: true, - Patch: patchBytes, - PatchType: func() *v1beta1.PatchType { - pt := v1beta1.PatchTypeJSONPatch - return &pt - }(), - } -} - -// Check whether the target resource need to be injected and return the required config name -func injectRequired(metadata *metav1.ObjectMeta, cli client.Client, cfg *config.Config, controllerCfg *controllerCfg.ChaosControllerConfig) (string, bool) { - // skip special kubernetes system namespaces - for _, namespace := range ignoredNamespaces { - if metadata.Namespace == namespace { - log.Info("Skip mutation for it' in special namespace", "name", metadata.Name, "namespace", metadata.Namespace) - return "", false - } - } - - if controllerCfg.EnableFilterNamespace { - ok, err := selector.IsAllowedNamespaces(context.Background(), cli, metadata.Namespace) - if err != nil { - log.Error(err, "fail to check whether this namespace should be injected", "namespace", metadata.Namespace) - } - - if !ok { - log.Info("Skip mutation for it' in special namespace", "name", metadata.Name, "namespace", metadata.Namespace) - return "", false - } - } - - log.V(4).Info("meta", "meta", metadata) - - if checkInjectStatus(metadata, cfg) { - log.Info("Pod annotation indicates injection already satisfied, skipping", - "namespace", metadata.Namespace, "name", metadata.Name, - "annotationKey", cfg.StatusAnnotationKey(), "value", StatusInjected) - return "", false - } - - requiredConfig, ok := injectByPodRequired(metadata, cfg) - if ok { - log.Info("Pod annotation requesting sidecar config", - "namespace", metadata.Namespace, "name", metadata.Name, - "annotation", cfg.RequestAnnotationKey(), "requiredConfig", requiredConfig) - return requiredConfig, true - } - - requiredConfig, ok = injectByNamespaceRequired(metadata, cli, cfg) - if ok { - log.Info("Pod annotation requesting sidecar config", - "namespace", metadata.Namespace, "name", metadata.Name, - "annotation", cfg.RequestAnnotationKey(), "requiredConfig", requiredConfig) - return requiredConfig, true - } - - requiredConfig, ok = injectByNamespaceInitRequired(metadata, cli, cfg) - if ok { - log.Info("Pod annotation init requesting sidecar config", - "namespace", metadata.Namespace, "name", metadata.Name, - "annotation", cfg.RequestAnnotationKey(), "requiredConfig", requiredConfig) - return requiredConfig, true - } - - return "", false -} - -func checkInjectStatus(metadata *metav1.ObjectMeta, cfg *config.Config) bool { - annotations := metadata.GetAnnotations() - if annotations == nil { - annotations = make(map[string]string) - } - - status, ok := annotations[cfg.StatusAnnotationKey()] - if ok && strings.ToLower(status) == StatusInjected { - return true - } - - return false -} - -func injectByNamespaceRequired(metadata *metav1.ObjectMeta, cli client.Client, cfg *config.Config) (string, bool) { - var ns corev1.Namespace - if err := cli.Get(context.Background(), types.NamespacedName{Name: metadata.Namespace}, &ns); err != nil { - log.Error(err, "failed to get namespace", "namespace", metadata.Namespace) - return "", false - } - annotations := ns.GetAnnotations() - if annotations == nil { - annotations = make(map[string]string) - } - - required, ok := annotations[annotation.GenKeyForWebhook(cfg.RequestAnnotationKey(), metadata.Name)] - if !ok { - log.Info("Pod annotation by namespace is missing, skipping injection", - "namespace", metadata.Namespace, "pod", metadata.Name, "config", required) - return "", false - } - - log.Info("Get sidecar config from namespace annotations", - "namespace", metadata.Namespace, "pod", metadata.Name, "config", required) - return strings.ToLower(required), true -} - -func injectByNamespaceInitRequired(metadata *metav1.ObjectMeta, cli client.Client, cfg *config.Config) (string, bool) { - var ns corev1.Namespace - if err := cli.Get(context.Background(), types.NamespacedName{Name: metadata.Namespace}, &ns); err != nil { - log.Error(err, "failed to get namespace", "namespace", metadata.Namespace) - return "", false - } - - annotations := ns.GetAnnotations() - if annotations == nil { - annotations = make(map[string]string) - } - - required, ok := annotations[cfg.RequestInitAnnotationKey()] - if !ok { - log.Info("Pod annotation by namespace is missing, skipping injection", - "namespace", metadata.Namespace, "pod", metadata.Name, "config", required) - return "", false - } - - log.Info("Get sidecar config from namespace annotations", - "namespace", metadata.Namespace, "pod", metadata.Name, "config", required) - return strings.ToLower(required), true -} - -func injectByPodRequired(metadata *metav1.ObjectMeta, cfg *config.Config) (string, bool) { - annotations := metadata.GetAnnotations() - if annotations == nil { - annotations = make(map[string]string) - } - - required, ok := annotations[cfg.RequestAnnotationKey()] - if !ok { - log.Info("Pod annotation is missing, skipping injection", - "namespace", metadata.Namespace, "name", metadata.Name, "annotation", cfg.RequestAnnotationKey()) - return "", false - } - - log.Info("Get sidecar config from pod annotations", - "namespace", metadata.Namespace, "pod", metadata.Name, "config", required) - return strings.ToLower(required), true -} - -// create mutation patch for resource -func createPatch(pod *corev1.Pod, inj *config.InjectionConfig, annotations map[string]string) ([]byte, error) { - var patch []patchOperation - - // make sure any injected containers in our config get the EnvVars and VolumeMounts injected - // this mutates inj.Containers with our environment vars - mutatedInjectedContainers := mergeEnvVars(inj.Environment, inj.Containers) - mutatedInjectedContainers = mergeVolumeMounts(inj.VolumeMounts, mutatedInjectedContainers) - - // make sure any injected init containers in our config get the EnvVars and VolumeMounts injected - // this mutates inj.InitContainers with our environment vars - mutatedInjectedInitContainers := mergeEnvVars(inj.Environment, inj.InitContainers) - mutatedInjectedInitContainers = mergeVolumeMounts(inj.VolumeMounts, mutatedInjectedInitContainers) - - // patch all existing containers with the env vars and volume mounts - patch = append(patch, setVolumeMounts(pod.Spec.Containers, inj.VolumeMounts, "/spec/containers")...) - // TODO: fix set env - // setEnvironment may not work, because we replace the whole container in `setVolumeMounts` - patch = append(patch, setEnvironment(pod.Spec.Containers, inj.Environment)...) - - // patch containers with our injected containers - patch = append(patch, addContainers(pod.Spec.Containers, mutatedInjectedContainers, "/spec/containers")...) - - // add initContainers, hostAliases and volumes - patch = append(patch, addContainers(pod.Spec.InitContainers, mutatedInjectedInitContainers, "/spec/initContainers")...) - patch = append(patch, addHostAliases(pod.Spec.HostAliases, inj.HostAliases, "/spec/hostAliases")...) - patch = append(patch, addVolumes(pod.Spec.Volumes, inj.Volumes, "/spec/volumes")...) - - // set annotations - patch = append(patch, updateAnnotations(pod.Annotations, annotations)...) - - // set shareProcessNamespace - patch = append(patch, updateShareProcessNamespace(inj.ShareProcessNamespace)...) - - // TODO: remove injecting commands when sidecar container supported - // set commands and args - patch = append(patch, setCommands(pod.Spec.Containers, inj.PostStart)...) - - return json.Marshal(patch) -} - -func setCommands(target []corev1.Container, postStart map[string]config.ExecAction) (patch []patchOperation) { - if postStart == nil { - return - } - - for containerIndex, container := range target { - execCmd, ok := postStart[container.Name] - if !ok { - continue - } - - path := fmt.Sprintf("/spec/containers/%d/command", containerIndex) - - commands := MergeCommands(execCmd.Command, container.Command, container.Args) - - log.Info("Inject command", "command", commands) - - patch = append(patch, patchOperation{ - Op: "replace", - Path: path, - Value: commands, - }) - - argsPath := fmt.Sprintf("/spec/containers/%d/args", containerIndex) - patch = append(patch, patchOperation{ - Op: "replace", - Path: argsPath, - Value: []string{}, - }) - } - return patch -} - -type patchOperation struct { - Op string `json:"op"` - Path string `json:"path"` - Value interface{} `json:"value,omitempty"` -} - -func setEnvironment(target []corev1.Container, addedEnv []corev1.EnvVar) (patch []patchOperation) { - var value interface{} - for containerIndex, container := range target { - // for each container in the spec, determine if we want to patch with any env vars - first := len(container.Env) == 0 - for _, add := range addedEnv { - path := fmt.Sprintf("/spec/containers/%d/env", containerIndex) - hasKey := false - // make sure we dont override any existing env vars; we only add, dont replace - for _, origEnv := range container.Env { - if origEnv.Name == add.Name { - hasKey = true - break - } - } - if !hasKey { - // make a patch - value = add - if first { - first = false - value = []corev1.EnvVar{add} - } else { - path = path + "/-" - } - patch = append(patch, patchOperation{ - Op: "add", - Path: path, - Value: value, - }) - } - } - } - - return patch -} - -func addContainers(target, added []corev1.Container, basePath string) (patch []patchOperation) { - first := len(target) == 0 - var value interface{} - for _, add := range added { - value = add - log.V(6).Info("Add container", "add", add) - path := basePath - if first { - first = false - value = []corev1.Container{add} - } else { - path = path + "/-" - } - patch = append(patch, patchOperation{ - Op: "add", - Path: path, - Value: value, - }) - } - return patch -} - -func addVolumes(target, added []corev1.Volume, basePath string) (patch []patchOperation) { - first := len(target) == 0 - var value interface{} - for _, add := range added { - value = add - path := basePath - if first { - first = false - value = []corev1.Volume{add} - } else { - path = path + "/-" - } - patch = append(patch, patchOperation{ - Op: "add", - Path: path, - Value: value, - }) - } - return patch -} - -func setVolumeMounts(target []corev1.Container, addedVolumeMounts []corev1.VolumeMount, basePath string) (patch []patchOperation) { - for index, c := range target { - volumeMounts := map[string]corev1.VolumeMount{} - for _, vm := range c.VolumeMounts { - volumeMounts[vm.Name] = vm - } - for _, added := range addedVolumeMounts { - log.Info("volumeMount", "add", added) - volumeMounts[added.Name] = added - } - - vs := []corev1.VolumeMount{} - for _, vm := range volumeMounts { - vs = append(vs, vm) - } - target[index].VolumeMounts = vs - } - - patch = append(patch, patchOperation{ - Op: "replace", - Path: basePath, - Value: target, - }) - - return patch -} - -func addHostAliases(target, added []corev1.HostAlias, basePath string) (patch []patchOperation) { - first := len(target) == 0 - var value interface{} - for _, add := range added { - value = add - path := basePath - if first { - first = false - value = []corev1.HostAlias{add} - } else { - path = path + "/-" - } - patch = append(patch, patchOperation{ - Op: "add", - Path: path, - Value: value, - }) - } - return patch -} - -// for containers, add any env vars that are not already defined in the Env list. -// this does _not_ return patches; this is intended to be used only on containers defined -// in the injection config, so the resources do not exist yet in the k8s api (thus no patch needed) -func mergeEnvVars(envs []corev1.EnvVar, containers []corev1.Container) []corev1.Container { - mutatedContainers := []corev1.Container{} - for _, c := range containers { - for _, newEnv := range envs { - // check each container for each env var by name. - // if the container has a matching name, dont override! - skip := false - for _, origEnv := range c.Env { - if origEnv.Name == newEnv.Name { - skip = true - break - } - } - if !skip { - c.Env = append(c.Env, newEnv) - } - } - mutatedContainers = append(mutatedContainers, c) - } - return mutatedContainers -} - -func mergeVolumeMounts(volumeMounts []corev1.VolumeMount, containers []corev1.Container) []corev1.Container { - mutatedContainers := []corev1.Container{} - for _, c := range containers { - for _, newVolumeMount := range volumeMounts { - // check each container for each volume mount by name. - // if the container has a matching name, dont override! - skip := false - for _, origVolumeMount := range c.VolumeMounts { - if origVolumeMount.Name == newVolumeMount.Name { - skip = true - break - } - } - if !skip { - c.VolumeMounts = append(c.VolumeMounts, newVolumeMount) - } - } - mutatedContainers = append(mutatedContainers, c) - } - return mutatedContainers -} - -func updateAnnotations(target map[string]string, added map[string]string) (patch []patchOperation) { - for key, value := range added { - if target == nil || target[key] == "" { - target = map[string]string{} - patch = append(patch, patchOperation{ - Op: "add", - Path: "/metadata/annotations", - Value: map[string]string{ - key: value, - }, - }) - } else { - patch = append(patch, patchOperation{ - Op: "replace", - Path: "/metadata/annotations/" + key, - Value: value, - }) - } - } - return patch -} - -func updateShareProcessNamespace(value bool) (patch []patchOperation) { - op := "add" - patch = append(patch, patchOperation{ - Op: op, - Path: "/spec/shareProcessNamespace", - Value: value, - }) - return patch -} - -func potentialPodName(metadata *metav1.ObjectMeta) string { - if metadata.Name != "" { - return metadata.Name - } - if metadata.GenerateName != "" { - return metadata.GenerateName + "***** (actual name not yet known)" - } - return "" -} diff --git a/pkg/webhook/inject/inject_test.go b/pkg/webhook/inject/inject_test.go deleted file mode 100644 index 475239ca54..0000000000 --- a/pkg/webhook/inject/inject_test.go +++ /dev/null @@ -1,455 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package inject - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "sigs.k8s.io/controller-runtime/pkg/client" - - controllerCfg "github.com/chaos-mesh/chaos-mesh/pkg/config" - "github.com/chaos-mesh/chaos-mesh/pkg/webhook/config" - - admissionv1beta1 "k8s.io/api/admission/v1beta1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -var _ = Describe("webhook inject", func() { - - Context("Inject", func() { - It("should return unexpected end of JSON input", func() { - var testClient client.Client - var cfg *config.Config - var controllerCfg *controllerCfg.ChaosControllerConfig - res := Inject(&admissionv1beta1.AdmissionRequest{}, testClient, cfg, controllerCfg, nil) - Expect(res.Result.Message).To(ContainSubstring("unexpected end of JSON input")) - }) - }) - - Context("checkInjectStatus", func() { - It("should return false", func() { - var metadata metav1.ObjectMeta - metadata.Annotations = make(map[string]string) - var cfg config.Config - res := checkInjectStatus(&metadata, &cfg) - Expect(res).To(Equal(false)) - }) - - It("should return true", func() { - var metadata metav1.ObjectMeta - metadata.Annotations = make(map[string]string) - metadata.Annotations["testNamespace/status"] = StatusInjected - var cfg config.Config - cfg.AnnotationNamespace = "testNamespace" - res := checkInjectStatus(&metadata, &cfg) - Expect(res).To(Equal(true)) - }) - }) - - Context("injectByPodRequired", func() { - It("should return false", func() { - var metadata metav1.ObjectMeta - metadata.Annotations = make(map[string]string) - var cfg config.Config - str, flag := injectByPodRequired(&metadata, &cfg) - Expect(str).To(Equal("")) - Expect(flag).To(Equal(false)) - }) - - It("should return false", func() { - var metadata metav1.ObjectMeta - metadata.Annotations = make(map[string]string) - metadata.Annotations["testNamespace/request"] = "test" - var cfg config.Config - cfg.AnnotationNamespace = "testNamespace" - str, flag := injectByPodRequired(&metadata, &cfg) - Expect(str).To(Equal("test")) - Expect(flag).To(Equal(true)) - }) - }) - - Context("injectRequired", func() { - It("should return ignore", func() { - var metadata metav1.ObjectMeta - metadata.Annotations = make(map[string]string) - metadata.Namespace = "kube-system" - var cli client.Client - var cfg config.Config - var controllerCfg controllerCfg.ChaosControllerConfig - str, flag := injectRequired(&metadata, cli, &cfg, &controllerCfg) - Expect(str).To(Equal("")) - Expect(flag).To(Equal(false)) - }) - - It("should return ignore", func() { - var metadata metav1.ObjectMeta - metadata.Annotations = make(map[string]string) - metadata.Annotations["testNamespace/status"] = StatusInjected - var cfg config.Config - var controllerCfg controllerCfg.ChaosControllerConfig - cfg.AnnotationNamespace = "testNamespace" - var cli client.Client - str, flag := injectRequired(&metadata, cli, &cfg, &controllerCfg) - Expect(str).To(Equal("")) - Expect(flag).To(Equal(false)) - }) - - It("should return ignore", func() { - var metadata metav1.ObjectMeta - metadata.Annotations = make(map[string]string) - metadata.Annotations["testNamespace/status"] = StatusInjected - var cfg config.Config - var controllerCfg controllerCfg.ChaosControllerConfig - cfg.AnnotationNamespace = "testNamespace" - var cli client.Client - str, flag := injectRequired(&metadata, cli, &cfg, &controllerCfg) - Expect(str).To(Equal("")) - Expect(flag).To(Equal(false)) - }) - - It("should return Pod annotation requesting sidecar config", func() { - var metadata metav1.ObjectMeta - metadata.Annotations = make(map[string]string) - metadata.Annotations["testNamespace/request"] = "test" - metadata.Namespace = "testNamespace" - var cfg config.Config - var controllerCfg controllerCfg.ChaosControllerConfig - cfg.AnnotationNamespace = "testNamespace" - str, flag := injectRequired(&metadata, k8sClient, &cfg, &controllerCfg) - Expect(str).To(Equal("test")) - Expect(flag).To(Equal(true)) - }) - - It("should return false", func() { - var metadata metav1.ObjectMeta - metadata.Annotations = make(map[string]string) - var cfg config.Config - var controllerCfg controllerCfg.ChaosControllerConfig - _, flag := injectRequired(&metadata, k8sClient, &cfg, &controllerCfg) - Expect(flag).To(Equal(false)) - }) - }) - - Context("injectByNamespaceRequired", func() { - It("should return nil and false", func() { - var metadata metav1.ObjectMeta - metadata.Annotations = make(map[string]string) - metadata.Namespace = "testNamespace" - var cfg config.Config - str, flag := injectByNamespaceRequired(&metadata, k8sClient, &cfg) - Expect(str).To(Equal("")) - Expect(flag).To(Equal(false)) - }) - }) - - Context("createPatch", func() { - It("should return nil and false", func() { - var pod corev1.Pod - var inj config.InjectionConfig - annotations := make(map[string]string) - _, err := createPatch(&pod, &inj, annotations) - Expect(err).To(BeNil()) - }) - }) - - Context("setCommands", func() { - It("should return", func() { - var target []corev1.Container = []corev1.Container{ - { - Name: "testContainerName", - }} - postStart := make(map[string]config.ExecAction) - patch := setCommands(target, postStart) - Expect(patch).To(BeNil()) - }) - - It("should return nil", func() { - var target []corev1.Container = []corev1.Container{ - { - Name: "testContainerName", - }} - postStart := make(map[string]config.ExecAction) - var ce config.ExecAction = config.ExecAction{ - Command: []string{"nil"}, - } - postStart["testContainerName"] = ce - patch := setCommands(target, postStart) - Expect(patch).ToNot(BeNil()) - }) - }) - - Context("setEnvironment", func() { - It("should return not nil", func() { - var target []corev1.Container = []corev1.Container{ - { - Name: "testContainerName", - }} - var addEnv []corev1.EnvVar = []corev1.EnvVar{ - { - Name: "testContainerName", - }} - patch := setEnvironment(target, addEnv) - Expect(patch).ToNot(BeNil()) - }) - - It("should return not nil", func() { - var Env []corev1.EnvVar = []corev1.EnvVar{ - { - Name: "_testContainerName_", - }} - var target []corev1.Container = []corev1.Container{ - { - Name: "testContainerName", - Env: Env, - }} - var addEnv []corev1.EnvVar = []corev1.EnvVar{ - { - Name: "testContainerName", - }} - patch := setEnvironment(target, addEnv) - Expect(patch).ToNot(BeNil()) - }) - - It("should return nil", func() { - var Env []corev1.EnvVar = []corev1.EnvVar{ - { - Name: "testContainerName", - }} - var target []corev1.Container = []corev1.Container{ - { - Name: "testContainerName", - Env: Env, - }} - var addEnv []corev1.EnvVar = []corev1.EnvVar{ - { - Name: "testContainerName", - }} - patch := setEnvironment(target, addEnv) - Expect(patch).To(BeNil()) - }) - }) - - Context("addContainers", func() { - It("should return not nil", func() { - var target []corev1.Container = []corev1.Container{ - { - Name: "testContainerName", - }} - var added []corev1.Container = []corev1.Container{ - { - Name: "testContainerName", - }} - basePath := "/test" - patch := addContainers(target, added, basePath) - Expect(patch).ToNot(BeNil()) - }) - - It("should return not nil", func() { - var target []corev1.Container = []corev1.Container{} - var added []corev1.Container = []corev1.Container{ - { - Name: "testContainerName", - }} - basePath := "/test" - patch := addContainers(target, added, basePath) - Expect(patch).ToNot(BeNil()) - }) - }) - - Context("addVolumes", func() { - It("should return not nil", func() { - var target []corev1.Volume = []corev1.Volume{ - { - Name: "test", - }} - var added []corev1.Volume = []corev1.Volume{ - { - Name: "test", - }} - basePath := "/test" - patch := addVolumes(target, added, basePath) - Expect(patch).ToNot(BeNil()) - }) - - It("should return not nil", func() { - var target []corev1.Volume = []corev1.Volume{} - var added []corev1.Volume = []corev1.Volume{ - { - Name: "test", - }} - basePath := "/test" - patch := addVolumes(target, added, basePath) - Expect(patch).ToNot(BeNil()) - }) - }) - - Context("setVolumeMounts", func() { - It("should return not nil", func() { - var vm []corev1.VolumeMount = []corev1.VolumeMount{ - { - Name: "test", - }} - var target []corev1.Container = []corev1.Container{ - { - Name: "test", - VolumeMounts: vm, - }} - var added []corev1.VolumeMount = []corev1.VolumeMount{ - { - Name: "test", - }} - basePath := "/test" - patch := setVolumeMounts(target, added, basePath) - Expect(patch).ToNot(BeNil()) - }) - }) - - Context("addHostAliases", func() { - It("should return not nil", func() { - var target []corev1.HostAlias = []corev1.HostAlias{ - { - IP: "testip", - }} - var added []corev1.HostAlias = []corev1.HostAlias{ - { - IP: "testip", - }} - basePath := "/test" - patch := addHostAliases(target, added, basePath) - Expect(patch).ToNot(BeNil()) - }) - - It("should return not nil", func() { - var target []corev1.HostAlias = []corev1.HostAlias{} - var added []corev1.HostAlias = []corev1.HostAlias{ - { - IP: "testip", - }} - basePath := "/test" - patch := addHostAliases(target, added, basePath) - Expect(patch).ToNot(BeNil()) - }) - }) - - Context("mergeEnvVars", func() { - It("should return not nil", func() { - var envs []corev1.EnvVar = []corev1.EnvVar{ - { - Name: "test", - }} - var containers []corev1.Container = []corev1.Container{ - { - Name: "test", - }} - mutatedContainers := mergeEnvVars(envs, containers) - Expect(mutatedContainers).ToNot(BeNil()) - }) - - It("should return not nil", func() { - var envs []corev1.EnvVar = []corev1.EnvVar{ - { - Name: "test", - }} - var env []corev1.EnvVar = []corev1.EnvVar{ - { - Name: "test", - }} - var containers []corev1.Container = []corev1.Container{ - { - Name: "test", - Env: env, - }} - mutatedContainers := mergeEnvVars(envs, containers) - Expect(mutatedContainers).ToNot(BeNil()) - }) - }) - - Context("mergeVolumeMounts", func() { - It("should return not nil", func() { - var volumeMounts []corev1.VolumeMount = []corev1.VolumeMount{ - { - Name: "test", - }} - var containers []corev1.Container = []corev1.Container{ - { - Name: "test", - }} - mutatedContainers := mergeVolumeMounts(volumeMounts, containers) - Expect(mutatedContainers).ToNot(BeNil()) - }) - - It("should return not nil", func() { - var volumeMounts []corev1.VolumeMount = []corev1.VolumeMount{ - { - Name: "test", - }} - var vm []corev1.VolumeMount = []corev1.VolumeMount{ - { - Name: "test", - }} - var containers []corev1.Container = []corev1.Container{ - { - Name: "test", - VolumeMounts: vm, - }} - mutatedContainers := mergeVolumeMounts(volumeMounts, containers) - Expect(mutatedContainers).ToNot(BeNil()) - }) - }) - - Context("updateAnnotations", func() { - It("should return not nil", func() { - target := make(map[string]string) - added := make(map[string]string) - added["testKey"] = "testValue" - patch := updateAnnotations(target, added) - Expect(patch).ToNot(BeNil()) - }) - - It("should return not nil", func() { - target := make(map[string]string) - added := make(map[string]string) - added["testKey"] = "testValue" - target["testKey"] = "testValue" - patch := updateAnnotations(target, added) - Expect(patch).ToNot(BeNil()) - }) - }) - - Context("potentialPodName", func() { - It("should return testName", func() { - var metadata metav1.ObjectMeta - metadata.Name = "testName" - name := potentialPodName(&metadata) - Expect(name).ToNot(BeNil()) - Expect(name).To(Equal("testName")) - }) - - It("should return (actual name not yet known)", func() { - var metadata metav1.ObjectMeta - metadata.GenerateName = "testName" - name := potentialPodName(&metadata) - Expect(name).ToNot(BeNil()) - Expect(name).To(ContainSubstring("(actual name not yet known)")) - }) - - It("should return nil", func() { - var metadata metav1.ObjectMeta - name := potentialPodName(&metadata) - Expect(name).To(Equal("")) - }) - }) -}) diff --git a/pkg/webhook/inject/setup_test.go b/pkg/webhook/inject/setup_test.go deleted file mode 100644 index b3b8b39cf6..0000000000 --- a/pkg/webhook/inject/setup_test.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package inject - -import ( - "os" - "path/filepath" - "testing" - "time" - - "github.com/onsi/gomega/gexec" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - - "k8s.io/client-go/kubernetes/scheme" - // +kubebuilder:scaffold:imports -) - -// These tests use Ginkgo (BDD-style Go testing framework). Refer to -// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. - -var k8sClient client.Client -var k8sManager ctrl.Manager -var testEnv *envtest.Environment - -func TestAPIs(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "webhook inject", - []Reporter{envtest.NewlineReporter{}}) -} - -var _ = BeforeSuite(func(done Done) { - logf.SetLogger(zap.LoggerTo(GinkgoWriter, true)) - - By("bootstrapping test environment") - t := true - if os.Getenv("TEST_USE_EXISTING_CLUSTER") == "true" { - testEnv = &envtest.Environment{ - UseExistingCluster: &t, - } - } else { - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, - } - } - - cfg, err := testEnv.Start() - Expect(err).ToNot(HaveOccurred()) - Expect(cfg).ToNot(BeNil()) - - err = scheme.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) - - err = v1alpha1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) - - // +kubebuilder:scaffold:scheme - - k8sManager, err = ctrl.NewManager(cfg, ctrl.Options{ - Scheme: scheme.Scheme, - MetricsBindAddress: "0", - }) - Expect(err).ToNot(HaveOccurred()) - - go func() { - err = k8sManager.Start(ctrl.SetupSignalHandler()) - Expect(err).ToNot(HaveOccurred()) - }() - - k8sClient = k8sManager.GetClient() - Expect(k8sClient).ToNot(BeNil()) - - close(done) -}, 60) - -var _ = AfterSuite(func() { - By("tearing down the test environment") - gexec.KillAndWait(5 * time.Second) - err := testEnv.Stop() - Expect(err).ToNot(HaveOccurred()) -}) diff --git a/pkg/webhook/validate_auth.go b/pkg/webhook/validate_auth.go new file mode 100644 index 0000000000..ab43917d29 --- /dev/null +++ b/pkg/webhook/validate_auth.go @@ -0,0 +1,174 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package webhook + +import ( + "context" + "fmt" + "net/http" + "strings" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + authv1 "k8s.io/api/authorization/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + authorizationv1 "k8s.io/client-go/kubernetes/typed/authorization/v1" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +var alwaysAllowedKind = []string{ + v1alpha1.KindAWSChaos, + v1alpha1.KindPodNetworkChaos, + v1alpha1.KindPodIOChaos, + v1alpha1.KindGCPChaos, + v1alpha1.KindPodHttpChaos, + v1alpha1.KindPhysicalMachine, + v1alpha1.KindStatusCheck, + v1alpha1.KindRemoteCluster, + + "WorkflowNode", +} + +// +kubebuilder:webhook:path=/validate-auth,mutating=false,failurePolicy=fail,groups=chaos-mesh.org,resources=*,verbs=create;update,versions=v1alpha1,name=vauth.kb.io + +// AuthValidator validates the authority +type AuthValidator struct { + enabled bool + authCli *authorizationv1.AuthorizationV1Client + + decoder *admission.Decoder + + clusterScoped bool + targetNamespace string + enableFilterNamespace bool + logger logr.Logger +} + +// NewAuthValidator returns a new AuthValidator +func NewAuthValidator(enabled bool, authCli *authorizationv1.AuthorizationV1Client, decoderScheme *runtime.Scheme, + clusterScoped bool, targetNamespace string, enableFilterNamespace bool, logger logr.Logger) *AuthValidator { + return &AuthValidator{ + enabled: enabled, + authCli: authCli, + decoder: admission.NewDecoder(decoderScheme), + clusterScoped: clusterScoped, + targetNamespace: targetNamespace, + enableFilterNamespace: enableFilterNamespace, + logger: logger, + } +} + +// AuthValidator admits a pod iff a specific annotation exists. +func (v *AuthValidator) Handle(ctx context.Context, req admission.Request) admission.Response { + if !v.enabled { + return admission.Allowed("") + } + + username := req.UserInfo.Username + groups := req.UserInfo.Groups + requestKind := req.Kind.Kind + + if contains(alwaysAllowedKind, requestKind) { + return admission.Allowed(fmt.Sprintf("skip the RBAC check for type %s", requestKind)) + } + + kind, ok := v1alpha1.AllKindsIncludeScheduleAndWorkflow()[requestKind] + if !ok { + err := errors.Wrapf(errInvalidValue, "kind %s is not support", requestKind) + return admission.Errored(http.StatusBadRequest, err) + } + chaos := kind.SpawnObject() + + err := v.decoder.Decode(req, chaos) + if err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + + requireClusterPrivileges, affectedNamespaces := affectedNamespaces(chaos) + + if requireClusterPrivileges { + allow, err := v.auth(username, groups, "", requestKind) + if err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + + if !allow { + return admission.Denied(fmt.Sprintf("%s is forbidden on cluster", username)) + } + v.logger.Info("user have the privileges on cluster, auth validate passed", "user", username, "groups", groups, "namespace", affectedNamespaces) + } else { + v.logger.Info("start validating user", "user", username, "groups", groups, "namespace", affectedNamespaces) + + for namespace := range affectedNamespaces { + allow, err := v.auth(username, groups, namespace, requestKind) + if err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + + if !allow { + return admission.Denied(fmt.Sprintf("%s is forbidden on namespace %s", username, namespace)) + } + } + + v.logger.Info("user have the privileges on namespace, auth validate passed", "user", username, "groups", groups, "namespace", affectedNamespaces) + } + + return admission.Allowed("") +} + +func (v *AuthValidator) auth(username string, groups []string, namespace string, chaosKind string) (bool, error) { + resourceName, err := v.resourceFor(chaosKind) + if err != nil { + return false, err + } + sar := authv1.SubjectAccessReview{ + Spec: authv1.SubjectAccessReviewSpec{ + ResourceAttributes: &authv1.ResourceAttributes{ + Namespace: namespace, + Verb: "create", + Group: "chaos-mesh.org", + Resource: resourceName, + }, + User: username, + Groups: groups, + }, + } + + // FIXME: get context from parameter + response, err := v.authCli.SubjectAccessReviews().Create(context.TODO(), &sar, metav1.CreateOptions{}) + if err != nil { + return false, err + } + + return response.Status.Allowed, nil +} + +func (v *AuthValidator) resourceFor(name string) (string, error) { + // TODO: we should use RESTMapper, but it relates to many dependencies + return strings.ToLower(name), nil +} + +func contains(arr []string, target string) bool { + for _, item := range arr { + if item == target { + return true + } + } + return false +} diff --git a/pkg/workflow/controllers/abort_node_reconciler.go b/pkg/workflow/controllers/abort_node_reconciler.go new file mode 100644 index 0000000000..d2f6d5a818 --- /dev/null +++ b/pkg/workflow/controllers/abort_node_reconciler.go @@ -0,0 +1,148 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controllers + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" +) + +type AbortNodeReconciler struct { + *ChildNodesFetcher + kubeClient client.Client + eventRecorder recorder.ChaosRecorder + logger logr.Logger +} + +func NewAbortNodeReconciler(kubeClient client.Client, eventRecorder recorder.ChaosRecorder, logger logr.Logger) *AbortNodeReconciler { + return &AbortNodeReconciler{ + ChildNodesFetcher: NewChildNodesFetcher(kubeClient, logger), + kubeClient: kubeClient, + eventRecorder: eventRecorder, + logger: logger, + } +} + +// Reconcile watches `WorkflowNodes`, if: +// 1. the abort condition is `False`, just return. +// 2. the abort condition is `True`, the node is not `TypeStatusCheck`, it will propagate abort condition to children nodes. +// 3. the abort condition is `True`, the node is `TypeStatusCheck`, it will add abort annotation to the parent workflow. +func (it *AbortNodeReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { + node := v1alpha1.WorkflowNode{} + err := it.kubeClient.Get(ctx, request.NamespacedName, &node) + if err != nil { + return reconcile.Result{}, client.IgnoreNotFound(err) + } + + if !ConditionEqualsTo(node.Status, v1alpha1.ConditionAborted, corev1.ConditionTrue) { + return reconcile.Result{}, nil + } + + if node.Spec.Type != v1alpha1.TypeStatusCheck { + // if this node is aborted, try propagating to children node + return reconcile.Result{}, it.propagateAbortToChildren(ctx, &node) + } + + updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { + if err := it.abortWorkflow(ctx, node); client.IgnoreNotFound(err) != nil { + return errors.Wrapf(err, "abort parent workflow") + } + return nil + }) + + return reconcile.Result{}, client.IgnoreNotFound(updateError) +} + +func (it *AbortNodeReconciler) propagateAbortToChildren(ctx context.Context, parent *v1alpha1.WorkflowNode) error { + switch parent.Spec.Type { + case v1alpha1.TypeSerial, v1alpha1.TypeParallel, v1alpha1.TypeTask: + activeChildNodes, _, err := it.ChildNodesFetcher.fetchChildNodes(ctx, *parent) + if err != nil { + return errors.Wrap(err, "fetch children nodes") + } + for _, childNode := range activeChildNodes { + childNode := childNode + + if WorkflowNodeFinished(childNode.Status) { + it.logger.Info("child node already finished, skip for propagate abort", "node", fmt.Sprintf("%s/%s", childNode.Namespace, childNode.Name)) + continue + } + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + nodeNeedUpdate := v1alpha1.WorkflowNode{} + err := it.kubeClient.Get(ctx, types.NamespacedName{ + Namespace: childNode.Namespace, + Name: childNode.Name, + }, &nodeNeedUpdate) + if err != nil { + return errors.Wrap(err, "get child workflow node") + } + if ConditionEqualsTo(nodeNeedUpdate.Status, v1alpha1.ConditionAborted, corev1.ConditionTrue) { + it.logger.Info("omit propagate abort to children, child already aborted", + "node", fmt.Sprintf("%s/%s", nodeNeedUpdate.Namespace, nodeNeedUpdate.Name), + "parent node", fmt.Sprintf("%s/%s", parent.Namespace, parent.Name), + ) + return nil + } + SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionAborted, + Status: corev1.ConditionTrue, + Reason: v1alpha1.ParentNodeAborted, + }) + it.eventRecorder.Event(&nodeNeedUpdate, recorder.ParentNodeAborted{ParentNodeName: parent.Name}) + return it.kubeClient.Status().Update(ctx, &nodeNeedUpdate) + }) + if err != nil { + return errors.Wrap(err, "update status of child workflow node") + } + it.logger.Info("propagate abort for child node", + "child node", fmt.Sprintf("%s/%s", childNode.Namespace, childNode.Name), + "parent node", fmt.Sprintf("%s/%s", parent.Namespace, parent.Name), + ) + } + return nil + default: + it.logger.V(4).Info("no need to propagate with this type of workflow node", "type", parent.Spec.Type) + return nil + } +} + +func (it *AbortNodeReconciler) abortWorkflow(ctx context.Context, node v1alpha1.WorkflowNode) error { + parentWorkflow, err := getParentWorkflow(ctx, it.kubeClient, node) + if err != nil { + return errors.WithStack(err) + } + if WorkflowAborted(*parentWorkflow) { + return nil + } + + it.logger.Info("add abort annotation to parent workflow", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "workflow", fmt.Sprintf("%s/%s", parentWorkflow.Namespace, parentWorkflow.Name)) + parentWorkflow.Annotations[v1alpha1.WorkflowAnnotationAbort] = "true" + return it.kubeClient.Update(ctx, parentWorkflow) +} diff --git a/pkg/workflow/controllers/abort_workflow_reconciler.go b/pkg/workflow/controllers/abort_workflow_reconciler.go new file mode 100644 index 0000000000..479c68d617 --- /dev/null +++ b/pkg/workflow/controllers/abort_workflow_reconciler.go @@ -0,0 +1,99 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controllers + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" +) + +type AbortWorkflowReconciler struct { + *ChildNodesFetcher + kubeClient client.Client + eventRecorder recorder.ChaosRecorder + logger logr.Logger +} + +func NewAbortWorkflowReconciler(kubeClient client.Client, eventRecorder recorder.ChaosRecorder, logger logr.Logger) *AbortWorkflowReconciler { + return &AbortWorkflowReconciler{ + ChildNodesFetcher: NewChildNodesFetcher(kubeClient, logger), + kubeClient: kubeClient, + eventRecorder: eventRecorder, + logger: logger, + } +} + +// Reconcile watches `Workflows`, if the workflow has the abort annotation, +// it will set the abort condition of the `entry node` to `True`. +func (it *AbortWorkflowReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { + workflow := v1alpha1.Workflow{} + err := it.kubeClient.Get(ctx, request.NamespacedName, &workflow) + if err != nil { + return reconcile.Result{}, client.IgnoreNotFound(err) + } + + updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { + workflowNeedUpdate := v1alpha1.Workflow{} + err := it.kubeClient.Get(ctx, request.NamespacedName, &workflowNeedUpdate) + if err != nil { + return errors.Wrapf(err, "get workflow") + } + + entryNodes, err := fetchEntryNode(ctx, it.kubeClient, workflowNeedUpdate) + if err != nil { + return errors.Wrapf(err, "fetch entry nodes of workflow") + } + + if len(entryNodes) == 0 { + it.logger.Info("omit set abort condition, workflow has no entry node", "key", request.NamespacedName) + return nil + } + if len(entryNodes) > 1 { + it.logger.Info("there are more than 1 entry nodes of workflow", "key", request.NamespacedName) + } + + entryNode := entryNodes[0] + if WorkflowAborted(workflowNeedUpdate) { + if !ConditionEqualsTo(entryNode.Status, v1alpha1.ConditionAborted, corev1.ConditionTrue) { + it.eventRecorder.Event(&entryNode, recorder.WorkflowAborted{WorkflowName: workflow.Name}) + } + SetCondition(&entryNode.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionAborted, + Status: corev1.ConditionTrue, + Reason: v1alpha1.WorkflowAborted, + }) + } else { + SetCondition(&entryNode.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionAborted, + Status: corev1.ConditionFalse, + Reason: "", + }) + } + + return client.IgnoreNotFound(it.kubeClient.Status().Update(ctx, &entryNode)) + }) + + return reconcile.Result{}, client.IgnoreNotFound(updateError) +} diff --git a/pkg/workflow/controllers/accomplish_watcher.go b/pkg/workflow/controllers/accomplish_watcher.go deleted file mode 100644 index a8b280fe10..0000000000 --- a/pkg/workflow/controllers/accomplish_watcher.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package controllers - -import ( - "context" - "reflect" - - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/record" - "k8s.io/client-go/util/retry" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -type AccomplishWatcher struct { - kubeClient client.Client - eventRecorder record.EventRecorder - logger logr.Logger -} - -func NewAccomplishWatcher(kubeClient client.Client, eventRecorder record.EventRecorder, logger logr.Logger) *AccomplishWatcher { - return &AccomplishWatcher{kubeClient: kubeClient, eventRecorder: eventRecorder, logger: logger} -} - -func (it *AccomplishWatcher) Reconcile(request reconcile.Request) (reconcile.Result, error) { - ctx := context.TODO() - - node := v1alpha1.WorkflowNode{} - err := it.kubeClient.Get(ctx, request.NamespacedName, &node) - if err != nil { - return reconcile.Result{}, client.IgnoreNotFound(err) - } - - if ConditionEqualsTo(node.Status, v1alpha1.ConditionAccomplished, corev1.ConditionTrue) || - ConditionEqualsTo(node.Status, v1alpha1.ConditionDeadlineExceed, corev1.ConditionTrue) { - owners := node.OwnerReferences - // NOOP - if len(owners) == 0 { - it.logger.V(1).Info("dangling node has no owner", "node", request.NamespacedName) - return reconcile.Result{}, nil - } - - // unexpected situation - if len(owners) > 1 { - it.logger.V(1).Info("node has more than one owner, it will not take any operates", "node", request.NamespacedName, "owners", owners) - return reconcile.Result{}, nil - } - - owner := owners[0] - it.logger.V(4).Info("fetch node's owner", "node", request.NamespacedName, "owner", owner) - if owner.Kind == GetKindOf(&v1alpha1.WorkflowNode{}) { - parentNode := v1alpha1.WorkflowNode{} - - err := it.kubeClient.Get(ctx, types.NamespacedName{ - Namespace: request.Namespace, - Name: owner.Name, - }, &parentNode) - if err != nil { - return reconcile.Result{}, err - } - if parentNode.Spec.Type == v1alpha1.TypeSerial { - err = it.updateParentSerialNode(ctx, node, parentNode) - return reconcile.Result{}, err - } - it.logger.Info("unsupported owner node type", "node type", parentNode.Spec.Type) - } else if owner.Kind == GetKindOf(&v1alpha1.Workflow{}) { - // TODO: update the status of workflow - it.logger.Info("unsupported update for workflow", "kind", owner.Kind) - } else { - it.logger.Info("unsupported owner type", "kind", owner.Kind) - } - } - return reconcile.Result{}, nil -} - -func (it *AccomplishWatcher) updateParentSerialNode(ctx context.Context, childNode, parentNode v1alpha1.WorkflowNode) error { - - updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { - nodeNeedUpdate := v1alpha1.WorkflowNode{} - err := it.kubeClient.Get(ctx, types.NamespacedName{ - Namespace: parentNode.Namespace, - Name: parentNode.Name, - }, &nodeNeedUpdate) - - if err != nil { - return client.IgnoreNotFound(err) - } - - // filter out accomplished node - var newActiveChildren []corev1.LocalObjectReference - - for _, item := range nodeNeedUpdate.Status.ActiveChildren { - item := item - if item.Name == childNode.Name { - continue - } - newActiveChildren = append(newActiveChildren, item) - } - - nodeNeedUpdate.Status.ActiveChildren = newActiveChildren - - if !childrenContains(nodeNeedUpdate.Status.FinishedChildren, childNode.Name) { - nodeNeedUpdate.Status.FinishedChildren = append(nodeNeedUpdate.Status.FinishedChildren, corev1.LocalObjectReference{Name: childNode.Name}) - } - return it.kubeClient.Update(ctx, &nodeNeedUpdate) - }) - - return updateError -} - -func childrenContains(list []corev1.LocalObjectReference, name string) bool { - for _, item := range list { - if item.Name == name { - return true - } - } - return false -} - -func GetKindOf(obj runtime.Object) string { - t := reflect.TypeOf(obj) - if t.Kind() != reflect.Ptr { - panic("All types must be pointers to structs.") - } - t = t.Elem() - return t.Name() -} diff --git a/pkg/workflow/controllers/bootstrap.go b/pkg/workflow/controllers/bootstrap.go index 123d1b5232..62cc4043b7 100644 --- a/pkg/workflow/controllers/bootstrap.go +++ b/pkg/workflow/controllers/bootstrap.go @@ -4,25 +4,33 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package controllers import ( "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/config" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" ) -func BootstrapWorkflowControllers(mgr manager.Manager, logger logr.Logger) error { +func BootstrapWorkflowControllers(mgr manager.Manager, logger logr.Logger, recorderBuilder *recorder.RecorderBuilder) error { + if !config.ShouldSpawnController("workflow") { + return nil + } noCacheClient, err := client.New(mgr.GetConfig(), client.Options{ Scheme: mgr.GetScheme(), @@ -33,11 +41,12 @@ func BootstrapWorkflowControllers(mgr manager.Manager, logger logr.Logger) error } err = ctrl.NewControllerManagedBy(mgr). For(&v1alpha1.Workflow{}). + Owns(&v1alpha1.WorkflowNode{}). Named("workflow-entry-reconciler"). Complete( NewWorkflowEntryReconciler( mgr.GetClient(), - mgr.GetEventRecorderFor("workflow-entry-reconciler"), + recorderBuilder.Build("workflow-entry-reconciler"), logger.WithName("workflow-entry-reconciler"), ), ) @@ -49,37 +58,41 @@ func BootstrapWorkflowControllers(mgr manager.Manager, logger logr.Logger) error // TODO: maybe we could use select with labelSelector as instead err = ctrl.NewControllerManagedBy(mgr). For(&v1alpha1.WorkflowNode{}). + Owns(&v1alpha1.WorkflowNode{}). Named("workflow-serial-node-reconciler"). Complete( NewSerialNodeReconciler( noCacheClient, - mgr.GetEventRecorderFor("workflow-serial-node-reconciler"), + recorderBuilder.Build("workflow-serial-node-reconciler"), logger.WithName("workflow-serial-node-reconciler"), ), ) if err != nil { return err } + err = ctrl.NewControllerManagedBy(mgr). For(&v1alpha1.WorkflowNode{}). - Named("workflow-accomplish-watcher"). + Owns(&v1alpha1.WorkflowNode{}). + Named("workflow-parallel-node-reconciler"). Complete( - NewAccomplishWatcher( - mgr.GetClient(), - mgr.GetEventRecorderFor("workflow-accomplish-watcher"), - logger.WithName("workflow-accomplish-watcher"), + NewParallelNodeReconciler( + noCacheClient, + recorderBuilder.Build("workflow-parallel-node-reconciler"), + logger.WithName("workflow-parallel-node-reconciler"), ), ) if err != nil { return err } + err = ctrl.NewControllerManagedBy(mgr). For(&v1alpha1.WorkflowNode{}). Named("workflow-deadline-reconciler"). Complete( NewDeadlineReconciler( mgr.GetClient(), - mgr.GetEventRecorderFor("workflow-deadline-reconciler"), + recorderBuilder.Build("workflow-deadline-reconciler"), logger.WithName("workflow-deadline-reconciler"), ), ) @@ -93,12 +106,61 @@ func BootstrapWorkflowControllers(mgr manager.Manager, logger logr.Logger) error Complete( NewChaosNodeReconciler( mgr.GetClient(), - mgr.GetEventRecorderFor("workflow-chaos-node-reconciler"), + recorderBuilder.Build("workflow-chaos-node-reconciler"), logger.WithName("workflow-chaos-node-reconciler"), ), ) if err != nil { return err } - return nil + err = ctrl.NewControllerManagedBy(mgr). + For(&v1alpha1.WorkflowNode{}). + Owns(&v1alpha1.WorkflowNode{}). + Owns(&corev1.Pod{}). + Named("workflow-task-reconciler"). + Complete(NewTaskReconciler( + noCacheClient, + mgr.GetConfig(), + recorderBuilder.Build("workflow-task-reconciler"), + logger.WithName("workflow-task-reconciler"), + )) + if err != nil { + return err + } + + err = ctrl.NewControllerManagedBy(mgr). + For(&v1alpha1.WorkflowNode{}). + Owns(&v1alpha1.WorkflowNode{}). + Owns(&v1alpha1.StatusCheck{}). + Named("workflow-statuscheck-reconciler"). + Complete(NewStatusCheckReconciler( + noCacheClient, + recorderBuilder.Build("workflow-statuscheck-reconciler"), + logger.WithName("workflow-statuscheck-reconciler"), + )) + if err != nil { + return err + } + + err = ctrl.NewControllerManagedBy(mgr). + For(&v1alpha1.WorkflowNode{}). + Named("workflow-abort-node-reconciler"). + Complete(NewAbortNodeReconciler( + noCacheClient, + recorderBuilder.Build("workflow-abort-node-reconciler"), + logger.WithName("workflow-abort-node-reconciler"), + )) + if err != nil { + return err + } + + err = ctrl.NewControllerManagedBy(mgr). + For(&v1alpha1.Workflow{}). + Named("workflow-abort-workflow-reconciler"). + Complete(NewAbortWorkflowReconciler( + noCacheClient, + recorderBuilder.Build("workflow-abort-workflow-reconciler"), + logger.WithName("workflow-abort-workflow-reconciler"), + )) + return err } diff --git a/pkg/workflow/controllers/chaos_node_reconciler.go b/pkg/workflow/controllers/chaos_node_reconciler.go index a7fbacdfc1..ac457f26c1 100644 --- a/pkg/workflow/controllers/chaos_node_reconciler.go +++ b/pkg/workflow/controllers/chaos_node_reconciler.go @@ -4,44 +4,55 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package controllers import ( "context" "fmt" + "sort" + "time" "github.com/go-logr/logr" + "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/record" "k8s.io/client-go/util/retry" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" ) type ChaosNodeReconciler struct { kubeClient client.Client - eventRecorder record.EventRecorder + eventRecorder recorder.ChaosRecorder logger logr.Logger } -func NewChaosNodeReconciler(kubeClient client.Client, eventRecorder record.EventRecorder, logger logr.Logger) *ChaosNodeReconciler { +func NewChaosNodeReconciler(kubeClient client.Client, eventRecorder recorder.ChaosRecorder, logger logr.Logger) *ChaosNodeReconciler { return &ChaosNodeReconciler{kubeClient: kubeClient, eventRecorder: eventRecorder, logger: logger} } -func (it *ChaosNodeReconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { - ctx := context.TODO() +func (it *ChaosNodeReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { + + startTime := time.Now() + defer func() { + it.logger.V(4).Info("Finished syncing for chaos node", + "node", request.NamespacedName, + "duration", time.Since(startTime), + ) + }() + node := v1alpha1.WorkflowNode{} err := it.kubeClient.Get(ctx, request.NamespacedName, &node) @@ -49,33 +60,253 @@ func (it *ChaosNodeReconciler) Reconcile(request reconcile.Request) (reconcile.R return reconcile.Result{}, client.IgnoreNotFound(err) } - if !v1alpha1.IsChoasTemplateType(node.Spec.Type) { + if !v1alpha1.IsChaosTemplateType(node.Spec.Type) { return reconcile.Result{}, nil } - if ConditionEqualsTo(node.Status, v1alpha1.ConditionDeadlineExceed, corev1.ConditionTrue) { - err := it.recoverChaos(ctx, node) - return reconcile.Result{}, err + it.logger.V(4).Info("resolve chaos node", "node", request) + + if node.Spec.Type == v1alpha1.TypeSchedule { + err := it.syncSchedule(ctx, node) + if err != nil { + return reconcile.Result{}, err + } + } else { + err = it.syncChaosResources(ctx, node) + if err != nil { + return reconcile.Result{}, err + } + } + + updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { + nodeNeedUpdate := v1alpha1.WorkflowNode{} + err := it.kubeClient.Get(ctx, request.NamespacedName, &nodeNeedUpdate) + if err != nil { + return client.IgnoreNotFound(err) + } + + if nodeNeedUpdate.Spec.Type == v1alpha1.TypeSchedule { + // sync status with schedule + scheduleList, err := it.fetchChildrenSchedule(ctx, nodeNeedUpdate) + if err != nil { + return client.IgnoreNotFound(err) + } + if len(scheduleList) > 1 { + it.logger.Info("the number of schedule custom resource affected by chaos node is more than 1", + "chaos node", fmt.Sprintf("%s/%s", nodeNeedUpdate.Namespace, nodeNeedUpdate.Name), + "schedule custom resources", scheduleList, + ) + } + if len(scheduleList) > 0 { + scheduleObject := scheduleList[0] + group := scheduleObject.GetObjectKind().GroupVersionKind().Group + chaosRef := corev1.TypedLocalObjectReference{ + APIGroup: &group, + Kind: scheduleObject.GetObjectKind().GroupVersionKind().Kind, + Name: scheduleObject.GetName(), + } + nodeNeedUpdate.Status.ChaosResource = &chaosRef + SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionChaosInjected, + Status: corev1.ConditionTrue, + Reason: v1alpha1.ChaosCRCreated, + }) + } else { + nodeNeedUpdate.Status.ChaosResource = nil + SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionChaosInjected, + Status: corev1.ConditionFalse, + Reason: v1alpha1.ChaosCRNotExists, + }) + } + + return client.IgnoreNotFound(it.kubeClient.Status().Update(ctx, &nodeNeedUpdate)) + } + + // sync status with chaos CustomResource + chaosList, err := it.fetchChildrenChaosCustomResource(ctx, nodeNeedUpdate) + if err != nil { + return client.IgnoreNotFound(err) + } + if len(chaosList) > 1 { + it.logger.Info("the number of chaos custom resource affected by chaos node is more than 1", + "chaos node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "chaos custom resources", chaosList, + ) + } + + if len(chaosList) > 0 { + chaosObject := chaosList[0] + group := chaosObject.GetObjectKind().GroupVersionKind().Group + chaosRef := corev1.TypedLocalObjectReference{ + APIGroup: &group, + Kind: chaosObject.GetObjectKind().GroupVersionKind().Kind, + Name: chaosObject.GetName(), + } + nodeNeedUpdate.Status.ChaosResource = &chaosRef + SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionChaosInjected, + Status: corev1.ConditionTrue, + Reason: v1alpha1.ChaosCRCreated, + }) + } else { + nodeNeedUpdate.Status.ChaosResource = nil + SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionChaosInjected, + Status: corev1.ConditionFalse, + Reason: v1alpha1.ChaosCRNotExists, + }) + } + + return client.IgnoreNotFound(it.kubeClient.Status().Update(ctx, &nodeNeedUpdate)) + }) + + return reconcile.Result{}, updateError +} + +func (it *ChaosNodeReconciler) syncSchedule(ctx context.Context, node v1alpha1.WorkflowNode) error { + scheduleList, err := it.fetchChildrenSchedule(ctx, node) + if err != nil { + return err + } + if WorkflowNodeFinished(node.Status) { + // make the number of schedule to 0 + for _, item := range scheduleList { + item := item + err := it.kubeClient.Delete(ctx, &item) + if client.IgnoreNotFound(err) != nil { + it.logger.Error(err, "failed to delete schedule CR for workflow chaos node", + "namespace", node.Namespace, + "chaos node", node.Name, + "schedule CR name", item.GetName(), + ) + it.eventRecorder.Event(&node, recorder.ChaosCustomResourceDeleteFailed{ + Name: item.GetName(), + Kind: item.GetObjectKind().GroupVersionKind().Kind, + }) + } else { + it.eventRecorder.Event(&node, recorder.ChaosCustomResourceDeleted{ + Name: item.GetName(), + Kind: item.GetObjectKind().GroupVersionKind().Kind, + }) + } + } + return nil + } + if len(scheduleList) == 0 { + return it.createSchedule(ctx, node) + } else if len(scheduleList) > 1 { + // need cleanup + + var scheduleCrToRemove []string + for _, item := range scheduleList[1:] { + scheduleCrToRemove = append(scheduleCrToRemove, item.GetName()) + } + + it.logger.Info("removing duplicated schedule custom resource", + "chaos node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "schedule cr to remove", scheduleCrToRemove, + ) + + for _, item := range scheduleList[1:] { + // best efforts deletion + item := item + err := it.kubeClient.Delete(ctx, &item) + if client.IgnoreNotFound(err) != nil { + it.logger.Error(err, "failed to delete schedule CR for workflow chaos node", + "namespace", node.Namespace, + "chaos node", node.Name, + "schedule CR name", item.GetName(), + ) + } + } + } else { + it.logger.V(4).Info("do not need spawn or remove schedule CR") + } + return nil + +} + +func (it *ChaosNodeReconciler) syncChaosResources(ctx context.Context, node v1alpha1.WorkflowNode) error { + + chaosList, err := it.fetchChildrenChaosCustomResource(ctx, node) + if err != nil { + return err + } + + if WorkflowNodeFinished(node.Status) { + // make the number of chaos resource to 0 + for _, item := range chaosList { + // best efforts deletion + item := item + // TODO: it should not be delete directly with the new implementation of *Chaos controller in branch nirvana + err := it.kubeClient.Delete(ctx, item) + if client.IgnoreNotFound(err) != nil { + it.logger.Error(err, "failed to delete chaos CR for workflow chaos node", + "namespace", node.Namespace, + "chaos node", node.Name, + "chaos CR name", item.GetName(), + ) + it.eventRecorder.Event(&node, recorder.ChaosCustomResourceDeleteFailed{ + Name: item.GetName(), + Kind: item.GetObjectKind().GroupVersionKind().Kind, + }) + } else { + it.eventRecorder.Event(&node, recorder.ChaosCustomResourceDeleted{ + Name: item.GetName(), + Kind: item.GetObjectKind().GroupVersionKind().Kind, + }) + } + } + return nil } + // make the number of chaos resource to 1 + if len(chaosList) == 0 { + return it.createChaos(ctx, node) + } else if len(chaosList) > 1 { - if !ConditionEqualsTo(node.Status, v1alpha1.ConditionChaosInjected, corev1.ConditionTrue) { - err = it.injectChaos(ctx, node) - return reconcile.Result{}, err + var chaosCrToRemove []string + for _, item := range chaosList[1:] { + chaosCrToRemove = append(chaosCrToRemove, item.GetName()) + } + + it.logger.Info("removing duplicated chaos custom resource", + "chaos node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "chaos cr to remove", chaosCrToRemove, + ) + + for _, item := range chaosList[1:] { + // best efforts deletion + item := item + err := it.kubeClient.Delete(ctx, item) + if client.IgnoreNotFound(err) != nil { + it.logger.Error(err, "failed to delete chaos CR for workflow chaos node", + "namespace", node.Namespace, + "chaos node", node.Name, + "chaos CR name", item.GetName(), + ) + } + } + } else { + it.logger.V(4).Info("do not need spawn or remove chaos CR") } - return reconcile.Result{}, nil + // TODO: also respawn the chaos resource if Spec changed in workflow + + return nil } -func (it *ChaosNodeReconciler) injectChaos(ctx context.Context, node v1alpha1.WorkflowNode) error { +// inject Chaos will create one instance of chaos CR +func (it *ChaosNodeReconciler) createChaos(ctx context.Context, node v1alpha1.WorkflowNode) error { - chaosObject, meta, err := node.Spec.EmbedChaos.SpawnNewObject(node.Spec.Type) + chaosObject, err := node.Spec.EmbedChaos.SpawnNewObject(node.Spec.Type) if err != nil { return err } - meta.SetGenerateName(fmt.Sprintf("%s-", node.Name)) - meta.SetNamespace(node.Namespace) - meta.SetOwnerReferences(append(meta.GetOwnerReferences(), metav1.OwnerReference{ + chaosObject.SetGenerateName(fmt.Sprintf("%s-", node.Name)) + chaosObject.SetNamespace(node.Namespace) + chaosObject.SetOwnerReferences(append(chaosObject.GetOwnerReferences(), metav1.OwnerReference{ APIVersion: node.APIVersion, Kind: node.Kind, Name: node.Name, @@ -83,91 +314,141 @@ func (it *ChaosNodeReconciler) injectChaos(ctx context.Context, node v1alpha1.Wo Controller: &isController, BlockOwnerDeletion: &blockOwnerDeletion, })) + chaosObject.SetLabels(map[string]string{ + v1alpha1.LabelControlledBy: node.Name, + v1alpha1.LabelWorkflow: node.Spec.WorkflowName, + }) err = it.kubeClient.Create(ctx, chaosObject) if err != nil { - it.eventRecorder.Event(&node, corev1.EventTypeWarning, v1alpha1.ChaosCRCreateFailed, "Failed to create chaos CR") + it.eventRecorder.Event(&node, recorder.ChaosCustomResourceCreateFailed{}) it.logger.Error(err, "failed to create chaos") return nil } - it.logger.Info("chaos object created", "namespace", meta.GetNamespace(), "name", meta.GetName()) - - it.eventRecorder.Event(&node, corev1.EventTypeNormal, v1alpha1.ChaosCRCreated, fmt.Sprintf("Chaos CR %s/%s created", meta.GetNamespace(), meta.GetName())) + it.logger.Info("chaos object created", "namespace", chaosObject.GetNamespace(), "name", chaosObject.GetName(), "parent node", node) + it.eventRecorder.Event(&node, recorder.ChaosCustomResourceCreated{ + Name: chaosObject.GetName(), + Kind: chaosObject.GetObjectKind().GroupVersionKind().Kind, + }) + return nil +} - group := chaosObject.GetObjectKind().GroupVersionKind().Group - chaosRef := corev1.TypedLocalObjectReference{ - APIGroup: &group, - Kind: chaosObject.GetObjectKind().GroupVersionKind().Kind, - Name: meta.GetName(), +func (it *ChaosNodeReconciler) fetchChildrenChaosCustomResource(ctx context.Context, node v1alpha1.WorkflowNode) ([]v1alpha1.GenericChaos, error) { + genericChaosList, err := node.Spec.EmbedChaos.SpawnNewList(node.Spec.Type) + if err != nil { + return nil, err + } + controlledByThisNode, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{ + MatchLabels: map[string]string{ + v1alpha1.LabelControlledBy: node.Name, + }, + }) + if err != nil { + it.logger.Error(err, "failed to build label selector with filtering children workflow node controlled by current node", + "current node", fmt.Sprintf("%s/%s", node.Namespace, node.Name)) + return nil, err } - updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { - nodeNeedUpdate := v1alpha1.WorkflowNode{} - err := it.kubeClient.Get(ctx, types.NamespacedName{ - Namespace: node.Namespace, - Name: node.Name, - }, &nodeNeedUpdate) - if err != nil { - return client.IgnoreNotFound(err) - } - nodeNeedUpdate.Status.ChaosResource = &chaosRef - - // TODO: this condition should be set by observation - SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ - Type: v1alpha1.ConditionChaosInjected, - Status: corev1.ConditionTrue, - Reason: v1alpha1.ChaosCRCreated, - }) - - return it.kubeClient.Update(ctx, &nodeNeedUpdate) - + err = it.kubeClient.List(ctx, genericChaosList, &client.ListOptions{ + LabelSelector: controlledByThisNode, }) - return updateError + if err != nil { + return nil, err + } + + var sorted SortGenericChaosByCreationTimestamp = genericChaosList.GetItems() + sort.Sort(sorted) + return sorted, err } -func (it *ChaosNodeReconciler) recoverChaos(ctx context.Context, node v1alpha1.WorkflowNode) error { - if node.Status.ChaosResource == nil { - return nil +func (it ChaosNodeReconciler) createSchedule(ctx context.Context, node v1alpha1.WorkflowNode) error { + if node.Spec.Schedule == nil { + return errors.New("invalid workfow node, the spec of schedule is nil") } - - var err error - chaosObject, err := v1alpha1.FetchChaosByTemplateType(node.Spec.Type) + scheduleToCreate := v1alpha1.Schedule{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: node.Namespace, + GenerateName: fmt.Sprintf("%s-", node.Name), + Labels: map[string]string{ + v1alpha1.LabelControlledBy: node.Name, + v1alpha1.LabelWorkflow: node.Spec.WorkflowName, + }, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: node.APIVersion, + Kind: node.Kind, + Name: node.Name, + UID: node.UID, + Controller: &isController, + BlockOwnerDeletion: &blockOwnerDeletion, + }, + }, + }, + Spec: *node.Spec.Schedule, + } + err := it.kubeClient.Create(ctx, &scheduleToCreate) if err != nil { - return err + it.eventRecorder.Event(&node, recorder.ChaosCustomResourceCreateFailed{}) + it.logger.Error(err, "failed to create schedule CR") + return nil } + it.logger.Info("schedule CR created", "namespace", scheduleToCreate.GetNamespace(), "name", scheduleToCreate.GetName()) + it.eventRecorder.Event(&node, recorder.ChaosCustomResourceCreated{ + Name: scheduleToCreate.GetName(), + Kind: scheduleToCreate.GetObjectKind().GroupVersionKind().Kind, + }) + return nil - err = it.kubeClient.Get(ctx, - types.NamespacedName{Namespace: node.Namespace, Name: node.Status.ChaosResource.Name}, - chaosObject) +} - if apierrors.IsNotFound(err) { - it.logger.V(4).Info("target chaos not exist", "namespace", node.Namespace, "name", node.Status.ChaosResource.Name, "chaos kind", node.Status.ChaosResource.Kind) - return nil +func (it *ChaosNodeReconciler) fetchChildrenSchedule(ctx context.Context, node v1alpha1.WorkflowNode) ([]v1alpha1.Schedule, error) { + var scheduleList v1alpha1.ScheduleList + controlledByThisNode, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{ + MatchLabels: map[string]string{ + v1alpha1.LabelControlledBy: node.Name, + }, + }) + if err != nil { + it.logger.Error(err, "failed to build label selector with filtering children workflow node controlled by current node", + "current node", fmt.Sprintf("%s/%s", node.Namespace, node.Name)) + return nil, err } + err = it.kubeClient.List(ctx, &scheduleList, &client.ListOptions{ + LabelSelector: controlledByThisNode, + }) if err != nil { - return err + return nil, err } + var sorted SortScheduleByCreationTimestamp = scheduleList.Items + sort.Sort(sorted) + return sorted, err +} - err = it.kubeClient.Delete(ctx, chaosObject) +type SortGenericChaosByCreationTimestamp []v1alpha1.GenericChaos - if client.IgnoreNotFound(err) != nil { - return err - } +func (it SortGenericChaosByCreationTimestamp) Len() int { + return len(it) +} - err = retry.RetryOnConflict(retry.DefaultRetry, func() error { - nodeNeedUpdate := v1alpha1.WorkflowNode{} - err := it.kubeClient.Get(ctx, types.NamespacedName{ - Namespace: node.Namespace, - Name: node.Name, - }, &nodeNeedUpdate) - if err != nil { - return client.IgnoreNotFound(err) - } +func (it SortGenericChaosByCreationTimestamp) Less(i, j int) bool { + return it[j].GetCreationTimestamp().After(it[i].GetCreationTimestamp().Time) +} - nodeNeedUpdate.Status.ChaosResource = nil - err = it.kubeClient.Update(ctx, &nodeNeedUpdate) - return client.IgnoreNotFound(err) - }) +func (it SortGenericChaosByCreationTimestamp) Swap(i, j int) { + it[i], it[j] = it[j], it[i] +} + +type SortScheduleByCreationTimestamp []v1alpha1.Schedule + +func (it SortScheduleByCreationTimestamp) Len() int { + return len(it) +} + +func (it SortScheduleByCreationTimestamp) Less(i, j int) bool { + return it[j].GetCreationTimestamp().After(it[i].GetCreationTimestamp().Time) +} - return err +func (it SortScheduleByCreationTimestamp) Swap(i, j int) { + it[i], it[j] = it[j], it[i] } diff --git a/pkg/workflow/controllers/chaos_node_test.go b/pkg/workflow/controllers/chaos_node_test.go new file mode 100644 index 0000000000..fa704ffaa5 --- /dev/null +++ b/pkg/workflow/controllers/chaos_node_test.go @@ -0,0 +1,165 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controllers + +import ( + "context" + "fmt" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +// integration tests +var _ = Describe("Workflow", func() { + var ns string + BeforeEach(func() { + ctx := context.TODO() + newNs := corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "chaos-mesh-", + }, + Spec: corev1.NamespaceSpec{}, + } + Expect(kubeClient.Create(ctx, &newNs)).To(Succeed()) + ns = newNs.Name + By(fmt.Sprintf("create new namespace %s", ns)) + }) + + AfterEach(func() { + ctx := context.TODO() + nsToDelete := corev1.Namespace{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Name: ns}, &nsToDelete)).To(Succeed()) + Expect(kubeClient.Delete(ctx, &nsToDelete)).To(Succeed()) + By(fmt.Sprintf("cleanup namespace %s", ns)) + }) + + Context("one chaos node", func() { + It("could spawn one chaos", func() { + ctx := context.TODO() + now := time.Now() + duration := 5 * time.Second + + By("create simple chaos node with pod chaos") + startTime := metav1.NewTime(now) + deadline := metav1.NewTime(now.Add(duration)) + workflowNode := v1alpha1.WorkflowNode{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + GenerateName: "chaos-node-with-chaos-", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + TemplateName: "", + WorkflowName: "", + Type: v1alpha1.TypePodChaos, + StartTime: &startTime, + Deadline: &deadline, + EmbedChaos: &v1alpha1.EmbedChaos{ + PodChaos: &v1alpha1.PodChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + }, + }, + Mode: v1alpha1.AllMode, + }, + }, + Action: v1alpha1.PodKillAction, + }, + }, + }, + } + Expect(kubeClient.Create(ctx, &workflowNode)).To(Succeed()) + Eventually(func() bool { + podChaosList := v1alpha1.PodChaosList{} + Expect(kubeClient.List(ctx, &podChaosList, &client.ListOptions{Namespace: ns})).To(Succeed()) + if len(podChaosList.Items) == 0 { + return false + } + return strings.HasPrefix(podChaosList.Items[0].Name, "chaos-node-with-chaos-") + }, 10*time.Second, time.Second).Should(BeTrue()) + }) + + It("could spawn one schedule", func() { + ctx := context.TODO() + now := time.Now() + duration := 5 * time.Second + + By("create simple chaos node with schedule") + startTime := metav1.NewTime(now) + deadline := metav1.NewTime(now.Add(duration)) + node := v1alpha1.WorkflowNode{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + GenerateName: "chaos-node-schedule-", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + WorkflowName: "", + Type: v1alpha1.TypeSchedule, + StartTime: &startTime, + Deadline: &deadline, + Schedule: &v1alpha1.ScheduleSpec{ + Schedule: "@every 1s", + StartingDeadlineSeconds: nil, + ConcurrencyPolicy: v1alpha1.AllowConcurrent, + HistoryLimit: 5, + Type: v1alpha1.ScheduleTypePodChaos, + ScheduleItem: v1alpha1.ScheduleItem{ + EmbedChaos: v1alpha1.EmbedChaos{ + PodChaos: &v1alpha1.PodChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{ + "app": "not-actually-exist", + }, + }, + }, + Mode: v1alpha1.AllMode, + }, + ContainerNames: nil, + }, + Action: v1alpha1.PodKillAction, + }, + }, + }, + }, + }, + } + Expect(kubeClient.Create(ctx, &node)).To(Succeed()) + Eventually(func() bool { + scheduleList := v1alpha1.ScheduleList{} + Expect(kubeClient.List(ctx, &scheduleList, &client.ListOptions{Namespace: ns})).To(Succeed()) + if len(scheduleList.Items) == 0 { + return false + } + return strings.HasPrefix(scheduleList.Items[0].Name, "chaos-node-schedule-") + }, 10*time.Second, time.Second).Should(BeTrue()) + }) + }) +}) diff --git a/pkg/workflow/controllers/deadline_reconciler.go b/pkg/workflow/controllers/deadline_reconciler.go index d1c31708ec..ca89adac36 100644 --- a/pkg/workflow/controllers/deadline_reconciler.go +++ b/pkg/workflow/controllers/deadline_reconciler.go @@ -4,43 +4,50 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package controllers import ( "context" + "fmt" "time" "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/tools/record" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/util/retry" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" ) type DeadlineReconciler struct { + *ChildNodesFetcher kubeClient client.Client - eventRecorder record.EventRecorder + eventRecorder recorder.ChaosRecorder logger logr.Logger } -func NewDeadlineReconciler(kubeClient client.Client, eventRecorder record.EventRecorder, logger logr.Logger) *DeadlineReconciler { - return &DeadlineReconciler{kubeClient: kubeClient, eventRecorder: eventRecorder, logger: logger} +func NewDeadlineReconciler(kubeClient client.Client, eventRecorder recorder.ChaosRecorder, logger logr.Logger) *DeadlineReconciler { + return &DeadlineReconciler{ + ChildNodesFetcher: NewChildNodesFetcher(kubeClient, logger), + kubeClient: kubeClient, + eventRecorder: eventRecorder, + logger: logger} } -func (it *DeadlineReconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { - ctx := context.TODO() - +func (it *DeadlineReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { node := v1alpha1.WorkflowNode{} err := it.kubeClient.Get(ctx, request.NamespacedName, &node) @@ -48,6 +55,11 @@ func (it *DeadlineReconciler) Reconcile(request reconcile.Request) (reconcile.Re return reconcile.Result{}, client.IgnoreNotFound(err) } + if ConditionEqualsTo(node.Status, v1alpha1.ConditionDeadlineExceed, corev1.ConditionTrue) { + // if this node deadline is exceed, try propagating to children node + return reconcile.Result{}, it.propagateDeadlineToChildren(ctx, &node) + } + if node.Spec.Deadline == nil { return reconcile.Result{}, nil } @@ -62,6 +74,11 @@ func (it *DeadlineReconciler) Reconcile(request reconcile.Request) (reconcile.Re return err } + if ConditionEqualsTo(nodeNeedUpdate.Status, v1alpha1.ConditionDeadlineExceed, corev1.ConditionTrue) { + // no need to update + return nil + } + var reason string if ConditionEqualsTo(nodeNeedUpdate.Status, v1alpha1.ConditionAccomplished, corev1.ConditionTrue) { reason = v1alpha1.NodeDeadlineOmitted @@ -69,18 +86,28 @@ func (it *DeadlineReconciler) Reconcile(request reconcile.Request) (reconcile.Re reason = v1alpha1.NodeDeadlineExceed } + if !ConditionEqualsTo(nodeNeedUpdate.Status, v1alpha1.ConditionDeadlineExceed, corev1.ConditionTrue) && reason == v1alpha1.NodeDeadlineExceed { + it.eventRecorder.Event(&node, recorder.DeadlineExceed{}) + } + SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ Type: v1alpha1.ConditionDeadlineExceed, Status: corev1.ConditionTrue, Reason: reason, }) - return it.kubeClient.Update(ctx, &nodeNeedUpdate) + + return it.kubeClient.Status().Update(ctx, &nodeNeedUpdate) }) if updateError != nil { return reconcile.Result{}, updateError } it.logger.Info("deadline exceed", "key", request.NamespacedName, "deadline", node.Spec.Deadline.Time) + propagateErr := it.propagateDeadlineToChildren(ctx, &node) + if propagateErr != nil { + it.logger.Error(propagateErr, "failed to propagate to children nodes", "key", request.NamespacedName) + return reconcile.Result{}, propagateErr + } } else { updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { nodeNeedUpdate := v1alpha1.WorkflowNode{} @@ -88,12 +115,21 @@ func (it *DeadlineReconciler) Reconcile(request reconcile.Request) (reconcile.Re if err != nil { return err } + + if ConditionEqualsTo(nodeNeedUpdate.Status, v1alpha1.ConditionDeadlineExceed, corev1.ConditionFalse) { + // no need to update + return nil + } else if ConditionEqualsTo(nodeNeedUpdate.Status, v1alpha1.ConditionDeadlineExceed, corev1.ConditionTrue) && + GetCondition(nodeNeedUpdate.Status, v1alpha1.ConditionDeadlineExceed).Reason == v1alpha1.ParentNodeDeadlineExceed { + return nil + } + SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ Type: v1alpha1.ConditionDeadlineExceed, Status: corev1.ConditionFalse, Reason: v1alpha1.NodeDeadlineNotExceed, }) - return it.kubeClient.Update(ctx, &nodeNeedUpdate) + return it.kubeClient.Status().Update(ctx, &nodeNeedUpdate) }) if updateError != nil { @@ -109,3 +145,57 @@ func (it *DeadlineReconciler) Reconcile(request reconcile.Request) (reconcile.Re return reconcile.Result{}, nil } + +func (it *DeadlineReconciler) propagateDeadlineToChildren(ctx context.Context, parent *v1alpha1.WorkflowNode) error { + switch parent.Spec.Type { + case v1alpha1.TypeSerial, v1alpha1.TypeParallel, v1alpha1.TypeTask: + activeChildNodes, _, err := it.ChildNodesFetcher.fetchChildNodes(ctx, *parent) + if err != nil { + return err + } + for _, childNode := range activeChildNodes { + childNode := childNode + + if WorkflowNodeFinished(childNode.Status) { + it.logger.Info("child node already finished, skip for propagate deadline", "node", fmt.Sprintf("%s/%s", childNode.Namespace, childNode.Name)) + continue + } + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + nodeNeedUpdate := v1alpha1.WorkflowNode{} + err := it.kubeClient.Get(ctx, types.NamespacedName{ + Namespace: childNode.Namespace, + Name: childNode.Name, + }, &nodeNeedUpdate) + if err != nil { + return err + } + if ConditionEqualsTo(nodeNeedUpdate.Status, v1alpha1.ConditionDeadlineExceed, corev1.ConditionTrue) { + it.logger.Info("omit propagate deadline to children, child already in deadline exceed", + "node", fmt.Sprintf("%s/%s", nodeNeedUpdate.Namespace, nodeNeedUpdate.Name), + "parent node", fmt.Sprintf("%s/%s", parent.Namespace, parent.Name), + ) + return nil + } + SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionDeadlineExceed, + Status: corev1.ConditionTrue, + Reason: v1alpha1.ParentNodeDeadlineExceed, + }) + it.eventRecorder.Event(&nodeNeedUpdate, recorder.ParentNodeDeadlineExceed{ParentNodeName: parent.Name}) + return it.kubeClient.Status().Update(ctx, &nodeNeedUpdate) + }) + if err != nil { + return err + } + it.logger.Info("propagate deadline for child node", + "child node", fmt.Sprintf("%s/%s", childNode.Namespace, childNode.Name), + "parent node", fmt.Sprintf("%s/%s", parent.Namespace, parent.Name), + ) + } + return nil + default: + it.logger.V(4).Info("no need to propagate with this type of workflow node", "type", parent.Spec.Type) + return nil + } +} diff --git a/pkg/workflow/controllers/deadline_reconciler_test.go b/pkg/workflow/controllers/deadline_reconciler_test.go new file mode 100644 index 0000000000..54e5cc066b --- /dev/null +++ b/pkg/workflow/controllers/deadline_reconciler_test.go @@ -0,0 +1,818 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controllers + +import ( + "context" + "fmt" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" + "k8s.io/utils/pointer" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +// integration tests +var _ = Describe("Workflow", func() { + var ns string + BeforeEach(func() { + ctx := context.TODO() + newNs := corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "chaos-mesh-", + }, + Spec: corev1.NamespaceSpec{}, + } + Expect(kubeClient.Create(ctx, &newNs)).To(Succeed()) + ns = newNs.Name + By(fmt.Sprintf("create new namespace %s", ns)) + }) + + AfterEach(func() { + ctx := context.TODO() + nsToDelete := corev1.Namespace{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Name: ns}, &nsToDelete)).To(Succeed()) + Expect(kubeClient.Delete(ctx, &nsToDelete)).To(Succeed()) + By(fmt.Sprintf("cleanup namespace %s", ns)) + }) + + Context("with deadline", func() { + Context("on suspend", func() { + It("should do nothing except waiting", func() { + ctx := context.TODO() + now := time.Now() + duration := 5 * time.Second + toleratedJitter := 3 * time.Second + + By("create simple suspend node") + startTime := metav1.NewTime(now) + deadline := metav1.NewTime(now.Add(duration)) + node := v1alpha1.WorkflowNode{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + GenerateName: "suspend-node-", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + WorkflowName: "", + Type: v1alpha1.TypeSuspend, + StartTime: &startTime, + Deadline: &deadline, + }, + } + Expect(kubeClient.Create(ctx, &node)).To(Succeed()) + + // TODO: no other side effects + + By("assert this node is finished") + Eventually(func() bool { + updatedNode := v1alpha1.WorkflowNode{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: node.Name}, &updatedNode)).To(Succeed()) + return ConditionEqualsTo(updatedNode.Status, v1alpha1.ConditionDeadlineExceed, corev1.ConditionTrue) + }, duration+toleratedJitter, time.Second).Should(BeTrue()) + + Eventually(func() bool { + updatedNode := v1alpha1.WorkflowNode{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: node.Name}, &updatedNode)).To(Succeed()) + return WorkflowNodeFinished(updatedNode.Status) + }, toleratedJitter, time.Second).Should(BeTrue()) + }) + }) + + Context("on chaos node with chaos", func() { + It("should delete chaos as soon as deadline exceed", func() { + ctx := context.TODO() + now := time.Now() + duration := 5 * time.Second + toleratedJitter := 3 * time.Second + + By("create simple chaos node with pod chaos") + startTime := metav1.NewTime(now) + deadline := metav1.NewTime(now.Add(duration)) + node := v1alpha1.WorkflowNode{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + GenerateName: "pod-chaos-", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + WorkflowName: "", + Type: v1alpha1.TypePodChaos, + StartTime: &startTime, + Deadline: &deadline, + EmbedChaos: &v1alpha1.EmbedChaos{ + PodChaos: &v1alpha1.PodChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{ + "app": "not-actually-exist", + }, + }, + }, + Mode: v1alpha1.AllMode, + }, + ContainerNames: nil, + }, + Action: v1alpha1.PodKillAction, + }, + }, + }, + } + Expect(kubeClient.Create(ctx, &node)).To(Succeed()) + + By("assert that pod chaos CR is created") + Eventually(func() bool { + updatedNode := v1alpha1.WorkflowNode{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: node.Name}, &updatedNode)).To(Succeed()) + if !ConditionEqualsTo(updatedNode.Status, v1alpha1.ConditionChaosInjected, corev1.ConditionTrue) { + return false + } + chaos := v1alpha1.PodChaos{} + err := kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: updatedNode.Status.ChaosResource.Name}, &chaos) + return err == nil + }, toleratedJitter, time.Second).Should(BeTrue()) + + By("assert that pod chaos should be purged") + Eventually(func() bool { + podChaosList := v1alpha1.PodChaosList{} + Expect(kubeClient.List(ctx, &podChaosList, &client.ListOptions{Namespace: ns})).To(Succeed()) + return len(podChaosList.Items) == 0 + }, duration+toleratedJitter, time.Second).Should(BeTrue()) + }) + }) + + Context("on chaos node with schedule", func() { + It("should delete schedule as soon as deadline exceed", func() { + ctx := context.TODO() + now := time.Now() + duration := 5 * time.Second + toleratedJitter := 3 * time.Second + + By("create simple chaos node with pod chaos") + startTime := metav1.NewTime(now) + deadline := metav1.NewTime(now.Add(duration)) + node := v1alpha1.WorkflowNode{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + GenerateName: "pod-chaos-", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + WorkflowName: "", + Type: v1alpha1.TypeSchedule, + StartTime: &startTime, + Deadline: &deadline, + Schedule: &v1alpha1.ScheduleSpec{ + Schedule: "@every 1s", + StartingDeadlineSeconds: nil, + ConcurrencyPolicy: v1alpha1.AllowConcurrent, + HistoryLimit: 5, + Type: v1alpha1.ScheduleTypePodChaos, + ScheduleItem: v1alpha1.ScheduleItem{ + EmbedChaos: v1alpha1.EmbedChaos{ + PodChaos: &v1alpha1.PodChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{ + "app": "not-actually-exist", + }, + }, + }, + Mode: v1alpha1.AllMode, + }, + ContainerNames: nil, + }, + Action: v1alpha1.PodKillAction, + }, + }, + }, + }, + }, + } + Expect(kubeClient.Create(ctx, &node)).To(Succeed()) + + By("assert that schedule CR is created") + Eventually(func() bool { + updatedNode := v1alpha1.WorkflowNode{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: node.Name}, &updatedNode)).To(Succeed()) + if !ConditionEqualsTo(updatedNode.Status, v1alpha1.ConditionChaosInjected, corev1.ConditionTrue) { + return false + } + schedule := v1alpha1.Schedule{} + err := kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: updatedNode.Status.ChaosResource.Name}, &schedule) + return err == nil + }, toleratedJitter, time.Second).Should(BeTrue()) + + By("assert that schedule should be purged") + Eventually(func() bool { + scheduleList := v1alpha1.ScheduleList{} + Expect(kubeClient.List(ctx, &scheduleList, &client.ListOptions{Namespace: ns})).To(Succeed()) + return len(scheduleList.Items) == 0 + }, duration+toleratedJitter, time.Second).Should(BeTrue()) + }) + }) + + Context("on serial", func() { + It("should shutdown all children of serial", func() { + ctx := context.TODO() + serialDuration := 3 * time.Second + durationOfSubTask1 := time.Second + durationOfSubTask2 := 5 * time.Second + durationOfSubTask3 := 5 * time.Second + toleratedJitter := 2 * time.Second + + maxConsisting := durationOfSubTask1 + durationOfSubTask2 + durationOfSubTask3 + + workflow := v1alpha1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + GenerateName: "fake-workflow-serial-", + }, + Spec: v1alpha1.WorkflowSpec{ + Entry: "entry-serial", + Templates: []v1alpha1.Template{{ + Name: "entry-serial", + Type: v1alpha1.TypeSerial, + Deadline: pointer.StringPtr(serialDuration.String()), + Children: []string{ + "serial-task-1", + "serial-task-2", + "serial-task-3", + }, + }, { + Name: "serial-task-1", + Type: v1alpha1.TypeSuspend, + Deadline: pointer.StringPtr(durationOfSubTask1.String()), + }, { + Name: "serial-task-2", + Type: v1alpha1.TypeSuspend, + Deadline: pointer.StringPtr(durationOfSubTask2.String()), + }, { + Name: "serial-task-3", + Type: v1alpha1.TypeSuspend, + Deadline: pointer.StringPtr(durationOfSubTask3.String()), + }}, + }, + Status: v1alpha1.WorkflowStatus{}, + } + + By("create workflow with serial entry") + Expect(kubeClient.Create(ctx, &workflow)).To(Succeed()) + + By("task 1 should be created") + task1Name := "" + Eventually(func() bool { + workflowNodes := v1alpha1.WorkflowNodeList{} + Expect(kubeClient.List(ctx, &workflowNodes)).To(Succeed()) + for _, item := range workflowNodes.Items { + if strings.HasPrefix(item.Name, "serial-task-1") { + task1Name = item.Name + return true + } + } + return false + }, toleratedJitter, 200*time.Millisecond).Should(BeTrue()) + + Expect(task1Name).NotTo(BeEmpty()) + + By("task 1 will be DeadlineExceed by itself") + Eventually(func() bool { + taskNode1 := v1alpha1.WorkflowNode{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: task1Name}, &taskNode1)).To(Succeed()) + condition := GetCondition(taskNode1.Status, v1alpha1.ConditionDeadlineExceed) + if condition == nil { + return false + } + if condition.Status != corev1.ConditionTrue { + return false + } + if condition.Reason != v1alpha1.NodeDeadlineExceed { + return false + } + return true + }, durationOfSubTask1+toleratedJitter, 200*time.Millisecond).Should(BeTrue()) + + By("task 2 should be created") + task2Name := "" + Eventually(func() bool { + workflowNodes := v1alpha1.WorkflowNodeList{} + Expect(kubeClient.List(ctx, &workflowNodes)).To(Succeed()) + for _, item := range workflowNodes.Items { + if strings.HasPrefix(item.Name, "serial-task-2") { + task2Name = item.Name + return true + } + } + return false + }, toleratedJitter, 200*time.Millisecond).Should(BeTrue()) + Expect(task2Name).NotTo(BeEmpty()) + + By("task 2 should be DeadlineExceed by parent") + taskNode2 := v1alpha1.WorkflowNode{} + Eventually(func() bool { + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: task2Name}, &taskNode2)).To(Succeed()) + condition := GetCondition(taskNode2.Status, v1alpha1.ConditionDeadlineExceed) + if condition == nil { + return false + } + if condition.Status != corev1.ConditionTrue { + return false + } + if condition.Reason != v1alpha1.ParentNodeDeadlineExceed { + return false + } + return true + }, durationOfSubTask1+toleratedJitter, 200*time.Millisecond).Should(BeTrue()) + + By("entry serial should also be DeadlineExceed by itself") + entryNode := v1alpha1.WorkflowNode{} + entryNodeName := taskNode2.Labels[v1alpha1.LabelControlledBy] + Expect(entryNodeName).NotTo(BeEmpty()) + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: entryNodeName}, &entryNode)).To(Succeed()) + condition := GetCondition(entryNode.Status, v1alpha1.ConditionDeadlineExceed) + Expect(condition).NotTo(BeNil()) + Expect(condition.Status).To(Equal(corev1.ConditionTrue)) + Expect(condition.Reason).To(Equal(v1alpha1.NodeDeadlineExceed)) + + By("task 3 should NEVER be created") + Consistently( + func() bool { + workflowNodes := v1alpha1.WorkflowNodeList{} + Expect(kubeClient.List(ctx, &workflowNodes)).To(Succeed()) + for _, item := range workflowNodes.Items { + if strings.HasPrefix(item.Name, "serial-task-3") { + return false + } + } + return true + }, + maxConsisting+toleratedJitter, time.Second).Should(BeTrue()) + }) + }) + + Context("on parallel", func() { + It("should shutdown all children of parallel", func() { + ctx := context.TODO() + parallelDuration := 3 * time.Second + durationOfSubTask1 := time.Second + durationOfSubTask2 := 5 * time.Second + durationOfSubTask3 := 5 * time.Second + toleratedJitter := 2 * time.Second + + workflow := v1alpha1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + GenerateName: "fake-workflow-parallel-", + }, + Spec: v1alpha1.WorkflowSpec{ + Entry: "entry-parallel", + Templates: []v1alpha1.Template{{ + Name: "entry-parallel", + Type: v1alpha1.TypeParallel, + Deadline: pointer.StringPtr(parallelDuration.String()), + Children: []string{ + "parallel-task-1", + "parallel-task-2", + "parallel-task-3", + }, + }, { + Name: "parallel-task-1", + Type: v1alpha1.TypeSuspend, + Deadline: pointer.StringPtr(durationOfSubTask1.String()), + }, { + Name: "parallel-task-2", + Type: v1alpha1.TypeSuspend, + Deadline: pointer.StringPtr(durationOfSubTask2.String()), + }, { + Name: "parallel-task-3", + Type: v1alpha1.TypeSuspend, + Deadline: pointer.StringPtr(durationOfSubTask3.String()), + }}, + }, + Status: v1alpha1.WorkflowStatus{}, + } + + By("create workflow with parallel entry") + Expect(kubeClient.Create(ctx, &workflow)).To(Succeed()) + + By("task 1,task 2,task 3 should be created") + task1Name := "" + task2Name := "" + task3Name := "" + Eventually(func() bool { + workflowNodes := v1alpha1.WorkflowNodeList{} + Expect(kubeClient.List(ctx, &workflowNodes)).To(Succeed()) + for _, item := range workflowNodes.Items { + if strings.HasPrefix(item.Name, "parallel-task-1") { + task1Name = item.Name + return true + } + } + return false + }, toleratedJitter, 200*time.Millisecond).Should(BeTrue()) + Eventually(func() bool { + workflowNodes := v1alpha1.WorkflowNodeList{} + Expect(kubeClient.List(ctx, &workflowNodes)).To(Succeed()) + for _, item := range workflowNodes.Items { + if strings.HasPrefix(item.Name, "parallel-task-2") { + task2Name = item.Name + return true + } + } + return false + }, toleratedJitter, 200*time.Millisecond).Should(BeTrue()) + Eventually(func() bool { + workflowNodes := v1alpha1.WorkflowNodeList{} + Expect(kubeClient.List(ctx, &workflowNodes)).To(Succeed()) + for _, item := range workflowNodes.Items { + if strings.HasPrefix(item.Name, "parallel-task-3") { + task3Name = item.Name + return true + } + } + return false + }, toleratedJitter, 200*time.Millisecond).Should(BeTrue()) + + Expect(task1Name).NotTo(BeEmpty()) + Expect(task2Name).NotTo(BeEmpty()) + Expect(task3Name).NotTo(BeEmpty()) + + By("task 1 should be DeadlineExceed by itself") + Eventually(func() bool { + taskNode := v1alpha1.WorkflowNode{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: task1Name}, &taskNode)).To(Succeed()) + condition := GetCondition(taskNode.Status, v1alpha1.ConditionDeadlineExceed) + if condition == nil { + return false + } + if condition.Status != corev1.ConditionTrue { + return false + } + if condition.Reason != v1alpha1.NodeDeadlineExceed { + return false + } + return true + }, durationOfSubTask1+toleratedJitter, 200*time.Millisecond).Should(BeTrue()) + + By("task 2 and task 3 should be DeadlineExceed by parent") + for _, nodeName := range []string{task2Name, task3Name} { + Eventually(func() bool { + taskNode := v1alpha1.WorkflowNode{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: nodeName}, &taskNode)).To(Succeed()) + condition := GetCondition(taskNode.Status, v1alpha1.ConditionDeadlineExceed) + if condition == nil { + return false + } + if condition.Status != corev1.ConditionTrue { + return false + } + if condition.Reason != v1alpha1.ParentNodeDeadlineExceed { + return false + } + return true + }, parallelDuration+toleratedJitter, 200*time.Millisecond).Should(BeTrue()) + } + By("entry parallel should also be DeadlineExceed by itself") + updateWorkflow := v1alpha1.Workflow{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: workflow.Name}, &updateWorkflow)).To(Succeed()) + entryNodeName := updateWorkflow.Status.EntryNode + Expect(entryNodeName).NotTo(BeNil()) + Expect(*entryNodeName).NotTo(BeEmpty()) + entryNode := v1alpha1.WorkflowNode{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: *entryNodeName}, &entryNode)).To(Succeed()) + condition := GetCondition(entryNode.Status, v1alpha1.ConditionDeadlineExceed) + Expect(condition).NotTo(BeNil()) + Expect(condition.Status).To(Equal(corev1.ConditionTrue)) + Expect(condition.Reason).To(Equal(v1alpha1.NodeDeadlineExceed)) + }) + }) + + Context("nested serial or parallel", func() { + It("should shutdown children recursively", func() { + ctx := context.TODO() + parallelDuration := 3 * time.Second + durationOfSuspend := 10 * time.Second + toleratedJitter := 2 * time.Second + + workflow := v1alpha1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + GenerateName: "fake-workflow-parallel-", + }, + Spec: v1alpha1.WorkflowSpec{ + Entry: "entry-parallel", + Templates: []v1alpha1.Template{{ + Name: "entry-parallel", + Type: v1alpha1.TypeParallel, + Deadline: pointer.StringPtr(parallelDuration.String()), + Children: []string{ + "parallel-level-1", + }, + }, { + Name: "parallel-level-1", + Type: v1alpha1.TypeParallel, + Children: []string{ + "parallel-level-2", + }, + }, { + Name: "parallel-level-2", + Type: v1alpha1.TypeParallel, + Children: []string{ + "suspend-task", + }, + }, { + Name: "suspend-task", + Type: v1alpha1.TypeSuspend, + Deadline: pointer.StringPtr(durationOfSuspend.String()), + }}, + }, + Status: v1alpha1.WorkflowStatus{}, + } + + By("create workflow with parallel entry") + Expect(kubeClient.Create(ctx, &workflow)).To(Succeed()) + + By("all the node should be created") + parallelLevel1NodeName := "" + parallelLevel2NodeName := "" + suspendTaskNodeName := "" + Eventually(func() bool { + workflowNodes := v1alpha1.WorkflowNodeList{} + Expect(kubeClient.List(ctx, &workflowNodes)).To(Succeed()) + for _, item := range workflowNodes.Items { + if strings.HasPrefix(item.Name, "parallel-level-1") { + parallelLevel1NodeName = item.Name + return true + } + } + return false + }, toleratedJitter, 200*time.Millisecond).Should(BeTrue()) + Eventually(func() bool { + workflowNodes := v1alpha1.WorkflowNodeList{} + Expect(kubeClient.List(ctx, &workflowNodes)).To(Succeed()) + for _, item := range workflowNodes.Items { + if strings.HasPrefix(item.Name, "parallel-level-2") { + parallelLevel2NodeName = item.Name + return true + } + } + return false + }, toleratedJitter, 200*time.Millisecond).Should(BeTrue()) + Eventually(func() bool { + workflowNodes := v1alpha1.WorkflowNodeList{} + Expect(kubeClient.List(ctx, &workflowNodes)).To(Succeed()) + for _, item := range workflowNodes.Items { + if strings.HasPrefix(item.Name, "suspend-task") { + suspendTaskNodeName = item.Name + return true + } + } + return false + }, toleratedJitter, 200*time.Millisecond).Should(BeTrue()) + + Expect(parallelLevel1NodeName).NotTo(BeEmpty()) + Expect(parallelLevel2NodeName).NotTo(BeEmpty()) + Expect(suspendTaskNodeName).NotTo(BeEmpty()) + + By("parallel level 1, parallel level 2 and suspend task should be DeadlineExceed by parent") + for _, nodeName := range []string{parallelLevel1NodeName, parallelLevel2NodeName, suspendTaskNodeName} { + Eventually(func() bool { + taskNode := v1alpha1.WorkflowNode{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: nodeName}, &taskNode)).To(Succeed()) + condition := GetCondition(taskNode.Status, v1alpha1.ConditionDeadlineExceed) + if condition == nil { + return false + } + if condition.Status != corev1.ConditionTrue { + return false + } + if condition.Reason != v1alpha1.ParentNodeDeadlineExceed { + return false + } + return true + }, parallelDuration+toleratedJitter, 200*time.Millisecond).Should(BeTrue()) + } + + By("entry parallel should also be DeadlineExceed by itself") + updateWorkflow := v1alpha1.Workflow{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: workflow.Name}, &updateWorkflow)).To(Succeed()) + entryNodeName := updateWorkflow.Status.EntryNode + Expect(entryNodeName).NotTo(BeNil()) + Expect(*entryNodeName).NotTo(BeEmpty()) + entryNode := v1alpha1.WorkflowNode{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: *entryNodeName}, &entryNode)).To(Succeed()) + condition := GetCondition(entryNode.Status, v1alpha1.ConditionDeadlineExceed) + Expect(condition).NotTo(BeNil()) + Expect(condition.Status).To(Equal(corev1.ConditionTrue)) + Expect(condition.Reason).To(Equal(v1alpha1.NodeDeadlineExceed)) + + }) + }) + + Context("if this node is already in DeadlineExceed because of ParentNodeDeadlineExceed", func() { + It("should omit the next coming deadline", func() { + ctx := context.TODO() + now := time.Now() + duration := 5 * time.Second + toleratedJitter := 3 * time.Second + + startTime := metav1.NewTime(now) + deadline := metav1.NewTime(now.Add(duration)) + + By("create one empty podchaos workflow node, with deadline: 3s") + node := v1alpha1.WorkflowNode{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + GenerateName: "pod-chaos-", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + WorkflowName: "", + Type: v1alpha1.TypePodChaos, + StartTime: &startTime, + Deadline: &deadline, + EmbedChaos: &v1alpha1.EmbedChaos{ + PodChaos: &v1alpha1.PodChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{ + "app": "not-actually-exist", + }, + }, + }, + Mode: v1alpha1.AllMode, + }, + ContainerNames: nil, + }, + Action: v1alpha1.PodKillAction, + }, + }, + }, + Status: v1alpha1.WorkflowNodeStatus{}, + } + Expect(kubeClient.Create(ctx, &node)).To(Succeed()) + By("manually set condition ConditionDeadlineExceed to true, because of v1alpha1.ParentNodeDeadlineExceed") + updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { + deadlineExceedNode := v1alpha1.WorkflowNode{} + + err := kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: node.Name}, &deadlineExceedNode) + if err != nil { + return err + } + deadlineExceedNode.Status.Conditions = []v1alpha1.WorkflowNodeCondition{ + { + Type: v1alpha1.ConditionDeadlineExceed, + Status: corev1.ConditionTrue, + Reason: v1alpha1.ParentNodeDeadlineExceed, + }, + } + err = kubeClient.Status().Update(ctx, &deadlineExceedNode) + if err != nil { + return err + } + return nil + }) + Expect(updateError).To(BeNil()) + By("after 3 seconds, the condition ConditionDeadlineExceed should not be modified") + Consistently(func() bool { + updatedNode := v1alpha1.WorkflowNode{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: node.Name}, &updatedNode)).To(Succeed()) + + condition := GetCondition(updatedNode.Status, v1alpha1.ConditionDeadlineExceed) + if condition == nil { + return false + } + if condition.Status != corev1.ConditionTrue { + return false + } + if condition.Reason != v1alpha1.ParentNodeDeadlineExceed { + return false + } + return true + }, + duration+toleratedJitter, time.Second, + ).Should(BeTrue()) + }) + + It("should NOT omit the next coming deadline otherwise", func() { + ctx := context.TODO() + now := time.Now() + duration := 5 * time.Second + toleratedJitter := 3 * time.Second + + startTime := metav1.NewTime(now) + deadline := metav1.NewTime(now.Add(duration)) + + By("create one empty podchaos workflow node, with deadline: 3s") + node := v1alpha1.WorkflowNode{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + GenerateName: "pod-chaos-", + }, + Spec: v1alpha1.WorkflowNodeSpec{ + WorkflowName: "", + Type: v1alpha1.TypePodChaos, + StartTime: &startTime, + Deadline: &deadline, + EmbedChaos: &v1alpha1.EmbedChaos{ + PodChaos: &v1alpha1.PodChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{ + "app": "not-actually-exist", + }, + }, + }, + Mode: v1alpha1.AllMode, + }, + ContainerNames: nil, + }, + Action: v1alpha1.PodKillAction, + }, + }, + }, + Status: v1alpha1.WorkflowNodeStatus{}, + } + Expect(kubeClient.Create(ctx, &node)).To(Succeed()) + By("manually set condition ConditionDeadlineExceed to true, but NOT caused by v1alpha1.ParentNodeDeadlineExceed") + updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { + deadlineExceedNode := v1alpha1.WorkflowNode{} + + err := kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: node.Name}, &deadlineExceedNode) + if err != nil { + return err + } + deadlineExceedNode.Status.Conditions = []v1alpha1.WorkflowNodeCondition{ + { + Type: v1alpha1.ConditionDeadlineExceed, + Status: corev1.ConditionTrue, + Reason: v1alpha1.NodeDeadlineExceed, + }, + } + err = kubeClient.Status().Update(ctx, &deadlineExceedNode) + if err != nil { + return err + } + return nil + }) + Expect(updateError).To(BeNil()) + By("condition ConditionDeadlineExceed should be corrected soon") + Eventually(func() bool { + updatedNode := v1alpha1.WorkflowNode{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: node.Name}, &updatedNode)).To(Succeed()) + return ConditionEqualsTo(updatedNode.Status, v1alpha1.ConditionDeadlineExceed, corev1.ConditionFalse) + }, + toleratedJitter, + time.Second) + By("after 5 seconds, the condition ConditionDeadlineExceed should not be modified, caused by NodeDeadlineExceed itself") + Eventually(func() bool { + updatedNode := v1alpha1.WorkflowNode{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: node.Name}, &updatedNode)).To(Succeed()) + + condition := GetCondition(updatedNode.Status, v1alpha1.ConditionDeadlineExceed) + if condition == nil { + return false + } + if condition.Status != corev1.ConditionTrue { + return false + } + if condition.Reason != v1alpha1.NodeDeadlineExceed { + return false + } + return true + }, + duration+toleratedJitter, time.Second, + ).Should(BeTrue()) + }) + }) + }) +}) diff --git a/pkg/workflow/controllers/new_node.go b/pkg/workflow/controllers/new_node.go index 23a7418ded..f55e2dd308 100644 --- a/pkg/workflow/controllers/new_node.go +++ b/pkg/workflow/controllers/new_node.go @@ -4,20 +4,22 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package controllers import ( - "errors" "fmt" "time" + "github.com/pkg/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" @@ -44,8 +46,8 @@ func renderNodesByTemplates(workflow *v1alpha1.Workflow, parent *v1alpha1.Workfl now := metav1.NewTime(time.Now()) var deadline *metav1.Time = nil - if template.Duration != nil { - duration, err := time.ParseDuration(*template.Duration) + if template.Deadline != nil { + duration, err := time.ParseDuration(*template.Deadline) if err != nil { // TODO: logger return nil, err @@ -60,13 +62,18 @@ func renderNodesByTemplates(workflow *v1alpha1.Workflow, parent *v1alpha1.Workfl GenerateName: fmt.Sprintf("%s-", template.Name), }, Spec: v1alpha1.WorkflowNodeSpec{ - TemplateName: template.Name, - WorkflowName: workflow.Name, - Type: template.Type, - StartTime: &now, - Deadline: deadline, - Tasks: template.Tasks, - EmbedChaos: template.EmbedChaos, + TemplateName: template.Name, + WorkflowName: workflow.Name, + Type: template.Type, + StartTime: &now, + Deadline: deadline, + Children: template.Children, + Task: template.Task, + ConditionalBranches: template.ConditionalBranches, + EmbedChaos: template.EmbedChaos, + Schedule: conversionSchedule(template.Schedule), + StatusCheck: template.StatusCheck, + AbortWithStatusCheck: template.AbortWithStatusCheck, }, } @@ -105,11 +112,41 @@ func renderNodesByTemplates(workflow *v1alpha1.Workflow, parent *v1alpha1.Workfl result = append(result, &renderedNode) continue } - return nil, errors.New( - fmt.Sprintf("workflow %s do not contains template called %s", - workflow.Name, - name, - )) + return nil, errors.Errorf( + "workflow %s do not contains template called %s", + workflow.Name, + name, + ) } return result, nil } + +func conversionSchedule(origin *v1alpha1.ChaosOnlyScheduleSpec) *v1alpha1.ScheduleSpec { + if origin == nil { + return nil + } + return &v1alpha1.ScheduleSpec{ + Schedule: origin.Schedule, + StartingDeadlineSeconds: origin.StartingDeadlineSeconds, + ConcurrencyPolicy: origin.ConcurrencyPolicy, + HistoryLimit: origin.HistoryLimit, + Type: origin.Type, + ScheduleItem: v1alpha1.ScheduleItem{ + EmbedChaos: v1alpha1.EmbedChaos{ + AWSChaos: origin.EmbedChaos.AWSChaos, + DNSChaos: origin.EmbedChaos.DNSChaos, + GCPChaos: origin.EmbedChaos.GCPChaos, + HTTPChaos: origin.EmbedChaos.HTTPChaos, + IOChaos: origin.EmbedChaos.IOChaos, + JVMChaos: origin.EmbedChaos.JVMChaos, + KernelChaos: origin.EmbedChaos.KernelChaos, + NetworkChaos: origin.EmbedChaos.NetworkChaos, + PodChaos: origin.EmbedChaos.PodChaos, + StressChaos: origin.EmbedChaos.StressChaos, + TimeChaos: origin.EmbedChaos.TimeChaos, + PhysicalMachineChaos: origin.EmbedChaos.PhysicalMachineChaos, + }, + Workflow: nil, + }, + } +} diff --git a/pkg/workflow/controllers/parallel_node_reconciler.go b/pkg/workflow/controllers/parallel_node_reconciler.go new file mode 100644 index 0000000000..092e209ebf --- /dev/null +++ b/pkg/workflow/controllers/parallel_node_reconciler.go @@ -0,0 +1,233 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controllers + +import ( + "context" + "fmt" + "time" + + "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" +) + +// ParallelNodeReconciler watches on nodes which type is Parallel +type ParallelNodeReconciler struct { + *ChildNodesFetcher + kubeClient client.Client + eventRecorder recorder.ChaosRecorder + logger logr.Logger +} + +func NewParallelNodeReconciler(kubeClient client.Client, eventRecorder recorder.ChaosRecorder, logger logr.Logger) *ParallelNodeReconciler { + return &ParallelNodeReconciler{ + ChildNodesFetcher: NewChildNodesFetcher(kubeClient, logger), + kubeClient: kubeClient, + eventRecorder: eventRecorder, + logger: logger, + } +} + +// Reconcile is extremely like the one in SerialNodeReconciler, only allows the parallel schedule, and respawn **all** the children tasks during retry +func (it *ParallelNodeReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { + startTime := time.Now() + defer func() { + it.logger.V(4).Info("Finished syncing for parallel node", + "node", request.NamespacedName, + "duration", time.Since(startTime), + ) + }() + + node := v1alpha1.WorkflowNode{} + err := it.kubeClient.Get(ctx, request.NamespacedName, &node) + if err != nil { + return reconcile.Result{}, client.IgnoreNotFound(err) + } + + // only resolve parallel nodes + if node.Spec.Type != v1alpha1.TypeParallel { + return reconcile.Result{}, nil + } + + it.logger.V(4).Info("resolve parallel node", "node", request) + + // make effects, create/remove children nodes + err = it.syncChildNodes(ctx, node) + if err != nil { + return reconcile.Result{}, err + } + + // update status + updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { + nodeNeedUpdate := v1alpha1.WorkflowNode{} + err := it.kubeClient.Get(ctx, request.NamespacedName, &nodeNeedUpdate) + if err != nil { + return err + } + + activeChildren, finishedChildren, err := it.fetchChildNodes(ctx, nodeNeedUpdate) + if err != nil { + return err + } + + nodeNeedUpdate.Status.FinishedChildren = nil + for _, finishedChild := range finishedChildren { + nodeNeedUpdate.Status.FinishedChildren = append(nodeNeedUpdate.Status.FinishedChildren, + corev1.LocalObjectReference{ + Name: finishedChild.Name, + }) + } + + nodeNeedUpdate.Status.ActiveChildren = nil + for _, activeChild := range activeChildren { + nodeNeedUpdate.Status.ActiveChildren = append(nodeNeedUpdate.Status.ActiveChildren, + corev1.LocalObjectReference{ + Name: activeChild.Name, + }) + } + + // TODO: also check the consistent between spec in task and the spec in child node + if len(finishedChildren) == len(nodeNeedUpdate.Spec.Children) { + if !WorkflowNodeFinished(nodeNeedUpdate.Status) { + it.eventRecorder.Event(&nodeNeedUpdate, recorder.NodeAccomplished{}) + } + SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionAccomplished, + Status: corev1.ConditionTrue, + Reason: "", + }) + } else { + SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionAccomplished, + Status: corev1.ConditionFalse, + Reason: "", + }) + } + + return it.kubeClient.Status().Update(ctx, &nodeNeedUpdate) + }) + + if updateError != nil { + it.logger.Error(err, "failed to update the status of node", "node", request) + return reconcile.Result{}, updateError + } + + return reconcile.Result{}, nil +} + +func (it *ParallelNodeReconciler) syncChildNodes(ctx context.Context, node v1alpha1.WorkflowNode) error { + + // empty parallel node + if len(node.Spec.Children) == 0 { + it.logger.V(4).Info("empty parallel node, NOOP", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + ) + return nil + } + + if WorkflowNodeFinished(node.Status) { + return nil + } + + activeChildNodes, finishedChildNodes, err := it.fetchChildNodes(ctx, node) + if err != nil { + return err + } + existsChildNodes := append(activeChildNodes, finishedChildNodes...) + + var taskNamesOfNodes []string + for _, childNode := range existsChildNodes { + taskNamesOfNodes = append(taskNamesOfNodes, getTaskNameFromGeneratedName(childNode.GetName())) + } + + var tasksToStartup []string + + if len(existsChildNodes) == 0 { + tasksToStartup = node.Spec.Children + } + // TODO: check the specific of task and workflow nodes + // the definition of Spec.Children changed, remove all the existed nodes + if len(existsChildNodes) > 0 && (len(setDifference(taskNamesOfNodes, node.Spec.Children)) > 0 || len(setDifference(node.Spec.Children, taskNamesOfNodes)) > 0) { + tasksToStartup = node.Spec.Children + + var nodesToCleanup []string + for _, item := range existsChildNodes { + nodesToCleanup = append(nodesToCleanup, item.Name) + } + it.eventRecorder.Event(&node, recorder.RerunBySpecChanged{CleanedChildrenNode: nodesToCleanup}) + + for _, childNode := range existsChildNodes { + // best effort deletion + err := it.kubeClient.Delete(ctx, &childNode) + if err != nil { + it.logger.Error(err, "failed to delete outdated child node", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "child node", fmt.Sprintf("%s/%s", childNode.Namespace, childNode.Name), + ) + } + } + + } + + if len(tasksToStartup) == 0 { + it.logger.Info("no need to spawn new child node", "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name)) + return nil + } + + parentWorkflow := v1alpha1.Workflow{} + err = it.kubeClient.Get(ctx, types.NamespacedName{ + Namespace: node.Namespace, + Name: node.Spec.WorkflowName, + }, &parentWorkflow) + if err != nil { + it.logger.Error(err, "failed to fetch parent workflow", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "workflow name", node.Spec.WorkflowName) + return err + } + + childNodes, err := renderNodesByTemplates(&parentWorkflow, &node, tasksToStartup...) + if err != nil { + it.logger.Error(err, "failed to render children childNodes", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name)) + return err + } + + var childrenNames []string + for _, childNode := range childNodes { + err := it.kubeClient.Create(ctx, childNode) + if err != nil { + it.logger.Error(err, "failed to create child node", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "child node", childNode) + return err + } + childrenNames = append(childrenNames, childNode.Name) + } + it.eventRecorder.Event(&node, recorder.NodesCreated{ChildNodes: childrenNames}) + it.logger.Info("parallel node spawn new child node", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "child node", childrenNames) + + return nil +} diff --git a/pkg/workflow/controllers/parallel_node_reconciler_test.go b/pkg/workflow/controllers/parallel_node_reconciler_test.go new file mode 100644 index 0000000000..eb9f7e440c --- /dev/null +++ b/pkg/workflow/controllers/parallel_node_reconciler_test.go @@ -0,0 +1,290 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controllers + +import ( + "context" + "fmt" + "reflect" + "sort" + "strings" + "testing" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +// unit tests +func Test_getTaskNameFromGeneratedName(t *testing.T) { + type args struct { + generatedNodeName string + } + tests := []struct { + name string + args args + want string + }{ + { + "common case", + args{"name-1"}, + "name", + }, { + "common case", + args{"name-1-2"}, + "name-1", + }, { + "common case", + args{"name"}, + "name", + }, { + "common case", + args{"name-"}, + "name", + }, + { + "common case", + args{"-name"}, + "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getTaskNameFromGeneratedName(tt.args.generatedNodeName); got != tt.want { + t.Errorf("getTaskNameFromGeneratedName() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_relativeComplementSet(t *testing.T) { + type args struct { + former []string + latter []string + } + tests := []struct { + name string + args args + want []string + }{ + { + name: "common_case", + args: args{ + former: []string{"a", "b", "c"}, + latter: []string{}, + }, + want: []string{"a", "b", "c"}, + }, { + name: "common_case", + args: args{ + former: []string{"a", "b", "c"}, + latter: []string{"b", "c"}, + }, + want: []string{"a"}, + }, { + name: "common_case", + args: args{ + former: []string{"a", "b", "c"}, + latter: []string{"c", "a"}, + }, + want: []string{"b"}, + }, { + name: "common_case", + args: args{ + former: []string{"a", "b", "c"}, + latter: []string{"c", "b", "d"}, + }, + want: []string{"a"}, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := setDifference(test.args.former, test.args.latter) + sort.Strings(got) + sort.Strings(test.want) + if !reflect.DeepEqual(got, test.want) { + t.Errorf("getTaskNameFromGeneratedName() = %v, want %v", got, test.want) + } + }) + } +} + +// integration tests +var _ = Describe("Workflow", func() { + var ns string + BeforeEach(func() { + ctx := context.TODO() + newNs := corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "chaos-mesh-", + }, + Spec: corev1.NamespaceSpec{}, + } + Expect(kubeClient.Create(ctx, &newNs)).To(Succeed()) + ns = newNs.Name + By(fmt.Sprintf("create new namespace %s", ns)) + }) + + AfterEach(func() { + ctx := context.TODO() + nsToDelete := corev1.Namespace{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Name: ns}, &nsToDelete)).To(Succeed()) + Expect(kubeClient.Delete(ctx, &nsToDelete)).To(Succeed()) + By(fmt.Sprintf("cleanup namespace %s", ns)) + }) + + Context("with one parallel node", func() { + Context("with one simple parallel node", func() { + + It("should spawn all the children at the same time", func() { + By("create simple workflow") + ctx := context.TODO() + simpleParallelWorkflow := v1alpha1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "simple-parallel", + Namespace: ns, + }, + Spec: v1alpha1.WorkflowSpec{ + Entry: "parallel", + Templates: []v1alpha1.Template{ + { + Name: "parallel", + Type: v1alpha1.TypeParallel, + Children: []string{ + "network-chaos", + "pod-chaos", + "stress-chaos", + }, + }, { + Name: "network-chaos", + Type: v1alpha1.TypeNetworkChaos, + EmbedChaos: &v1alpha1.EmbedChaos{ + NetworkChaos: &v1alpha1.NetworkChaosSpec{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{ + "app": "not-exist", + }, + }, + }, + Mode: v1alpha1.AllMode, + }, + Action: v1alpha1.PartitionAction, + }, + }, + }, { + Name: "pod-chaos", + Type: v1alpha1.TypePodChaos, + EmbedChaos: &v1alpha1.EmbedChaos{ + PodChaos: &v1alpha1.PodChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{ + "app": "not-exist", + }, + }, + }, + Mode: v1alpha1.AllMode, + }, + }, + Action: v1alpha1.PodKillAction, + }, + }, + }, + { + Name: "stress-chaos", + Type: v1alpha1.TypeStressChaos, + EmbedChaos: &v1alpha1.EmbedChaos{ + StressChaos: &v1alpha1.StressChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{ + "app": "not-exist", + }, + }, + }, + Mode: v1alpha1.AllMode, + }, + }, + Stressors: &v1alpha1.Stressors{ + CPUStressor: &v1alpha1.CPUStressor{ + Stressor: v1alpha1.Stressor{ + Workers: 2, + }, + }}, + }, + }, + }, + }, + }} + Expect(kubeClient.Create(ctx, &simpleParallelWorkflow)).To(Succeed()) + + By("assert that all resource has been created") + + By("assert that 1 entry node and 3 chaos nodes created") + Eventually(func() int { + workflowNodeList := v1alpha1.WorkflowNodeList{} + Expect(kubeClient.List(ctx, &workflowNodeList, &client.ListOptions{Namespace: ns})).To(Succeed()) + return len(workflowNodeList.Items) + }, 10*time.Second, time.Second).Should(Equal(4)) + + By("assert that network chaos has been created") + Eventually(func() bool { + chaosList := v1alpha1.NetworkChaosList{} + Expect(kubeClient.List(ctx, &chaosList, &client.ListOptions{Namespace: ns})).To(Succeed()) + if len(chaosList.Items) != 1 { + return false + } + return strings.HasPrefix(chaosList.Items[0].Name, "network-chaos") + }, 10*time.Second, time.Second).Should(BeTrue()) + + By("assert that pod chaos has been created") + Eventually(func() bool { + chaosList := v1alpha1.PodChaosList{} + Expect(kubeClient.List(ctx, &chaosList, &client.ListOptions{Namespace: ns})).To(Succeed()) + if len(chaosList.Items) != 1 { + return false + } + return strings.HasPrefix(chaosList.Items[0].Name, "pod-chaos") + }, 10*time.Second, time.Second).Should(BeTrue()) + + By("assert that stress chaos has been created") + Eventually(func() bool { + chaosList := v1alpha1.StressChaosList{} + Expect(kubeClient.List(ctx, &chaosList, &client.ListOptions{Namespace: ns})).To(Succeed()) + if len(chaosList.Items) != 1 { + return false + } + return strings.HasPrefix(chaosList.Items[0].Name, "stress-chaos") + }, 10*time.Second, time.Second).Should(BeTrue()) + }) + }) + }) +}) diff --git a/pkg/workflow/controllers/serial_node_reconciler.go b/pkg/workflow/controllers/serial_node_reconciler.go index 1eb4158d34..06cbf1d3a9 100644 --- a/pkg/workflow/controllers/serial_node_reconciler.go +++ b/pkg/workflow/controllers/serial_node_reconciler.go @@ -4,42 +4,75 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package controllers import ( "context" + "fmt" + "strings" + "time" "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/record" "k8s.io/client-go/util/retry" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" ) // SerialNodeReconciler watches on nodes which type is Serial type SerialNodeReconciler struct { + *ChildNodesFetcher kubeClient client.Client - eventRecorder record.EventRecorder + eventRecorder recorder.ChaosRecorder logger logr.Logger } -func NewSerialNodeReconciler(kubeClient client.Client, eventRecorder record.EventRecorder, logger logr.Logger) *SerialNodeReconciler { - return &SerialNodeReconciler{kubeClient: kubeClient, eventRecorder: eventRecorder, logger: logger} +func NewSerialNodeReconciler(kubeClient client.Client, eventRecorder recorder.ChaosRecorder, logger logr.Logger) *SerialNodeReconciler { + return &SerialNodeReconciler{ + ChildNodesFetcher: NewChildNodesFetcher(kubeClient, logger), + kubeClient: kubeClient, + eventRecorder: eventRecorder, + logger: logger, + } } -func (it *SerialNodeReconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { - ctx := context.TODO() +// Reconcile should be invoked by: changes on a serial node, or changes on a node which controlled by serial node. +// So we need to setup EnqueueRequestForOwner while setting up this reconciler. +// +// Reconcile does these things: +// 1. walk through on tasks in spec, compare them with the node instances (listed with v1alpha1.LabelControlledBy), +// remove the outdated instance; +// 2. find out the node needs to be created, then create one if exists; +// 3. update the status of serial node; +// +// In this reconciler, we SHOULD NOT use v1alpha1.WorkflowNodeStatus as the state. +// Because v1alpha1.WorkflowNodeStatus is generated by this reconciler, if that itself also depends on that state, +// it will be complex to decide when to update the status, and even require to update status more than one time, +// that sounds not good. +// And We MUST update v1alpha1.WorkflowNodeStatus by "observing real world" at EACH TIME, such as listing controlled +// children nodes. +// We only update v1alpha1.WorkflowNodeStatus once(wrapped with retry on conflict), at the end of this method. +func (it *SerialNodeReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { + startTime := time.Now() + defer func() { + it.logger.V(4).Info("Finished syncing for serial node", + "node", request.NamespacedName, + "duration", time.Since(startTime), + ) + }() node := v1alpha1.WorkflowNode{} err := it.kubeClient.Get(ctx, request.NamespacedName, &node) @@ -52,93 +85,205 @@ func (it *SerialNodeReconciler) Reconcile(request reconcile.Request) (reconcile. return reconcile.Result{}, nil } - // empty serial node - if len(node.Spec.Tasks) == 0 { - it.logger.V(4).Info("empty serial node, NOOP", "key", request.NamespacedName) - return reconcile.Result{}, nil - } + it.logger.V(4).Info("resolve serial node", "node", request) - // un-synced expected children - if node.Status.ExpectedChildrenNum == nil { - expected := len(node.Spec.Tasks) - node.Status.ExpectedChildrenNum = &expected + // make effects, create/remove children nodes + err = it.syncChildNodes(ctx, node) + if err != nil { + return reconcile.Result{}, err } - // this node should finished - if len(node.Status.FinishedChildren) == *node.Status.ExpectedChildrenNum { - if !ConditionEqualsTo(node.Status, v1alpha1.ConditionAccomplished, corev1.ConditionTrue) { - updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { - nodeNeedUpdate := v1alpha1.WorkflowNode{} - err := it.kubeClient.Get(ctx, request.NamespacedName, &nodeNeedUpdate) - if err != nil { - return client.IgnoreNotFound(err) - } - SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ - Type: v1alpha1.ConditionAccomplished, - Status: corev1.ConditionTrue, - Reason: v1alpha1.NodeAccomplished, - }) - return it.kubeClient.Update(ctx, &nodeNeedUpdate) - }) - - if updateError != nil { - return reconcile.Result{}, updateError - } + // update status + updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { + nodeNeedUpdate := v1alpha1.WorkflowNode{} + err := it.kubeClient.Get(ctx, request.NamespacedName, &nodeNeedUpdate) + if err != nil { + return err + } - it.eventRecorder.Event(&node, corev1.EventTypeNormal, v1alpha1.NodeAccomplished, "Serial node accomplished") + activeChildren, finishedChildren, err := it.fetchChildNodes(ctx, nodeNeedUpdate) + if err != nil { + return err } - return reconcile.Result{}, nil - } - if len(node.Status.ActiveChildren) == 0 { - it.logger.Info("schedule next", "key", request.NamespacedName, "status", node.Status) - taskToStartup := node.Spec.Tasks[len(node.Status.FinishedChildren)] - parentWorkflow := v1alpha1.Workflow{} + nodeNeedUpdate.Status.FinishedChildren = nil + for _, finishedChild := range finishedChildren { + nodeNeedUpdate.Status.FinishedChildren = append(nodeNeedUpdate.Status.FinishedChildren, + corev1.LocalObjectReference{ + Name: finishedChild.Name, + }) + } - err := it.kubeClient.Get(ctx, types.NamespacedName{ - Namespace: node.Namespace, - Name: node.Spec.WorkflowName, - }, &parentWorkflow) - if err != nil { - it.logger.Error(err, "failed to fetch parent workflow", "key", request.NamespacedName, "workflow name", node.Spec.WorkflowName) - return reconcile.Result{}, err + nodeNeedUpdate.Status.ActiveChildren = nil + for _, activeChild := range activeChildren { + nodeNeedUpdate.Status.ActiveChildren = append(nodeNeedUpdate.Status.ActiveChildren, + corev1.LocalObjectReference{ + Name: activeChild.Name, + }) } - childrenNodes, err := renderNodesByTemplates(&parentWorkflow, &node, taskToStartup) - if err != nil { - it.logger.Error(err, "failed to render children childrenNodes", "node", request.NamespacedName) - return reconcile.Result{}, err + + if len(activeChildren) > 1 { + it.logger.Info("warning: serial node has more than 1 active children", "namespace", nodeNeedUpdate.Namespace, "name", nodeNeedUpdate.Name, "children", nodeNeedUpdate.Status.ActiveChildren) } - for _, childNode := range childrenNodes { - err := it.kubeClient.Create(ctx, childNode) - if err != nil { - it.logger.Error(err, "failed to create child node", "node", request.NamespacedName, "child node", childNode) - return reconcile.Result{}, err + // TODO: also check the consistent between spec in task and the spec in child node + if len(finishedChildren) == len(nodeNeedUpdate.Spec.Children) { + if !WorkflowNodeFinished(nodeNeedUpdate.Status) { + it.eventRecorder.Event(&nodeNeedUpdate, recorder.NodeAccomplished{}) } + SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionAccomplished, + Status: corev1.ConditionTrue, + Reason: "", + }) + } else { + SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionAccomplished, + Status: corev1.ConditionFalse, + Reason: "", + }) } - updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { - nodeNeedUpdate := v1alpha1.WorkflowNode{} - err := it.kubeClient.Get(ctx, request.NamespacedName, &nodeNeedUpdate) - if err != nil { - return err - } - for _, item := range childrenNodes { - nodeNeedUpdate.Status.ActiveChildren = append(nodeNeedUpdate.Status.ActiveChildren, corev1.LocalObjectReference{Name: item.Name}) - } - return it.kubeClient.Update(ctx, &nodeNeedUpdate) - }) + return it.kubeClient.Status().Update(ctx, &nodeNeedUpdate) + }) + + if updateError != nil { + it.logger.Error(err, "failed to update the status of node", "node", request) + return reconcile.Result{}, updateError + } - if updateError != nil { - return reconcile.Result{}, updateError + return reconcile.Result{}, nil +} + +// syncChildNodes reconciles the children nodes to following the desired states. +// It does the first 2 steps mentioned in Reconcile. +// +// Notice again: we SHOULD NOT decide the operation based on v1alpha1.WorkflowNodeStatus, please +// use kubeClient to fetch information from real world. +func (it *SerialNodeReconciler) syncChildNodes(ctx context.Context, node v1alpha1.WorkflowNode) error { + + // empty serial node + if len(node.Spec.Children) == 0 { + it.logger.V(4).Info("empty serial node, NOOP", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + ) + return nil + } + + if WorkflowNodeFinished(node.Status) { + return nil + } + + activeChildNodes, finishedChildNodes, err := it.fetchChildNodes(ctx, node) + if err != nil { + return err + } + var taskToStartup string + if len(activeChildNodes) == 0 { + // no active children, trying to spawn a new one + for index, task := range node.Spec.Children { + // Walking through on the Spec.Children, each one of task SHOULD has one corresponding workflow node; + // If the spec of one task has been changed, the corresponding workflow node and other + // workflow nodes **behinds** that workflow node will be deleted. + // That's so called "partial rerun" feature. + // For example: + // One serial node have three children nodes: A, B, C, and all of them have finished. + // Then user updates the Spec.Children[B], the expected behavior is workflow node B and C will be + // deleted, then create a new node that refs to B, no effects on A. + if index < len(finishedChildNodes) { + // TODO: if the definition/spec of task changed, we should also respawn the node + // child node start with task name + + // TODO: maybe the changes on Spec.Children should be concerned each time, not only during spawning + // new instances, for shutdown outdated nodes **instantly** + + if strings.HasPrefix(task, finishedChildNodes[index].Name) { + // TODO: emit event + taskToStartup = task + + // TODO: nodes to delete should be all other unrecognized children nodes, include not contained in finishedChildNodes + // delete that related nodes with best-effort pattern + nodesToDelete := finishedChildNodes[index:] + + if len(nodesToDelete) > 0 { + var nodesToCleanup []string + for _, item := range nodesToDelete { + nodesToCleanup = append(nodesToCleanup, item.Name) + } + it.eventRecorder.Event(&node, recorder.RerunBySpecChanged{CleanedChildrenNode: nodesToCleanup}) + + for _, refToDelete := range nodesToDelete { + nodeToDelete := v1alpha1.WorkflowNode{} + err := it.kubeClient.Get(ctx, types.NamespacedName{ + Namespace: node.Namespace, + Name: refToDelete.Name, + }, &nodeToDelete) + if client.IgnoreNotFound(err) != nil { + it.logger.Error(err, "failed to fetch outdated child node", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "child node", fmt.Sprintf("%s/%s", node.Namespace, nodeToDelete.Name)) + } + err = it.kubeClient.Delete(ctx, &nodeToDelete) + if client.IgnoreNotFound(err) != nil { + it.logger.Error(err, "failed to fetch outdated child node", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "child node", fmt.Sprintf("%s/%s", node.Namespace, nodeToDelete.Name)) + } + } + } + break + } + } else { + // spawn child node + taskToStartup = task + break + } } + } else { + it.logger.V(4).Info("serial node has active child/children, skip scheduling", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "active children", activeChildNodes) + } + + if len(taskToStartup) == 0 { + it.logger.Info("no need to spawn new child node", "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name)) + return nil + } - var childrenNames []string - for _, item := range childrenNodes { - childrenNames = append(childrenNames, item.Name) + parentWorkflow := v1alpha1.Workflow{} + err = it.kubeClient.Get(ctx, types.NamespacedName{ + Namespace: node.Namespace, + Name: node.Spec.WorkflowName, + }, &parentWorkflow) + if err != nil { + it.logger.Error(err, "failed to fetch parent workflow", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "workflow name", node.Spec.WorkflowName) + return err + } + // TODO: using ordered id instead of random suffix is better, like StatefulSet, also related to the sorting + childNodes, err := renderNodesByTemplates(&parentWorkflow, &node, taskToStartup) + if err != nil { + it.logger.Error(err, "failed to render children childNodes", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name)) + return err + } + + var childrenNames []string + for _, childNode := range childNodes { + err := it.kubeClient.Create(ctx, childNode) + if err != nil { + it.logger.Error(err, "failed to create child node", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "child node", childNode) + return err } - it.logger.Info("serial node's child created", "key", request.NamespacedName, "children", childrenNames) + childrenNames = append(childrenNames, childNode.Name) } + it.eventRecorder.Event(&node, recorder.NodesCreated{ChildNodes: childrenNames}) + it.logger.Info("serial node spawn new child node", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "child node", childrenNames) - return reconcile.Result{}, nil + return nil } diff --git a/pkg/workflow/controllers/serial_node_reconciler_test.go b/pkg/workflow/controllers/serial_node_reconciler_test.go new file mode 100644 index 0000000000..1b2a7ebf7d --- /dev/null +++ b/pkg/workflow/controllers/serial_node_reconciler_test.go @@ -0,0 +1,249 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controllers + +import ( + "context" + "fmt" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +// integration tests +var _ = Describe("Workflow", func() { + var ns string + BeforeEach(func() { + ctx := context.TODO() + newNs := corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "chaos-mesh-", + }, + Spec: corev1.NamespaceSpec{}, + } + Expect(kubeClient.Create(ctx, &newNs)).To(Succeed()) + ns = newNs.Name + By(fmt.Sprintf("create new namespace %s", ns)) + }) + + AfterEach(func() { + ctx := context.TODO() + nsToDelete := corev1.Namespace{} + Expect(kubeClient.Get(ctx, types.NamespacedName{Name: ns}, &nsToDelete)).To(Succeed()) + Expect(kubeClient.Delete(ctx, &nsToDelete)).To(Succeed()) + By(fmt.Sprintf("cleanup namespace %s", ns)) + }) + + Context("with one serial node", func() { + Context("with one simple serial node", func() { + + It("should spawn all the children one by one", func() { + By("create simple workflow") + ctx := context.TODO() + + networkChaosDuration := 5 * time.Second + networkChaosDurationString := networkChaosDuration.String() + podChaosDuration := 7 * time.Second + podChaosDurationString := podChaosDuration.String() + stressChaosDuration := 9 * time.Second + stressChaosDurationString := stressChaosDuration.String() + + toleratedJitter := 10 * time.Second + + simpleSerialWorkflow := v1alpha1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "simple-serial", + Namespace: ns, + }, + Spec: v1alpha1.WorkflowSpec{ + Entry: "serial", + Templates: []v1alpha1.Template{ + { + Name: "serial", + Type: v1alpha1.TypeSerial, + Children: []string{ + "network-chaos", + "pod-chaos", + "stress-chaos", + }, + }, { + Name: "network-chaos", + Type: v1alpha1.TypeNetworkChaos, + Deadline: &networkChaosDurationString, + EmbedChaos: &v1alpha1.EmbedChaos{ + NetworkChaos: &v1alpha1.NetworkChaosSpec{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{ + "app": "not-exist", + }, + }, + }, + Mode: v1alpha1.AllMode, + }, + Action: v1alpha1.PartitionAction, + }, + }, + }, { + Name: "pod-chaos", + Type: v1alpha1.TypePodChaos, + Deadline: &podChaosDurationString, + EmbedChaos: &v1alpha1.EmbedChaos{ + PodChaos: &v1alpha1.PodChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{ + "app": "not-exist", + }, + }, + }, + Mode: v1alpha1.AllMode, + }, + }, + Action: v1alpha1.PodKillAction, + }, + }, + }, + { + Name: "stress-chaos", + Type: v1alpha1.TypeStressChaos, + Deadline: &stressChaosDurationString, + EmbedChaos: &v1alpha1.EmbedChaos{ + StressChaos: &v1alpha1.StressChaosSpec{ + ContainerSelector: v1alpha1.ContainerSelector{ + PodSelector: v1alpha1.PodSelector{ + Selector: v1alpha1.PodSelectorSpec{ + GenericSelectorSpec: v1alpha1.GenericSelectorSpec{ + Namespaces: []string{ns}, + LabelSelectors: map[string]string{ + "app": "not-exist", + }, + }, + }, + Mode: v1alpha1.AllMode, + }, + }, + Stressors: &v1alpha1.Stressors{ + CPUStressor: &v1alpha1.CPUStressor{ + Stressor: v1alpha1.Stressor{ + Workers: 2, + }, + }}, + }, + }, + }, + }, + }} + Expect(kubeClient.Create(ctx, &simpleSerialWorkflow)).To(Succeed()) + + By("assert that all resource has been created") + + By("assert that entry node created") + Eventually(func() int { + workflowNodeList := v1alpha1.WorkflowNodeList{} + Expect(kubeClient.List(ctx, &workflowNodeList, &client.ListOptions{Namespace: ns})).To(Succeed()) + return len(workflowNodeList.Items) + }, 10*time.Second, time.Second).Should(BeNumerically(">=", 1)) + + By("assert that network chaos has been created") + Eventually(func() bool { + chaosList := v1alpha1.NetworkChaosList{} + Expect(kubeClient.List(ctx, &chaosList, &client.ListOptions{Namespace: ns})).To(Succeed()) + if len(chaosList.Items) != 1 { + return false + } + return strings.HasPrefix(chaosList.Items[0].Name, "network-chaos") + }, toleratedJitter, time.Second).Should(BeTrue()) + + By("assert that network chaos has been deleted") + Eventually(func() int { + chaosList := v1alpha1.NetworkChaosList{} + Expect(kubeClient.List(ctx, &chaosList, &client.ListOptions{Namespace: ns})).To(Succeed()) + return len(chaosList.Items) + }, networkChaosDuration+toleratedJitter, time.Second).Should(BeZero()) + + By("assert that pod chaos has been created") + Eventually(func() bool { + chaosList := v1alpha1.PodChaosList{} + Expect(kubeClient.List(ctx, &chaosList, &client.ListOptions{Namespace: ns})).To(Succeed()) + if len(chaosList.Items) != 1 { + return false + } + return strings.HasPrefix(chaosList.Items[0].Name, "pod-chaos") + }, toleratedJitter, time.Second).Should(BeTrue()) + + By("assert that pod chaos has been deleted") + Eventually(func() int { + chaosList := v1alpha1.PodChaosList{} + Expect(kubeClient.List(ctx, &chaosList, &client.ListOptions{Namespace: ns})).To(Succeed()) + return len(chaosList.Items) + }, podChaosDuration+toleratedJitter, time.Second).Should(BeZero()) + + By("assert that stress chaos has been created") + Eventually(func() bool { + chaosList := v1alpha1.StressChaosList{} + Expect(kubeClient.List(ctx, &chaosList, &client.ListOptions{Namespace: ns})).To(Succeed()) + if len(chaosList.Items) != 1 { + return false + } + return strings.HasPrefix(chaosList.Items[0].Name, "stress-chaos") + }, toleratedJitter, time.Second).Should(BeTrue()) + + By("assert that stress chaos has been deleted") + Eventually(func() int { + chaosList := v1alpha1.StressChaosList{} + Expect(kubeClient.List(ctx, &chaosList, &client.ListOptions{Namespace: ns})).To(Succeed()) + return len(chaosList.Items) + }, stressChaosDuration+toleratedJitter, time.Second).Should(BeZero()) + + By("assert that serial node marked as finished") + Eventually(func() bool { + workflowNodeList := v1alpha1.WorkflowNodeList{} + Expect(kubeClient.List(ctx, &workflowNodeList, &client.ListOptions{Namespace: ns})).To(Succeed()) + if len(workflowNodeList.Items) != 4 { + return false + } + entryFounded := false + var entry *v1alpha1.WorkflowNode = nil + for _, item := range workflowNodeList.Items { + item := item + if item.Spec.Type == v1alpha1.TypeSerial { + entryFounded = true + entry = &item + } + } + if !entryFounded || entry == nil { + return false + } + return ConditionEqualsTo(entry.Status, v1alpha1.ConditionAccomplished, corev1.ConditionTrue) + }, toleratedJitter, time.Second).Should(BeTrue()) + }) + }) + }) +}) diff --git a/pkg/workflow/controllers/statuscheck_reconciler.go b/pkg/workflow/controllers/statuscheck_reconciler.go new file mode 100644 index 0000000000..594d2e6757 --- /dev/null +++ b/pkg/workflow/controllers/statuscheck_reconciler.go @@ -0,0 +1,270 @@ +// Copyright Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controllers + +import ( + "context" + "fmt" + "time" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" +) + +type StatusCheckReconciler struct { + kubeClient client.Client + eventRecorder recorder.ChaosRecorder + logger logr.Logger +} + +func NewStatusCheckReconciler(kubeClient client.Client, eventRecorder recorder.ChaosRecorder, logger logr.Logger) *StatusCheckReconciler { + return &StatusCheckReconciler{kubeClient: kubeClient, eventRecorder: eventRecorder, logger: logger} +} + +func (it *StatusCheckReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { + startTime := time.Now() + defer func() { + it.logger.V(4).Info("finished syncing for status check node", + "node", request.NamespacedName, + "duration", time.Since(startTime), + ) + }() + + node := v1alpha1.WorkflowNode{} + err := it.kubeClient.Get(ctx, request.NamespacedName, &node) + if err != nil { + return reconcile.Result{}, client.IgnoreNotFound(err) + } + if node.Spec.Type != v1alpha1.TypeStatusCheck { + return reconcile.Result{}, nil + } + + it.logger.V(4).Info("resolve status check node", "node", request) + if err := it.syncStatusCheck(ctx, request, node); err != nil { + return reconcile.Result{}, errors.Wrap(err, "sync status check") + } + + updateError := retry.RetryOnConflict(retry.DefaultRetry, it.updateNodeStatus(ctx, request)) + + return reconcile.Result{}, updateError +} + +func (it *StatusCheckReconciler) syncStatusCheck(ctx context.Context, request reconcile.Request, node v1alpha1.WorkflowNode) error { + statusChecks, err := it.fetchChildrenStatusCheck(ctx, node) + if err != nil { + return errors.Wrap(err, "fetch children status check") + } + + if WorkflowNodeFinished(node.Status) { + for _, item := range statusChecks { + // best efforts deletion + item := item + err := it.kubeClient.Delete(ctx, &item) + if client.IgnoreNotFound(err) != nil { + it.logger.Error(err, "failed to delete StatusCheck for workflow status check node", + "namespace", node.Namespace, + "nodeName", node.Name, + "statusCheckName", item.GetName(), + ) + it.eventRecorder.Event(&node, recorder.StatusCheckDeletedFailed{Name: item.GetName()}) + } else { + it.eventRecorder.Event(&node, recorder.StatusCheckDeleted{Name: item.GetName()}) + } + } + return nil + } + + if len(statusChecks) == 0 { + parentWorkflow, err := getParentWorkflow(ctx, it.kubeClient, node) + if err != nil { + return errors.WithStack(err) + } + spawnedStatusCheck, err := it.spawnStatusCheck(ctx, &node, parentWorkflow) + if err != nil { + it.eventRecorder.Event(&node, recorder.StatusCheckCreatedFailed{Name: spawnedStatusCheck.GetName()}) + return errors.Wrap(err, "spawn status check") + } + it.eventRecorder.Event(&node, recorder.StatusCheckCreated{Name: spawnedStatusCheck.GetName()}) + } else if len(statusChecks) > 1 { + var statusCheckToRemove []string + for _, item := range statusChecks[1:] { + statusCheckToRemove = append(statusCheckToRemove, item.GetName()) + } + it.logger.Info("removing duplicated StatusCheck", + "node", request, + "statusCheckToRemove", statusCheckToRemove) + + for _, item := range statusChecks[1:] { + // best efforts deletion + item := item + err := it.kubeClient.Delete(ctx, &item) + if client.IgnoreNotFound(err) != nil { + it.logger.Error(err, "failed to delete StatusCheck for workflow status check node", + "namespace", node.Namespace, + "node", node.Name, + "statusCheck", item.GetName(), + ) + } + } + } else { + it.logger.V(4).Info("do not need spawn or remove StatusCheck") + } + + return nil +} + +func (it *StatusCheckReconciler) updateNodeStatus(ctx context.Context, request reconcile.Request) func() error { + return func() error { + node := v1alpha1.WorkflowNode{} + if err := it.kubeClient.Get(ctx, request.NamespacedName, &node); err != nil { + return client.IgnoreNotFound(err) + } + + statusChecks, err := it.fetchChildrenStatusCheck(ctx, node) + if err != nil { + return client.IgnoreNotFound(err) + } + if len(statusChecks) > 1 { + it.logger.Info("the number of StatusCheck affected by status check node is more than 1", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + "statusCheck", statusChecks, + ) + } else if len(statusChecks) == 0 { + it.logger.Info("the number of StatusCheck affected by status check node is 0", + "node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + ) + return nil + } + + statusCheck := statusChecks[0] + if statusCheck.IsCompleted() { + SetCondition(&node.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionAccomplished, + Status: corev1.ConditionTrue, + Reason: v1alpha1.StatusCheckCompleted, + }) + } else { + SetCondition(&node.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionAccomplished, + Status: corev1.ConditionFalse, + Reason: "", + }) + } + + if node.Spec.AbortWithStatusCheck && needToAbort(statusCheck) { + SetCondition(&node.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionAborted, + Status: corev1.ConditionTrue, + Reason: v1alpha1.StatusCheckNotExceedSuccessThreshold, + }) + } else { + SetCondition(&node.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionAborted, + Status: corev1.ConditionFalse, + Reason: "", + }) + } + + return client.IgnoreNotFound(it.kubeClient.Status().Update(ctx, &node)) + } +} + +func (it *StatusCheckReconciler) fetchChildrenStatusCheck(ctx context.Context, node v1alpha1.WorkflowNode) ([]v1alpha1.StatusCheck, error) { + controlledByThisNode, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{ + MatchLabels: map[string]string{ + v1alpha1.LabelControlledBy: node.Name, + }, + }) + if err != nil { + return nil, errors.Wrap(err, "build label selector") + } + + var childStatusChecks v1alpha1.StatusCheckList + if err = it.kubeClient.List(ctx, &childStatusChecks, &client.ListOptions{LabelSelector: controlledByThisNode}); err != nil { + return nil, errors.Wrap(err, "list child status checks") + } + return childStatusChecks.Items, nil +} + +func (it *StatusCheckReconciler) spawnStatusCheck(ctx context.Context, node *v1alpha1.WorkflowNode, workflow *v1alpha1.Workflow) (*v1alpha1.StatusCheck, error) { + if node.Spec.StatusCheck == nil { + return nil, errors.Errorf("node %s/%s does not contains spec of Target", node.Namespace, node.Name) + } + statusCheckSpec := node.Spec.StatusCheck.DeepCopy() + statusCheck := v1alpha1.StatusCheck{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: fmt.Sprintf("%s-", node.Name), + Namespace: node.Namespace, + Labels: map[string]string{ + v1alpha1.LabelControlledBy: node.Name, + v1alpha1.LabelWorkflow: workflow.Name, + }, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: ApiVersion, + Kind: KindWorkflowNode, + Name: node.Name, + UID: node.UID, + Controller: &isController, + BlockOwnerDeletion: &blockOwnerDeletion, + }, + }, + Finalizers: []string{metav1.FinalizerDeleteDependents}, + }, + Spec: *statusCheckSpec, + } + if err := it.kubeClient.Create(ctx, &statusCheck); err != nil { + return nil, errors.Wrap(err, "create status check") + } + return &statusCheck, nil +} + +func getParentWorkflow(ctx context.Context, kubeClient client.Client, node v1alpha1.WorkflowNode) (*v1alpha1.Workflow, error) { + workflowName, ok := node.Labels[v1alpha1.LabelWorkflow] + if !ok { + return nil, errors.Errorf("node %s/%s does not contains label %s", node.Namespace, node.Name, v1alpha1.LabelWorkflow) + } + parentWorkflow := v1alpha1.Workflow{} + if err := kubeClient.Get(ctx, types.NamespacedName{ + Namespace: node.Namespace, + Name: workflowName, + }, &parentWorkflow); err != nil { + return nil, errors.Wrap(err, "get parent workflow") + } + return &parentWorkflow, nil +} + +func needToAbort(statusCheck v1alpha1.StatusCheck) bool { + if !statusCheck.IsCompleted() { + return false + } + for _, condition := range statusCheck.Status.Conditions { + if condition.Type == v1alpha1.StatusCheckConditionSuccessThresholdExceed && + condition.Status != corev1.ConditionTrue { + return true + } + } + return false +} diff --git a/pkg/workflow/controllers/suite_test.go b/pkg/workflow/controllers/suite_test.go new file mode 100644 index 0000000000..8ddfa2b250 --- /dev/null +++ b/pkg/workflow/controllers/suite_test.go @@ -0,0 +1,113 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controllers + +import ( + "context" + "os" + "path/filepath" + "testing" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "go.uber.org/fx" + "k8s.io/client-go/rest" + "k8s.io/kubectl/pkg/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/types" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/test" + "github.com/chaos-mesh/chaos-mesh/pkg/log" +) + +var app *fx.App +var kubeClient client.Client +var restConfig *rest.Config +var testEnv *envtest.Environment +var setupLog = ctrl.Log.WithName("setup") + +// TestWorkflow runs the integration tests of workflow. +// Before run tests, take a look on ENV KUBEBUILDER_ASSETS, it should be set to /output/bin/kubebuilder/bin +func TestWorkflow(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "workflow suite") +} + +var _ = BeforeSuite(func(ctx SpecContext) { + logf.SetLogger(log.NewZapLoggerWithWriter(GinkgoWriter)) + By("bootstrapping test environment") + t := true + if os.Getenv("USE_EXISTING_CLUSTER") == "true" { + testEnv = &envtest.Environment{ + UseExistingCluster: &t, + } + } else { + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crd", "bases")}, + } + } + + err := v1alpha1.SchemeBuilder.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + restConfig, err = testEnv.Start() + Expect(err).ToNot(HaveOccurred()) + Expect(restConfig).ToNot(BeNil()) + + kubeClient, err = client.New(restConfig, client.Options{Scheme: scheme.Scheme}) + Expect(err).ToNot(HaveOccurred()) + Expect(kubeClient).ToNot(BeNil()) + + rootLogger, err := log.NewDefaultZapLogger() + Expect(err).ToNot(HaveOccurred()) + + app = fx.New( + fx.Options( + fx.Supply(rootLogger), + test.Module, + fx.Supply(restConfig), + types.ChaosObjects, + ), + // only startup workflow related + fx.Invoke(BootstrapWorkflowControllers), + ) + startCtx, cancel := context.WithTimeout(context.Background(), app.StartTimeout()) + defer cancel() + + if err := app.Start(startCtx); err != nil { + setupLog.Error(err, "fail to start manager") + } + Expect(err).ToNot(HaveOccurred()) + +}, NodeTimeout(60*time.Second)) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + stopCtx, cancel := context.WithTimeout(context.Background(), app.StopTimeout()) + defer cancel() + + if err := app.Stop(stopCtx); err != nil { + setupLog.Error(err, "fail to stop manager") + } + err := testEnv.Stop() + Expect(err).ToNot(HaveOccurred()) +}) diff --git a/pkg/workflow/controllers/task_reconciler.go b/pkg/workflow/controllers/task_reconciler.go new file mode 100644 index 0000000000..c54fa93979 --- /dev/null +++ b/pkg/workflow/controllers/task_reconciler.go @@ -0,0 +1,493 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package controllers + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/rest" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" + "github.com/chaos-mesh/chaos-mesh/pkg/workflow/task" + "github.com/chaos-mesh/chaos-mesh/pkg/workflow/task/collector" +) + +type TaskReconciler struct { + *ChildNodesFetcher + kubeClient client.Client + restConfig *rest.Config + eventRecorder recorder.ChaosRecorder + logger logr.Logger +} + +func NewTaskReconciler(kubeClient client.Client, restConfig *rest.Config, eventRecorder recorder.ChaosRecorder, logger logr.Logger) *TaskReconciler { + return &TaskReconciler{ + ChildNodesFetcher: NewChildNodesFetcher(kubeClient, logger), + kubeClient: kubeClient, + restConfig: restConfig, + eventRecorder: eventRecorder, + logger: logger, + } +} + +func (it *TaskReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { + + startTime := time.Now() + defer func() { + it.logger.V(4).Info("Finished syncing for task node", + "node", request.NamespacedName, + "duration", time.Since(startTime), + ) + }() + + node := v1alpha1.WorkflowNode{} + err := it.kubeClient.Get(ctx, request.NamespacedName, &node) + if err != nil { + return reconcile.Result{}, client.IgnoreNotFound(err) + } + + // only resolve task nodes + if node.Spec.Type != v1alpha1.TypeTask { + return reconcile.Result{}, nil + } + + it.logger.V(4).Info("resolve task node", "node", request) + + pods, err := it.FetchPodControlledByThisWorkflowNode(ctx, node) + if err != nil { + return reconcile.Result{}, err + } + + if len(pods) == 0 { + if workflowName, ok := node.Labels[v1alpha1.LabelWorkflow]; ok { + parentWorkflow := v1alpha1.Workflow{} + err := it.kubeClient.Get(ctx, types.NamespacedName{ + Namespace: node.Namespace, + Name: workflowName, + }, &parentWorkflow) + if err != nil { + return reconcile.Result{}, err + } + spawnedPod, err := it.SpawnTaskPod(ctx, &node, &parentWorkflow) + if err != nil { + it.logger.Error(err, "failed to spawn pod for Task Node", "node", request) + it.eventRecorder.Event(&node, recorder.TaskPodSpawnFailed{}) + return reconcile.Result{}, err + } + it.eventRecorder.Event(&node, recorder.TaskPodSpawned{PodName: spawnedPod.Name}) + } else { + return reconcile.Result{}, errors.Errorf("node %s/%s does not contains label %s", node.Namespace, node.Name, v1alpha1.LabelWorkflow) + } + + } + + if len(pods) > 1 { + var podNames []string + for _, pod := range pods { + podNames = append(podNames, fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)) + } + it.logger.Info("unexpected more than 1 pod created by task node, it will pick random one", + "node", request, + "pods", podNames, + "picked", fmt.Sprintf("%s/%s", pods[0].Namespace, pods[0].Name), + ) + } + + // update the status about conditional tasks + if len(pods) > 0 && (pods[0].Status.Phase == corev1.PodFailed || pods[0].Status.Phase == corev1.PodSucceeded) { + evaluated, err := it.conditionalBranchesEvaluated(ctx, node) + if err != nil { + return reconcile.Result{}, err + } + if !evaluated { + it.eventRecorder.Event(&node, recorder.TaskPodPodCompleted{PodName: pods[0].Name}) + // task pod is terminated + updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { + nodeNeedUpdate := v1alpha1.WorkflowNode{} + err := it.kubeClient.Get(ctx, request.NamespacedName, &nodeNeedUpdate) + if err != nil { + return err + } + + if nodeNeedUpdate.Status.ConditionalBranchesStatus == nil { + nodeNeedUpdate.Status.ConditionalBranchesStatus = &v1alpha1.ConditionalBranchesStatus{} + } + + // TODO: update related condition + defaultCollector := collector.DefaultCollector(it.kubeClient, it.restConfig, pods[0].Namespace, pods[0].Name, nodeNeedUpdate.Spec.Task.Container.Name) + env, err := defaultCollector.CollectContext(ctx) + if err != nil { + it.logger.Error(err, "failed to fetch env from task", + "task", fmt.Sprintf("%s/%s", nodeNeedUpdate.Namespace, nodeNeedUpdate.Name), + ) + return err + } + if env != nil { + jsonString, err := json.Marshal(env) + if err != nil { + it.logger.Error(err, "failed to convert env to json", + "task", fmt.Sprintf("%s/%s", nodeNeedUpdate.Namespace, nodeNeedUpdate.Name), + "env", env) + } else { + nodeNeedUpdate.Status.ConditionalBranchesStatus.Context = []string{string(jsonString)} + } + } + + evaluator := task.NewEvaluator(it.logger, it.kubeClient) + evaluateConditionBranches, err := evaluator.EvaluateConditionBranches(nodeNeedUpdate.Spec.ConditionalBranches, env) + if err != nil { + it.logger.Error(err, "failed to evaluate expression", + "task", fmt.Sprintf("%s/%s", nodeNeedUpdate.Namespace, nodeNeedUpdate.Name), + ) + return err + } + + nodeNeedUpdate.Status.ConditionalBranchesStatus.Branches = evaluateConditionBranches + + var selectedBranches []string + for _, item := range evaluateConditionBranches { + if item.EvaluationResult == corev1.ConditionTrue { + selectedBranches = append(selectedBranches, item.Target) + } + } + it.eventRecorder.Event(&nodeNeedUpdate, recorder.ConditionalBranchesSelected{SelectedBranches: selectedBranches}) + + err = it.kubeClient.Status().Update(ctx, &nodeNeedUpdate) + return err + }) + if client.IgnoreNotFound(updateError) != nil { + it.logger.Error(updateError, "failed to update the condition status of task", + "task", request) + } + } + } else { + // task pod is still running or not exists + updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { + nodeNeedUpdate := v1alpha1.WorkflowNode{} + err := it.kubeClient.Get(ctx, request.NamespacedName, &nodeNeedUpdate) + if err != nil { + return err + } + // TODO: update related condition + var branches []v1alpha1.ConditionalBranchStatus + + if nodeNeedUpdate.Status.ConditionalBranchesStatus == nil { + nodeNeedUpdate.Status.ConditionalBranchesStatus = &v1alpha1.ConditionalBranchesStatus{} + } + + for _, conditionalTask := range nodeNeedUpdate.Spec.ConditionalBranches { + branch := v1alpha1.ConditionalBranchStatus{ + Target: conditionalTask.Target, + EvaluationResult: corev1.ConditionUnknown, + } + branches = append(branches, branch) + } + + nodeNeedUpdate.Status.ConditionalBranchesStatus.Branches = branches + + err = it.kubeClient.Status().Update(ctx, &nodeNeedUpdate) + return err + }) + + if client.IgnoreNotFound(updateError) != nil { + it.logger.Error(updateError, "k failed to update the condition status of task", + "task", request) + } + + } + + // update the status about children nodes + var evaluatedNode v1alpha1.WorkflowNode + + err = it.kubeClient.Get(ctx, request.NamespacedName, &evaluatedNode) + if err != nil { + return reconcile.Result{}, err + } + evaluated, err := it.conditionalBranchesEvaluated(ctx, evaluatedNode) + if err != nil { + return reconcile.Result{}, err + } + if evaluated { + err = it.syncChildNodes(ctx, evaluatedNode) + if err != nil { + return reconcile.Result{}, err + } + + // update the status of children workflow nodes + updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { + nodeNeedUpdate := v1alpha1.WorkflowNode{} + err := it.kubeClient.Get(ctx, request.NamespacedName, &nodeNeedUpdate) + if err != nil { + return err + } + var tasks []string + for _, branch := range evaluatedNode.Status.ConditionalBranchesStatus.Branches { + if branch.EvaluationResult == corev1.ConditionTrue { + tasks = append(tasks, branch.Target) + } + } + + activeChildren, finishedChildren, err := it.fetchChildNodes(ctx, nodeNeedUpdate) + if err != nil { + return err + } + + nodeNeedUpdate.Status.FinishedChildren = nil + for _, finishedChild := range finishedChildren { + nodeNeedUpdate.Status.FinishedChildren = append(nodeNeedUpdate.Status.FinishedChildren, + corev1.LocalObjectReference{ + Name: finishedChild.Name, + }) + } + + nodeNeedUpdate.Status.ActiveChildren = nil + for _, activeChild := range activeChildren { + nodeNeedUpdate.Status.ActiveChildren = append(nodeNeedUpdate.Status.ActiveChildren, + corev1.LocalObjectReference{ + Name: activeChild.Name, + }) + } + + // TODO: also check the consistent between spec in task and the spec in child node + evaluated, err := it.conditionalBranchesEvaluated(ctx, nodeNeedUpdate) + if err != nil { + return err + } + if evaluated && len(finishedChildren) == len(tasks) { + if !WorkflowNodeFinished(nodeNeedUpdate.Status) { + it.eventRecorder.Event(&nodeNeedUpdate, recorder.NodeAccomplished{}) + } + SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionAccomplished, + Status: corev1.ConditionTrue, + Reason: "", + }) + } else { + SetCondition(&nodeNeedUpdate.Status, v1alpha1.WorkflowNodeCondition{ + Type: v1alpha1.ConditionAccomplished, + Status: corev1.ConditionFalse, + Reason: "", + }) + } + + return it.kubeClient.Status().Update(ctx, &nodeNeedUpdate) + }) + + return reconcile.Result{}, client.IgnoreNotFound(updateError) + } + + return reconcile.Result{}, nil + +} + +func (it *TaskReconciler) syncChildNodes(ctx context.Context, evaluatedNode v1alpha1.WorkflowNode) error { + + var tasks []string + for _, branch := range evaluatedNode.Status.ConditionalBranchesStatus.Branches { + if branch.EvaluationResult == corev1.ConditionTrue { + tasks = append(tasks, branch.Target) + } + } + + if len(tasks) == 0 { + it.logger.V(4).Info("0 condition of branch in task node is True, Noop", + "node", fmt.Sprintf("%s/%s", evaluatedNode.Namespace, evaluatedNode.Name), + ) + return nil + } + + activeChildNodes, finishedChildNodes, err := it.fetchChildNodes(ctx, evaluatedNode) + if err != nil { + return err + } + existsChildNodes := append(activeChildNodes, finishedChildNodes...) + + var taskNamesOfNodes []string + for _, childNode := range existsChildNodes { + taskNamesOfNodes = append(taskNamesOfNodes, getTaskNameFromGeneratedName(childNode.GetName())) + } + + if len(existsChildNodes) > 0 { + // TODO: check the specific of task and workflow nodes + // the definition of tasks changed, remove all the existed nodes + if len(setDifference(taskNamesOfNodes, tasks)) > 0 || len(setDifference(tasks, taskNamesOfNodes)) > 0 { + // nodesToCleanup is just a vanilla string array + var nodesToCleanup []string + for _, item := range existsChildNodes { + nodesToCleanup = append(nodesToCleanup, item.Name) + } + it.eventRecorder.Event(&evaluatedNode, recorder.RerunBySpecChanged{CleanedChildrenNode: nodesToCleanup}) + + for _, childNode := range existsChildNodes { + // best effort deletion + err := it.kubeClient.Delete(ctx, &childNode) + if err != nil { + it.logger.Error(err, "failed to delete outdated child node", + "node", fmt.Sprintf("%s/%s", evaluatedNode.Namespace, evaluatedNode.Name), + "child node", fmt.Sprintf("%s/%s", childNode.Namespace, childNode.Name), + ) + } + } + } else { + // exactly same, NOOP + return nil + } + } + + parentWorkflow := v1alpha1.Workflow{} + err = it.kubeClient.Get(ctx, types.NamespacedName{ + Namespace: evaluatedNode.Namespace, + Name: evaluatedNode.Spec.WorkflowName, + }, &parentWorkflow) + if err != nil { + it.logger.Error(err, "failed to fetch parent workflow", + "node", fmt.Sprintf("%s/%s", evaluatedNode.Namespace, evaluatedNode.Name), + "workflow name", evaluatedNode.Spec.WorkflowName) + return err + } + + childNodes, err := renderNodesByTemplates(&parentWorkflow, &evaluatedNode, tasks...) + if err != nil { + it.logger.Error(err, "failed to render children childNodes", + "node", fmt.Sprintf("%s/%s", evaluatedNode.Namespace, evaluatedNode.Name)) + return err + } + + // TODO: emit event + var childrenNames []string + for _, childNode := range childNodes { + err := it.kubeClient.Create(ctx, childNode) + if err != nil { + it.logger.Error(err, "failed to create child node", + "node", fmt.Sprintf("%s/%s", evaluatedNode.Namespace, evaluatedNode.Name), + "child node", childNode) + return err + } + childrenNames = append(childrenNames, childNode.Name) + } + it.eventRecorder.Event(&evaluatedNode, recorder.NodesCreated{ChildNodes: childrenNames}) + it.logger.Info("task node spawn new child node", + "node", fmt.Sprintf("%s/%s", evaluatedNode.Namespace, evaluatedNode.Name), + "child node", childrenNames) + + return nil +} + +func (it *TaskReconciler) FetchPodControlledByThisWorkflowNode(ctx context.Context, node v1alpha1.WorkflowNode) ([]corev1.Pod, error) { + controlledByThisNode, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{ + MatchLabels: map[string]string{ + v1alpha1.LabelControlledBy: node.Name, + }, + }) + + if err != nil { + it.logger.Error(err, "failed to build label selector with filtering children workflow node controlled by current node", + "current node", fmt.Sprintf("%s/%s", node.Namespace, node.Name)) + return nil, err + } + + var childPods corev1.PodList + + err = it.kubeClient.List(ctx, &childPods, &client.ListOptions{ + LabelSelector: controlledByThisNode, + }) + if err != nil { + return nil, err + } + return childPods.Items, nil +} + +func (it *TaskReconciler) SpawnTaskPod(ctx context.Context, node *v1alpha1.WorkflowNode, workflow *v1alpha1.Workflow) (*corev1.Pod, error) { + if node.Spec.Task == nil { + return nil, errors.Errorf("node %s/%s does not contains spec of Target", node.Namespace, node.Name) + } + podSpec, err := task.SpawnPodForTask(*node.Spec.Task) + if err != nil { + return nil, err + } + taskPod := corev1.Pod{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: fmt.Sprintf("%s-", node.Name), + Namespace: node.Namespace, + Labels: map[string]string{ + v1alpha1.LabelControlledBy: node.Name, + v1alpha1.LabelWorkflow: workflow.Name, + }, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: ApiVersion, + Kind: KindWorkflowNode, + Name: node.Name, + UID: node.UID, + Controller: &isController, + BlockOwnerDeletion: &blockOwnerDeletion, + }, + }, + Finalizers: []string{metav1.FinalizerDeleteDependents}, + }, + Spec: podSpec, + } + err = it.kubeClient.Create(ctx, &taskPod) + if err != nil { + return nil, err + } + return &taskPod, nil +} + +func (it *TaskReconciler) conditionalBranchesEvaluated(ctx context.Context, node v1alpha1.WorkflowNode) (bool, error) { + // task pod should be completed, it's phase should be PodSucceeded or PodFailed + pods, err := it.FetchPodControlledByThisWorkflowNode(ctx, node) + if err != nil { + return false, err + } + if len(pods) == 0 { + return false, nil + } + if !(pods[0].Status.Phase == corev1.PodFailed || pods[0].Status.Phase == corev1.PodSucceeded) { + return false, nil + } + + // conditional branches status should not be nil + if node.Status.ConditionalBranchesStatus == nil { + return false, nil + } + + // count of status should be equals to branches + if len(node.Spec.ConditionalBranches) != len(node.Status.ConditionalBranchesStatus.Branches) { + return false, nil + } + + // each status should be evaluated + for _, branch := range node.Status.ConditionalBranchesStatus.Branches { + if branch.EvaluationResult == corev1.ConditionUnknown { + return false, nil + } + } + return true, nil +} diff --git a/pkg/workflow/controllers/utils.go b/pkg/workflow/controllers/utils.go index 640fe60b66..0ec289f117 100644 --- a/pkg/workflow/controllers/utils.go +++ b/pkg/workflow/controllers/utils.go @@ -4,17 +4,27 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package controllers import ( + "context" + "fmt" + "sort" + "strings" + + "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" ) @@ -55,3 +65,149 @@ func filterOutCondition(conditions []v1alpha1.WorkflowNodeCondition, except v1al } return newConditions } + +func WorkflowNodeFinished(status v1alpha1.WorkflowNodeStatus) bool { + return ConditionEqualsTo(status, v1alpha1.ConditionAccomplished, corev1.ConditionTrue) || + ConditionEqualsTo(status, v1alpha1.ConditionDeadlineExceed, corev1.ConditionTrue) || + ConditionEqualsTo(status, v1alpha1.ConditionAborted, corev1.ConditionTrue) +} + +func WorkflowAborted(workflow v1alpha1.Workflow) bool { + return workflow.Annotations[v1alpha1.WorkflowAnnotationAbort] == "true" +} + +func SetWorkflowCondition(status *v1alpha1.WorkflowStatus, condition v1alpha1.WorkflowCondition) { + currentCond := GetWorkflowCondition(*status, condition.Type) + if currentCond != nil && currentCond.Status == condition.Status && currentCond.Reason == condition.Reason { + return + } + newConditions := filterOutWorkflowCondition(status.Conditions, condition.Type) + status.Conditions = append(newConditions, condition) +} + +func GetWorkflowCondition(status v1alpha1.WorkflowStatus, conditionType v1alpha1.WorkflowConditionType) *v1alpha1.WorkflowCondition { + for _, item := range status.Conditions { + if item.Type == conditionType { + return &item + } + } + return nil +} + +func WorkflowConditionEqualsTo(status v1alpha1.WorkflowStatus, conditionType v1alpha1.WorkflowConditionType, expected corev1.ConditionStatus) bool { + condition := GetWorkflowCondition(status, conditionType) + if condition == nil { + return false + } + return condition.Status == expected +} + +func filterOutWorkflowCondition(conditions []v1alpha1.WorkflowCondition, except v1alpha1.WorkflowConditionType) []v1alpha1.WorkflowCondition { + var newConditions []v1alpha1.WorkflowCondition + for _, c := range conditions { + if c.Type == except { + continue + } + newConditions = append(newConditions, c) + } + return newConditions +} + +type SortByCreationTimestamp []v1alpha1.WorkflowNode + +func (it SortByCreationTimestamp) Len() int { + return len(it) +} + +func (it SortByCreationTimestamp) Less(i, j int) bool { + return it[j].GetCreationTimestamp().After(it[i].GetCreationTimestamp().Time) +} + +func (it SortByCreationTimestamp) Swap(i, j int) { + it[i], it[j] = it[j], it[i] +} + +type ChildNodesFetcher struct { + kubeClient client.Client + logger logr.Logger +} + +func NewChildNodesFetcher(kubeClient client.Client, logger logr.Logger) *ChildNodesFetcher { + return &ChildNodesFetcher{kubeClient: kubeClient, logger: logger} +} + +// fetchChildNodes will return children workflow nodes controlled by given node +// Should only be used with Parallel and Serial Node +func (it *ChildNodesFetcher) fetchChildNodes(ctx context.Context, node v1alpha1.WorkflowNode) (activeChildNodes []v1alpha1.WorkflowNode, finishedChildNodes []v1alpha1.WorkflowNode, err error) { + childNodes := v1alpha1.WorkflowNodeList{} + controlledByThisNode, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{ + MatchLabels: map[string]string{ + v1alpha1.LabelControlledBy: node.Name, + }, + }) + + if err != nil { + it.logger.Error(err, "failed to build label selector with filtering children workflow node controlled by current node", + "current node", fmt.Sprintf("%s/%s", node.Namespace, node.Name)) + return nil, nil, err + } + + err = it.kubeClient.List(ctx, &childNodes, &client.ListOptions{ + Namespace: node.Namespace, + LabelSelector: controlledByThisNode, + }) + + if err != nil { + it.logger.Error(err, "failed to list children workflow node controlled by current node", + "current node", fmt.Sprintf("%s/%s", node.Namespace, node.Name)) + return nil, nil, err + } + + sortedChildNodes := SortByCreationTimestamp(childNodes.Items) + sort.Sort(sortedChildNodes) + + it.logger.V(4).Info("list children node", "current node", + "current node", fmt.Sprintf("%s/%s", node.Namespace, node.Name), + len(sortedChildNodes), "children", sortedChildNodes) + + var activeChildren []v1alpha1.WorkflowNode + var finishedChildren []v1alpha1.WorkflowNode + + for _, item := range sortedChildNodes { + childNode := item + if WorkflowNodeFinished(childNode.Status) { + finishedChildren = append(finishedChildren, childNode) + } else { + activeChildren = append(activeChildren, childNode) + } + } + return activeChildren, finishedChildren, nil +} + +func getTaskNameFromGeneratedName(generatedNodeName string) string { + index := strings.LastIndex(generatedNodeName, "-") + if index < 0 { + return generatedNodeName + } + return generatedNodeName[:index] +} + +// setDifference return the set of elements which contained in former but not in latter +func setDifference(former []string, latter []string) []string { + var result []string + formerSet := make(map[string]struct{}) + latterSet := make(map[string]struct{}) + + for _, item := range former { + formerSet[item] = struct{}{} + } + for _, item := range latter { + latterSet[item] = struct{}{} + } + for k := range formerSet { + if _, ok := latterSet[k]; !ok { + result = append(result, k) + } + } + return result +} diff --git a/pkg/workflow/controllers/workflow_entry_reconciler.go b/pkg/workflow/controllers/workflow_entry_reconciler.go index 3cee4118b3..fd08b31453 100644 --- a/pkg/workflow/controllers/workflow_entry_reconciler.go +++ b/pkg/workflow/controllers/workflow_entry_reconciler.go @@ -4,41 +4,55 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package controllers import ( "context" + "fmt" + "sort" + "time" "github.com/go-logr/logr" + "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" - "k8s.io/client-go/tools/record" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/util/retry" + "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder" ) // WorkflowEntryReconciler watches on Workflow, creates new Entry Node for created Workflow. type WorkflowEntryReconciler struct { kubeClient client.Client - eventRecorder record.EventRecorder + eventRecorder recorder.ChaosRecorder logger logr.Logger } -func NewWorkflowEntryReconciler(kubeClient client.Client, eventRecorder record.EventRecorder, logger logr.Logger) *WorkflowEntryReconciler { +func NewWorkflowEntryReconciler(kubeClient client.Client, eventRecorder recorder.ChaosRecorder, logger logr.Logger) *WorkflowEntryReconciler { return &WorkflowEntryReconciler{kubeClient: kubeClient, eventRecorder: eventRecorder, logger: logger} } -func (it *WorkflowEntryReconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { - ctx := context.TODO() +func (it *WorkflowEntryReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { + startTime := time.Now() + defer func() { + it.logger.V(4).Info("Finished syncing for workflow", + "node", request.NamespacedName, + "duration", time.Since(startTime), + ) + }() workflow := v1alpha1.Workflow{} err := it.kubeClient.Get(ctx, request.NamespacedName, &workflow) @@ -46,49 +60,203 @@ func (it *WorkflowEntryReconciler) Reconcile(request reconcile.Request) (reconci return reconcile.Result{}, client.IgnoreNotFound(err) } - if workflow.Status.EntryNode == nil { - // This workflow is just created, create entry node - nodes, err := renderNodesByTemplates(&workflow, nil, workflow.Spec.Entry) - if err != nil { - it.logger.Error(err, "failed create entry node", "workflow", workflow.Name, "entry", workflow.Spec.Entry) - it.eventRecorder.Event(&workflow, corev1.EventTypeWarning, v1alpha1.InvalidEntry, "can not find workflow's entry template") - return reconcile.Result{}, nil - } + entryNodes, err := fetchEntryNode(ctx, it.kubeClient, workflow) + if err != nil { + it.logger.Error(err, "failed to list entry nodes of workflow", + "workflow", request.NamespacedName) + return reconcile.Result{}, err + } - if len(nodes) > 1 { - it.logger.V(1).Info("the results of entry nodes are more than 1", "workflow", request.NamespacedName, "nodes", nodes) + if len(entryNodes) == 0 { + func() { + // Not scheduled yet, spawn the entry workflow node + spawnedEntryNode, err := it.spawnEntryNode(ctx, workflow) + if err != nil { + it.eventRecorder.Event(&workflow, recorder.InvalidEntry{ + EntryTemplate: workflow.Spec.Entry, + }) + it.logger.Error(err, "failed to spawn new entry node of workflow", + "workflow", request.NamespacedName, + "entry", workflow.Spec.Entry) + // failed to spawn new entry, but will not break the reconcile, continue to sync status + return + } + it.logger.Info( + "entry node for workflow created", + "workflow", request.NamespacedName, + "entry node", fmt.Sprintf("%s/%s", spawnedEntryNode.Namespace, spawnedEntryNode.Name), + ) + it.eventRecorder.Event(&workflow, recorder.EntryCreated{Entry: spawnedEntryNode.Name}) + }() + } + + if len(entryNodes) > 1 { + var nodeNames []string + for _, node := range entryNodes { + nodeNames = append(nodeNames, node.GetName()) } + it.logger.Info("there are more than 1 entry nodes of workflow, cleaning up except first one", + "workflow", request.NamespacedName, + "entry nodes", nodeNames, + ) + for _, redundantEntryNode := range entryNodes[1:] { + redundantEntryNode := redundantEntryNode + // best effort deletion + err := it.kubeClient.Delete(ctx, &redundantEntryNode) + if err != nil { + it.logger.Error(err, + "failed to delete redundant entry node", + "workflow", request.NamespacedName, + "redundant entry node", fmt.Sprintf("%s/%s", redundantEntryNode.Namespace, redundantEntryNode.Name), + ) + } + } + } - entryNode := nodes[0] - err = it.kubeClient.Create(ctx, entryNode) + // sync the status + updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { + workflowNeedUpdate := v1alpha1.Workflow{} + err := it.kubeClient.Get(ctx, request.NamespacedName, &workflowNeedUpdate) if err != nil { - it.logger.V(1).Info("failed to create workflow nodes") - return reconcile.Result{}, err + it.logger.Error(err, + "failed to fetch the latest state of workflow", + "workflow", request.NamespacedName, + ) + return err } - it.eventRecorder.Event(&workflow, corev1.EventTypeNormal, v1alpha1.EntryCreated, "Entry node created") + entryNodes, err := fetchEntryNode(ctx, it.kubeClient, workflowNeedUpdate) + if err != nil { + it.logger.Error(err, + "failed to list entry nodes of workflow", + "workflow", request.NamespacedName, + ) + return err + } - updateError := retry.RetryOnConflict(retry.DefaultRetry, func() error { - workflowNeedUpdate := v1alpha1.Workflow{} - err := it.kubeClient.Get(ctx, request.NamespacedName, &workflowNeedUpdate) - if err != nil { - return err + if len(entryNodes) > 0 { + if len(entryNodes) > 1 { + var nodeNames []string + for _, node := range entryNodes { + nodeNames = append(nodeNames, node.GetName()) + } + it.logger.Info("there are more than 1 entry nodes of workflow", + "workflow", request.NamespacedName, + "entry nodes", nodeNames, + ) } - workflowNeedUpdate.Status.EntryNode = &entryNode.Name - // TODO: add metav1.FinalizerDeleteDependents for workflowNeedUpdate's finalizer in webhook - err = it.kubeClient.Update(ctx, &workflowNeedUpdate) - if err != nil { - it.logger.Error(err, "failed to update workflowNeedUpdate status") - return err + workflowNeedUpdate.Status.EntryNode = pointer.StringPtr(entryNodes[0].Name) + SetWorkflowCondition(&workflowNeedUpdate.Status, v1alpha1.WorkflowCondition{ + Type: v1alpha1.WorkflowConditionScheduled, + Status: corev1.ConditionTrue, + Reason: "", + }) + + if WorkflowNodeFinished(entryNodes[0].Status) { + SetWorkflowCondition(&workflowNeedUpdate.Status, v1alpha1.WorkflowCondition{ + Type: v1alpha1.WorkflowConditionAccomplished, + Status: corev1.ConditionTrue, + Reason: "", + }) + if workflowNeedUpdate.Status.EndTime == nil { + now := metav1.NewTime(time.Now()) + workflowNeedUpdate.Status.EndTime = &now + it.eventRecorder.Event(&workflow, recorder.WorkflowAccomplished{}) + } + } else { + SetWorkflowCondition(&workflowNeedUpdate.Status, v1alpha1.WorkflowCondition{ + Type: v1alpha1.WorkflowConditionAccomplished, + Status: corev1.ConditionFalse, + Reason: "", + }) + workflowNeedUpdate.Status.EndTime = nil } - return nil - }) + } else { + SetWorkflowCondition(&workflowNeedUpdate.Status, v1alpha1.WorkflowCondition{ + Type: v1alpha1.WorkflowConditionScheduled, + Status: corev1.ConditionFalse, + Reason: "", + }) + SetWorkflowCondition(&workflowNeedUpdate.Status, v1alpha1.WorkflowCondition{ + Type: v1alpha1.WorkflowConditionAccomplished, + Status: corev1.ConditionFalse, + Reason: "", + }) + workflowNeedUpdate.Status.EndTime = nil + } - if updateError != nil { - return reconcile.Result{}, updateError + if workflowNeedUpdate.Status.StartTime == nil { + tmp := metav1.NewTime(startTime) + workflowNeedUpdate.Status.StartTime = &tmp } + err = it.kubeClient.Status().Update(ctx, &workflowNeedUpdate) + if err != nil { + it.logger.Error(err, "failed to update workflowNeedUpdate status") + return err + } + return nil + }) + + return reconcile.Result{}, client.IgnoreNotFound(updateError) +} + +// fetchEntryNode will return the entry workflow node(s) of that workflow, return nil if not exists. +// +// The expected length of result is 1, but due to the reconcile and the inconsistent cache, there might be more than one +// entry nodes created, if should be reported to the upper logic. +func fetchEntryNode(ctx context.Context, kubeClient client.Client, workflow v1alpha1.Workflow) ([]v1alpha1.WorkflowNode, error) { + entryNodesList := v1alpha1.WorkflowNodeList{} + controlledByWorkflow, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{ + MatchLabels: map[string]string{ + v1alpha1.LabelControlledBy: workflow.Name, + }, + }) + if err != nil { + return nil, errors.Wrap(err, "build label selector") + } + + err = kubeClient.List(ctx, &entryNodesList, &client.ListOptions{ + Namespace: workflow.Namespace, + LabelSelector: controlledByWorkflow, + }) + if err != nil { + return nil, errors.Wrapf(err, "list entry workflow node") + } + + sortedEntryNodes := SortByCreationTimestamp(entryNodesList.Items) + sort.Sort(sortedEntryNodes) + + return sortedEntryNodes, nil +} + +// spawnEntryNode will create **one** entry workflow node for current workflow +func (it *WorkflowEntryReconciler) spawnEntryNode(ctx context.Context, workflow v1alpha1.Workflow) (*v1alpha1.WorkflowNode, error) { + // This workflow is just created, create entry node + nodes, err := renderNodesByTemplates(&workflow, nil, workflow.Spec.Entry) + if err != nil { + it.logger.Error(err, "failed create entry node", "workflow", workflow.Name, "entry", workflow.Spec.Entry) + return nil, err + } + + if len(nodes) > 1 { + it.logger.Info("the results of entry nodes are more than 1, will only pick the first one", + "workflow", fmt.Sprintf("%s/%s", workflow.Namespace, workflow.Name), + "nodes", nodes, + ) } - return reconcile.Result{}, nil + + entryNode := nodes[0] + err = it.kubeClient.Create(ctx, entryNode) + if err != nil { + it.logger.Info("failed to create workflow nodes") + return nil, err + } + it.logger.Info("entry workflow node created", + "workflow", fmt.Sprintf("%s/%s", workflow.Namespace, workflow.Name), + "entry node", entryNode.Name, + ) + + return entryNode, nil } diff --git a/pkg/workflow/errors/errors.go b/pkg/workflow/errors/errors.go index 952ddd0b95..aa9e2c210d 100644 --- a/pkg/workflow/errors/errors.go +++ b/pkg/workflow/errors/errors.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package errors diff --git a/pkg/workflow/errors/jsonify_error.go b/pkg/workflow/errors/jsonify_error.go index 94b812caad..c5abbb5b81 100644 --- a/pkg/workflow/errors/jsonify_error.go +++ b/pkg/workflow/errors/jsonify_error.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package errors diff --git a/pkg/workflow/errors/no_more_template_in_serial_template.go b/pkg/workflow/errors/no_more_template_in_serial_template.go index 08edc1d7ac..924c66d603 100644 --- a/pkg/workflow/errors/no_more_template_in_serial_template.go +++ b/pkg/workflow/errors/no_more_template_in_serial_template.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package errors diff --git a/pkg/workflow/errors/no_such_template.go b/pkg/workflow/errors/no_such_template.go index bb50cc5a60..e6f25e553d 100644 --- a/pkg/workflow/errors/no_such_template.go +++ b/pkg/workflow/errors/no_such_template.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package errors diff --git a/pkg/workflow/errors/no_such_tree_node.go b/pkg/workflow/errors/no_such_tree_node.go index acb4d58eb3..0e557fdc91 100644 --- a/pkg/workflow/errors/no_such_tree_node.go +++ b/pkg/workflow/errors/no_such_tree_node.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package errors diff --git a/pkg/workflow/errors/parse_template_failed.go b/pkg/workflow/errors/parse_template_failed.go index dc699f0d4e..9458257639 100644 --- a/pkg/workflow/errors/parse_template_failed.go +++ b/pkg/workflow/errors/parse_template_failed.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package errors diff --git a/pkg/workflow/mock/model/mock_node/mock_node.go b/pkg/workflow/mock/model/mock_node/mock_node.go deleted file mode 100644 index 55bcad4948..0000000000 --- a/pkg/workflow/mock/model/mock_node/mock_node.go +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by MockGen. DO NOT EDIT. -// Source: ./model/node/node.go - -// Package mock_node is a generated GoMock package. -package mock_node - -import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - - node "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/node" -) - -// MockNode is a mock of Node interface. -type MockNode struct { - ctrl *gomock.Controller - recorder *MockNodeMockRecorder -} - -// MockNodeMockRecorder is the mock recorder for MockNode. -type MockNodeMockRecorder struct { - mock *MockNode -} - -// NewMockNode creates a new mock instance. -func NewMockNode(ctrl *gomock.Controller) *MockNode { - mock := &MockNode{ctrl: ctrl} - mock.recorder = &MockNodeMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockNode) EXPECT() *MockNodeMockRecorder { - return m.recorder -} - -// Name mocks base method. -func (m *MockNode) Name() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) - return ret0 -} - -// Name indicates an expected call of Name. -func (mr *MockNodeMockRecorder) Name() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockNode)(nil).Name)) -} - -// NodePhase mocks base method. -func (m *MockNode) NodePhase() node.NodePhase { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NodePhase") - ret0, _ := ret[0].(node.NodePhase) - return ret0 -} - -// NodePhase indicates an expected call of NodePhase. -func (mr *MockNodeMockRecorder) NodePhase() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodePhase", reflect.TypeOf((*MockNode)(nil).NodePhase)) -} - -// ParentNodeName mocks base method. -func (m *MockNode) ParentNodeName() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParentNodeName") - ret0, _ := ret[0].(string) - return ret0 -} - -// ParentNodeName indicates an expected call of ParentNodeName. -func (mr *MockNodeMockRecorder) ParentNodeName() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParentNodeName", reflect.TypeOf((*MockNode)(nil).ParentNodeName)) -} - -// TemplateName mocks base method. -func (m *MockNode) TemplateName() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TemplateName") - ret0, _ := ret[0].(string) - return ret0 -} - -// TemplateName indicates an expected call of TemplateName. -func (mr *MockNodeMockRecorder) TemplateName() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TemplateName", reflect.TypeOf((*MockNode)(nil).TemplateName)) -} - -// MockNodeTreeNode is a mock of NodeTreeNode interface. -type MockNodeTreeNode struct { - ctrl *gomock.Controller - recorder *MockNodeTreeNodeMockRecorder -} - -// MockNodeTreeNodeMockRecorder is the mock recorder for MockNodeTreeNode. -type MockNodeTreeNodeMockRecorder struct { - mock *MockNodeTreeNode -} - -// NewMockNodeTreeNode creates a new mock instance. -func NewMockNodeTreeNode(ctrl *gomock.Controller) *MockNodeTreeNode { - mock := &MockNodeTreeNode{ctrl: ctrl} - mock.recorder = &MockNodeTreeNodeMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockNodeTreeNode) EXPECT() *MockNodeTreeNodeMockRecorder { - return m.recorder -} - -// Children mocks base method. -func (m *MockNodeTreeNode) Children() node.NodeTreeChildren { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Children") - ret0, _ := ret[0].(node.NodeTreeChildren) - return ret0 -} - -// Children indicates an expected call of Children. -func (mr *MockNodeTreeNodeMockRecorder) Children() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Children", reflect.TypeOf((*MockNodeTreeNode)(nil).Children)) -} - -// FetchNodeByName mocks base method. -func (m *MockNodeTreeNode) FetchNodeByName(nodeName string) (node.NodeTreeNode, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FetchNodeByName", nodeName) - ret0, _ := ret[0].(node.NodeTreeNode) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FetchNodeByName indicates an expected call of FetchNodeByName. -func (mr *MockNodeTreeNodeMockRecorder) FetchNodeByName(nodeName interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchNodeByName", reflect.TypeOf((*MockNodeTreeNode)(nil).FetchNodeByName), nodeName) -} - -// Name mocks base method. -func (m *MockNodeTreeNode) Name() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) - return ret0 -} - -// Name indicates an expected call of Name. -func (mr *MockNodeTreeNodeMockRecorder) Name() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockNodeTreeNode)(nil).Name)) -} - -// TemplateName mocks base method. -func (m *MockNodeTreeNode) TemplateName() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TemplateName") - ret0, _ := ret[0].(string) - return ret0 -} - -// TemplateName indicates an expected call of TemplateName. -func (mr *MockNodeTreeNodeMockRecorder) TemplateName() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TemplateName", reflect.TypeOf((*MockNodeTreeNode)(nil).TemplateName)) -} - -// MockNodeTreeChildren is a mock of NodeTreeChildren interface. -type MockNodeTreeChildren struct { - ctrl *gomock.Controller - recorder *MockNodeTreeChildrenMockRecorder -} - -// MockNodeTreeChildrenMockRecorder is the mock recorder for MockNodeTreeChildren. -type MockNodeTreeChildrenMockRecorder struct { - mock *MockNodeTreeChildren -} - -// NewMockNodeTreeChildren creates a new mock instance. -func NewMockNodeTreeChildren(ctrl *gomock.Controller) *MockNodeTreeChildren { - mock := &MockNodeTreeChildren{ctrl: ctrl} - mock.recorder = &MockNodeTreeChildrenMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockNodeTreeChildren) EXPECT() *MockNodeTreeChildrenMockRecorder { - return m.recorder -} - -// GetAllChildrenNode mocks base method. -func (m *MockNodeTreeChildren) GetAllChildrenNode() []node.NodeTreeNode { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAllChildrenNode") - ret0, _ := ret[0].([]node.NodeTreeNode) - return ret0 -} - -// GetAllChildrenNode indicates an expected call of GetAllChildrenNode. -func (mr *MockNodeTreeChildrenMockRecorder) GetAllChildrenNode() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllChildrenNode", reflect.TypeOf((*MockNodeTreeChildren)(nil).GetAllChildrenNode)) -} - -// Length mocks base method. -func (m *MockNodeTreeChildren) Length() int { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Length") - ret0, _ := ret[0].(int) - return ret0 -} - -// Length indicates an expected call of Length. -func (mr *MockNodeTreeChildrenMockRecorder) Length() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Length", reflect.TypeOf((*MockNodeTreeChildren)(nil).Length)) -} diff --git a/pkg/workflow/mock/model/mock_template/mock_parallel.go b/pkg/workflow/mock/model/mock_template/mock_parallel.go deleted file mode 100644 index 43c2995e1b..0000000000 --- a/pkg/workflow/mock/model/mock_template/mock_parallel.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by MockGen. DO NOT EDIT. -// Source: ./model/template/parallel.go - -// Package mock_template is a generated GoMock package. -package mock_template - -import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - - template "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/template" -) - -// MockParallelTemplate is a mock of ParallelTemplate interface. -type MockParallelTemplate struct { - ctrl *gomock.Controller - recorder *MockParallelTemplateMockRecorder -} - -// MockParallelTemplateMockRecorder is the mock recorder for MockParallelTemplate. -type MockParallelTemplateMockRecorder struct { - mock *MockParallelTemplate -} - -// NewMockParallelTemplate creates a new mock instance. -func NewMockParallelTemplate(ctrl *gomock.Controller) *MockParallelTemplate { - mock := &MockParallelTemplate{ctrl: ctrl} - mock.recorder = &MockParallelTemplateMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockParallelTemplate) EXPECT() *MockParallelTemplateMockRecorder { - return m.recorder -} - -// Name mocks base method. -func (m *MockParallelTemplate) Name() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) - return ret0 -} - -// Name indicates an expected call of Name. -func (mr *MockParallelTemplateMockRecorder) Name() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockParallelTemplate)(nil).Name)) -} - -// ParallelChildrenList mocks base method. -func (m *MockParallelTemplate) ParallelChildrenList() []template.Template { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParallelChildrenList") - ret0, _ := ret[0].([]template.Template) - return ret0 -} - -// ParallelChildrenList indicates an expected call of ParallelChildrenList. -func (mr *MockParallelTemplateMockRecorder) ParallelChildrenList() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParallelChildrenList", reflect.TypeOf((*MockParallelTemplate)(nil).ParallelChildrenList)) -} - -// TemplateType mocks base method. -func (m *MockParallelTemplate) TemplateType() template.TemplateType { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TemplateType") - ret0, _ := ret[0].(template.TemplateType) - return ret0 -} - -// TemplateType indicates an expected call of TemplateType. -func (mr *MockParallelTemplateMockRecorder) TemplateType() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TemplateType", reflect.TypeOf((*MockParallelTemplate)(nil).TemplateType)) -} diff --git a/pkg/workflow/mock/model/mock_template/mock_serial.go b/pkg/workflow/mock/model/mock_template/mock_serial.go deleted file mode 100644 index f7e5cad503..0000000000 --- a/pkg/workflow/mock/model/mock_template/mock_serial.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by MockGen. DO NOT EDIT. -// Source: ./model/template/serial.go - -// Package mock_template is a generated GoMock package. -package mock_template - -import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - - template "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/template" -) - -// MockSerialTemplate is a mock of SerialTemplate interface. -type MockSerialTemplate struct { - ctrl *gomock.Controller - recorder *MockSerialTemplateMockRecorder -} - -// MockSerialTemplateMockRecorder is the mock recorder for MockSerialTemplate. -type MockSerialTemplateMockRecorder struct { - mock *MockSerialTemplate -} - -// NewMockSerialTemplate creates a new mock instance. -func NewMockSerialTemplate(ctrl *gomock.Controller) *MockSerialTemplate { - mock := &MockSerialTemplate{ctrl: ctrl} - mock.recorder = &MockSerialTemplateMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockSerialTemplate) EXPECT() *MockSerialTemplateMockRecorder { - return m.recorder -} - -// Name mocks base method. -func (m *MockSerialTemplate) Name() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) - return ret0 -} - -// Name indicates an expected call of Name. -func (mr *MockSerialTemplateMockRecorder) Name() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockSerialTemplate)(nil).Name)) -} - -// SerialChildrenList mocks base method. -func (m *MockSerialTemplate) SerialChildrenList() []string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SerialChildrenList") - ret0, _ := ret[0].([]string) - return ret0 -} - -// SerialChildrenList indicates an expected call of SerialChildrenList. -func (mr *MockSerialTemplateMockRecorder) SerialChildrenList() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SerialChildrenList", reflect.TypeOf((*MockSerialTemplate)(nil).SerialChildrenList)) -} - -// TemplateType mocks base method. -func (m *MockSerialTemplate) TemplateType() template.TemplateType { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TemplateType") - ret0, _ := ret[0].(template.TemplateType) - return ret0 -} - -// TemplateType indicates an expected call of TemplateType. -func (mr *MockSerialTemplateMockRecorder) TemplateType() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TemplateType", reflect.TypeOf((*MockSerialTemplate)(nil).TemplateType)) -} diff --git a/pkg/workflow/mock/model/mock_template/mock_suspend.go b/pkg/workflow/mock/model/mock_template/mock_suspend.go deleted file mode 100644 index 0592e9b12a..0000000000 --- a/pkg/workflow/mock/model/mock_template/mock_suspend.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by MockGen. DO NOT EDIT. -// Source: ./model/template/suspend.go - -// Package mock_template is a generated GoMock package. -package mock_template - -import ( - reflect "reflect" - time "time" - - gomock "github.com/golang/mock/gomock" - - template "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/template" -) - -// MockSuspendTemplate is a mock of SuspendTemplate interface. -type MockSuspendTemplate struct { - ctrl *gomock.Controller - recorder *MockSuspendTemplateMockRecorder -} - -// MockSuspendTemplateMockRecorder is the mock recorder for MockSuspendTemplate. -type MockSuspendTemplateMockRecorder struct { - mock *MockSuspendTemplate -} - -// NewMockSuspendTemplate creates a new mock instance. -func NewMockSuspendTemplate(ctrl *gomock.Controller) *MockSuspendTemplate { - mock := &MockSuspendTemplate{ctrl: ctrl} - mock.recorder = &MockSuspendTemplateMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockSuspendTemplate) EXPECT() *MockSuspendTemplateMockRecorder { - return m.recorder -} - -// Duration mocks base method. -func (m *MockSuspendTemplate) Duration() (time.Duration, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Duration") - ret0, _ := ret[0].(time.Duration) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Duration indicates an expected call of Duration. -func (mr *MockSuspendTemplateMockRecorder) Duration() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Duration", reflect.TypeOf((*MockSuspendTemplate)(nil).Duration)) -} - -// Name mocks base method. -func (m *MockSuspendTemplate) Name() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) - return ret0 -} - -// Name indicates an expected call of Name. -func (mr *MockSuspendTemplateMockRecorder) Name() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockSuspendTemplate)(nil).Name)) -} - -// TemplateType mocks base method. -func (m *MockSuspendTemplate) TemplateType() template.TemplateType { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TemplateType") - ret0, _ := ret[0].(template.TemplateType) - return ret0 -} - -// TemplateType indicates an expected call of TemplateType. -func (mr *MockSuspendTemplateMockRecorder) TemplateType() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TemplateType", reflect.TypeOf((*MockSuspendTemplate)(nil).TemplateType)) -} diff --git a/pkg/workflow/mock/model/mock_template/mock_task.go b/pkg/workflow/mock/model/mock_template/mock_task.go deleted file mode 100644 index 3bf54d436b..0000000000 --- a/pkg/workflow/mock/model/mock_template/mock_task.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by MockGen. DO NOT EDIT. -// Source: ./model/template/task.go - -// Package mock_template is a generated GoMock package. -package mock_template - -import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - - template "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/template" -) - -// MockTaskTemplate is a mock of TaskTemplate interface. -type MockTaskTemplate struct { - ctrl *gomock.Controller - recorder *MockTaskTemplateMockRecorder -} - -// MockTaskTemplateMockRecorder is the mock recorder for MockTaskTemplate. -type MockTaskTemplateMockRecorder struct { - mock *MockTaskTemplate -} - -// NewMockTaskTemplate creates a new mock instance. -func NewMockTaskTemplate(ctrl *gomock.Controller) *MockTaskTemplate { - mock := &MockTaskTemplate{ctrl: ctrl} - mock.recorder = &MockTaskTemplateMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockTaskTemplate) EXPECT() *MockTaskTemplateMockRecorder { - return m.recorder -} - -// AllTemplates mocks base method. -func (m *MockTaskTemplate) AllTemplates() []template.Template { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AllTemplates") - ret0, _ := ret[0].([]template.Template) - return ret0 -} - -// AllTemplates indicates an expected call of AllTemplates. -func (mr *MockTaskTemplateMockRecorder) AllTemplates() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllTemplates", reflect.TypeOf((*MockTaskTemplate)(nil).AllTemplates)) -} - -// Name mocks base method. -func (m *MockTaskTemplate) Name() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) - return ret0 -} - -// Name indicates an expected call of Name. -func (mr *MockTaskTemplateMockRecorder) Name() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockTaskTemplate)(nil).Name)) -} - -// TemplateType mocks base method. -func (m *MockTaskTemplate) TemplateType() template.TemplateType { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TemplateType") - ret0, _ := ret[0].(template.TemplateType) - return ret0 -} - -// TemplateType indicates an expected call of TemplateType. -func (mr *MockTaskTemplateMockRecorder) TemplateType() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TemplateType", reflect.TypeOf((*MockTaskTemplate)(nil).TemplateType)) -} diff --git a/pkg/workflow/mock/model/mock_template/mock_template.go b/pkg/workflow/mock/model/mock_template/mock_template.go deleted file mode 100644 index 03f3dee184..0000000000 --- a/pkg/workflow/mock/model/mock_template/mock_template.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by MockGen. DO NOT EDIT. -// Source: ./model/template/template.go - -// Package mock_template is a generated GoMock package. -package mock_template - -import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - - template "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/template" -) - -// MockTemplate is a mock of Template interface. -type MockTemplate struct { - ctrl *gomock.Controller - recorder *MockTemplateMockRecorder -} - -// MockTemplateMockRecorder is the mock recorder for MockTemplate. -type MockTemplateMockRecorder struct { - mock *MockTemplate -} - -// NewMockTemplate creates a new mock instance. -func NewMockTemplate(ctrl *gomock.Controller) *MockTemplate { - mock := &MockTemplate{ctrl: ctrl} - mock.recorder = &MockTemplateMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockTemplate) EXPECT() *MockTemplateMockRecorder { - return m.recorder -} - -// Name mocks base method. -func (m *MockTemplate) Name() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) - return ret0 -} - -// Name indicates an expected call of Name. -func (mr *MockTemplateMockRecorder) Name() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockTemplate)(nil).Name)) -} - -// TemplateType mocks base method. -func (m *MockTemplate) TemplateType() template.TemplateType { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TemplateType") - ret0, _ := ret[0].(template.TemplateType) - return ret0 -} - -// TemplateType indicates an expected call of TemplateType. -func (mr *MockTemplateMockRecorder) TemplateType() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TemplateType", reflect.TypeOf((*MockTemplate)(nil).TemplateType)) -} diff --git a/pkg/workflow/mock/model/mock_workflow/mock_workflow.go b/pkg/workflow/mock/model/mock_workflow/mock_workflow.go deleted file mode 100644 index e746713db6..0000000000 --- a/pkg/workflow/mock/model/mock_workflow/mock_workflow.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by MockGen. DO NOT EDIT. -// Source: ./model/workflow/workflow.go - -// Package mock_workflow is a generated GoMock package. -package mock_workflow - -import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - - node "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/node" - template "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/template" - workflow "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/workflow" -) - -// MockWorkflowSpec is a mock of WorkflowSpec interface. -type MockWorkflowSpec struct { - ctrl *gomock.Controller - recorder *MockWorkflowSpecMockRecorder -} - -// MockWorkflowSpecMockRecorder is the mock recorder for MockWorkflowSpec. -type MockWorkflowSpecMockRecorder struct { - mock *MockWorkflowSpec -} - -// NewMockWorkflowSpec creates a new mock instance. -func NewMockWorkflowSpec(ctrl *gomock.Controller) *MockWorkflowSpec { - mock := &MockWorkflowSpec{ctrl: ctrl} - mock.recorder = &MockWorkflowSpecMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockWorkflowSpec) EXPECT() *MockWorkflowSpecMockRecorder { - return m.recorder -} - -// Entry mocks base method. -func (m *MockWorkflowSpec) Entry() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Entry") - ret0, _ := ret[0].(string) - return ret0 -} - -// Entry indicates an expected call of Entry. -func (mr *MockWorkflowSpecMockRecorder) Entry() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Entry", reflect.TypeOf((*MockWorkflowSpec)(nil).Entry)) -} - -// FetchTemplateByName mocks base method. -func (m *MockWorkflowSpec) FetchTemplateByName(templateName string) (template.Template, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FetchTemplateByName", templateName) - ret0, _ := ret[0].(template.Template) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FetchTemplateByName indicates an expected call of FetchTemplateByName. -func (mr *MockWorkflowSpecMockRecorder) FetchTemplateByName(templateName interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchTemplateByName", reflect.TypeOf((*MockWorkflowSpec)(nil).FetchTemplateByName), templateName) -} - -// Name mocks base method. -func (m *MockWorkflowSpec) Name() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) - return ret0 -} - -// Name indicates an expected call of Name. -func (mr *MockWorkflowSpecMockRecorder) Name() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockWorkflowSpec)(nil).Name)) -} - -// MockWorkflowStatus is a mock of WorkflowStatus interface. -type MockWorkflowStatus struct { - ctrl *gomock.Controller - recorder *MockWorkflowStatusMockRecorder -} - -// MockWorkflowStatusMockRecorder is the mock recorder for MockWorkflowStatus. -type MockWorkflowStatusMockRecorder struct { - mock *MockWorkflowStatus -} - -// NewMockWorkflowStatus creates a new mock instance. -func NewMockWorkflowStatus(ctrl *gomock.Controller) *MockWorkflowStatus { - mock := &MockWorkflowStatus{ctrl: ctrl} - mock.recorder = &MockWorkflowStatusMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockWorkflowStatus) EXPECT() *MockWorkflowStatusMockRecorder { - return m.recorder -} - -// FetchNodeByName mocks base method. -func (m *MockWorkflowStatus) FetchNodeByName(nodeName string) (node.Node, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FetchNodeByName", nodeName) - ret0, _ := ret[0].(node.Node) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FetchNodeByName indicates an expected call of FetchNodeByName. -func (mr *MockWorkflowStatusMockRecorder) FetchNodeByName(nodeName interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchNodeByName", reflect.TypeOf((*MockWorkflowStatus)(nil).FetchNodeByName), nodeName) -} - -// Nodes mocks base method. -func (m *MockWorkflowStatus) Nodes() []node.Node { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Nodes") - ret0, _ := ret[0].([]node.Node) - return ret0 -} - -// Nodes indicates an expected call of Nodes. -func (mr *MockWorkflowStatusMockRecorder) Nodes() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Nodes", reflect.TypeOf((*MockWorkflowStatus)(nil).Nodes)) -} - -// NodesMap mocks base method. -func (m *MockWorkflowStatus) NodesMap() map[string]node.Node { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NodesMap") - ret0, _ := ret[0].(map[string]node.Node) - return ret0 -} - -// NodesMap indicates an expected call of NodesMap. -func (mr *MockWorkflowStatusMockRecorder) NodesMap() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodesMap", reflect.TypeOf((*MockWorkflowStatus)(nil).NodesMap)) -} - -// NodesTree mocks base method. -func (m *MockWorkflowStatus) NodesTree() (node.NodeTreeNode, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NodesTree") - ret0, _ := ret[0].(node.NodeTreeNode) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// NodesTree indicates an expected call of NodesTree. -func (mr *MockWorkflowStatusMockRecorder) NodesTree() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodesTree", reflect.TypeOf((*MockWorkflowStatus)(nil).NodesTree)) -} - -// Phase mocks base method. -func (m *MockWorkflowStatus) Phase() workflow.WorkflowPhase { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Phase") - ret0, _ := ret[0].(workflow.WorkflowPhase) - return ret0 -} - -// Phase indicates an expected call of Phase. -func (mr *MockWorkflowStatusMockRecorder) Phase() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Phase", reflect.TypeOf((*MockWorkflowStatus)(nil).Phase)) -} - -// WorkflowSpecName mocks base method. -func (m *MockWorkflowStatus) WorkflowSpecName() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WorkflowSpecName") - ret0, _ := ret[0].(string) - return ret0 -} - -// WorkflowSpecName indicates an expected call of WorkflowSpecName. -func (mr *MockWorkflowStatusMockRecorder) WorkflowSpecName() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WorkflowSpecName", reflect.TypeOf((*MockWorkflowStatus)(nil).WorkflowSpecName)) -} diff --git a/pkg/workflow/mock_generate.go b/pkg/workflow/mock_generate.go deleted file mode 100644 index 0d49a8896b..0000000000 --- a/pkg/workflow/mock_generate.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package workflow - -//go:generate rm -rf ./mock -//go:generate mockgen -source ./model/workflow/workflow.go -copyright_file ../../hack/boilerplate/boilerplate.gomock.txt -destination ./mock/model/mock_workflow/mock_workflow.go - -//go:generate mockgen -source ./model/node/node.go -copyright_file ../../hack/boilerplate/boilerplate.gomock.txt -destination ./mock/model/mock_node/mock_node.go - -//go:generate mockgen -source ./model/template/template.go -copyright_file ../../hack/boilerplate/boilerplate.gomock.txt -destination ./mock/model/mock_template/mock_template.go -//go:generate mockgen -source ./model/template/serial.go -copyright_file ../../hack/boilerplate/boilerplate.gomock.txt -aux_files github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/template=./model/template/template.go -destination ./mock/model/mock_template/mock_serial.go -//go:generate mockgen -source ./model/template/task.go -copyright_file ../../hack/boilerplate/boilerplate.gomock.txt -aux_files github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/template=./model/template/template.go -destination ./mock/model/mock_template/mock_task.go -//go:generate mockgen -source ./model/template/parallel.go -copyright_file ../../hack/boilerplate/boilerplate.gomock.txt -aux_files github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/template=./model/template/template.go -destination ./mock/model/mock_template/mock_parallel.go -//go:generate mockgen -source ./model/template/suspend.go -copyright_file ../../hack/boilerplate/boilerplate.gomock.txt -aux_files github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/template=./model/template/template.go -destination ./mock/model/mock_template/mock_suspend.go diff --git a/pkg/workflow/model/doc.go b/pkg/workflow/model/doc.go deleted file mode 100644 index 1e97968cfb..0000000000 --- a/pkg/workflow/model/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package model the basic workflow interface and structs in this package. -package model diff --git a/pkg/workflow/model/node/node.go b/pkg/workflow/model/node/node.go deleted file mode 100644 index 8e6bb37e5b..0000000000 --- a/pkg/workflow/model/node/node.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package node - -type NodePhase string - -const ( - Init NodePhase = "Init" - WaitingForSchedule NodePhase = "WaitingForSchedule" - Running NodePhase = "Running" - // It means current node is not changing something, but waiting for some signal. It's still alive. - // It's the most common state for most of Node which referenced Template contains duration or deadline. - Holding NodePhase = "Holding" - Succeed NodePhase = "Succeed" - Failed NodePhase = "Failed" - WaitingForChild NodePhase = "WaitingForChild" - Evaluating NodePhase = "Evaluating" -) - -type Node interface { - Name() string - NodePhase() NodePhase - ParentNodeName() string - TemplateName() string -} - -// FIXME: remove this interface, it's should belongs to node status -type NodeTreeNode interface { - Name() string - TemplateName() string - Children() NodeTreeChildren - // Find node by name, might return itself, or find from children nodes recursively - FetchNodeByName(nodeName string) (NodeTreeNode, error) -} - -type NodeTreeChildren interface { - Length() int - GetAllChildrenNode() []NodeTreeNode -} diff --git a/pkg/workflow/model/template/network_chaos.go b/pkg/workflow/model/template/network_chaos.go deleted file mode 100644 index f70229ead7..0000000000 --- a/pkg/workflow/model/template/network_chaos.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package template - -import ( - "time" - - chaosmeshv1alph1 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/workflow/errors" -) - -type NetworkChaosTemplate interface { - Template - ChaosNamePrefix() string - NetworkChaosSpec() chaosmeshv1alph1.NetworkChaosSpec - Duration() (time.Duration, error) -} - -func ParseNetworkChaosTemplate(raw interface{}) (NetworkChaosTemplate, error) { - op := "template.NetworkChaosTemplate" - if target, ok := raw.(NetworkChaosTemplate); ok { - return target, nil - } - return nil, errors.NewParseSerialTemplateFailedError(op, raw) -} diff --git a/pkg/workflow/model/template/parallel.go b/pkg/workflow/model/template/parallel.go deleted file mode 100644 index abffc89a16..0000000000 --- a/pkg/workflow/model/template/parallel.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package template - -type ParallelTemplate interface { - Template - ParallelChildrenList() []Template -} - -func ParseParallelTemplate(raw interface{}) (ParallelTemplate, error) { - panic("unimplemented") -} diff --git a/pkg/workflow/model/template/pod_chaos.go b/pkg/workflow/model/template/pod_chaos.go deleted file mode 100644 index 06be7b5b6d..0000000000 --- a/pkg/workflow/model/template/pod_chaos.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package template - -import ( - "time" - - chaosmeshv1alph1 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/workflow/errors" -) - -type PodChaosTemplate interface { - Template - ChaosNamePrefix() string - PodChaosSpec() chaosmeshv1alph1.PodChaosSpec - Duration() (time.Duration, error) -} - -func ParsePodChaosTemplate(raw interface{}) (PodChaosTemplate, error) { - op := "template.ParsePodChaosTemplate" - if target, ok := raw.(PodChaosTemplate); ok { - return target, nil - } - return nil, errors.NewParseSerialTemplateFailedError(op, raw) -} diff --git a/pkg/workflow/model/template/serial.go b/pkg/workflow/model/template/serial.go deleted file mode 100644 index 6266e76be7..0000000000 --- a/pkg/workflow/model/template/serial.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package template - -import "github.com/chaos-mesh/chaos-mesh/pkg/workflow/errors" - -type SerialTemplate interface { - Template - // TODO: make it return only template name - SerialChildrenList() []string -} - -func ParseSerialTemplate(raw interface{}) (SerialTemplate, error) { - op := "template.ParseSerialTemplate" - if target, ok := raw.(SerialTemplate); ok { - return target, nil - } - return nil, errors.NewParseSerialTemplateFailedError(op, raw) -} diff --git a/pkg/workflow/model/template/suspend.go b/pkg/workflow/model/template/suspend.go deleted file mode 100644 index c653e0381a..0000000000 --- a/pkg/workflow/model/template/suspend.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package template - -import ( - "time" - - "github.com/chaos-mesh/chaos-mesh/pkg/workflow/errors" -) - -type SuspendTemplate interface { - Template - Duration() (time.Duration, error) -} - -func ParseSuspendTemplate(raw interface{}) (SuspendTemplate, error) { - op := "template.ParseSuspendTemplate" - if target, ok := raw.(SuspendTemplate); ok { - return target, nil - } - return nil, errors.NewParseSerialTemplateFailedError(op, raw) -} diff --git a/pkg/workflow/model/template/task.go b/pkg/workflow/model/template/task.go deleted file mode 100644 index dc4f4dc34d..0000000000 --- a/pkg/workflow/model/template/task.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package template - -type TaskTemplate interface { - Template - AllTemplates() []Template -} - -func ParseTaskTemplate(raw interface{}) (TaskTemplate, error) { - panic("unimplemented") -} diff --git a/pkg/workflow/model/template/template.go b/pkg/workflow/model/template/template.go deleted file mode 100644 index 2eae9120e9..0000000000 --- a/pkg/workflow/model/template/template.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package template - -type TemplateType string - -const ( - Task TemplateType = "Task" - Serial TemplateType = "Serial" - Parallel TemplateType = "Parallel" - Suspend TemplateType = "Suspend" - IoChaos TemplateType = "IoChaos" - NetworkChaos TemplateType = "NetworkChaos" - StressChaos TemplateType = "StressChaos" - PodChaos TemplateType = "PodChaos" - TimeChaos TemplateType = "TimeChaos" - KernelChaos TemplateType = "KernelChaos" - DnsChaos TemplateType = "DnsChaos" - HttpChaos TemplateType = "HttpChaos" - JvmChaos TemplateType = "JvmChaos" -) - -type Template interface { - Name() string - TemplateType() TemplateType -} - -// func IsCompositeType. CompositeType means this Template could have children Templates. -func (it TemplateType) IsCompositeType() bool { - return it == Serial || it == Parallel || it == Task -} diff --git a/pkg/workflow/model/workflow/workflow.go b/pkg/workflow/model/workflow/workflow.go deleted file mode 100644 index 7961c6c71d..0000000000 --- a/pkg/workflow/model/workflow/workflow.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package workflow - -import ( - "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/node" - "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/template" -) - -type WorkflowSpec interface { - Name() string - Entry() string - FetchTemplateByName(templateName string) (template.Template, error) -} - -type WorkflowPhase string - -const ( - // It's also the initial phase of a workflow. - Init WorkflowPhase = "Init" - Running WorkflowPhase = "Running" - Succeed WorkflowPhase = "Succeed" - Failed WorkflowPhase = "Failed" -) - -type WorkflowStatus interface { - // func Phase returns current phase - Phase() WorkflowPhase - // func Nodes returns the flat array of all nodes - Nodes() []node.Node - // func WorkflowSpecName returns the name of WorkflowSpec - WorkflowSpecName() string - // func NodesTree returns the root of the node tree. - // This tree could present the hierarchy of how nodes execute. - NodesTree() (node.NodeTreeNode, error) - - // func NodesMap - // Key is the name of node - NodesMap() map[string]node.Node - - FetchNodeByName(nodeName string) (node.Node, error) -} diff --git a/pkg/workflow/scheduler/scheduler.go b/pkg/workflow/scheduler/scheduler.go deleted file mode 100644 index dd134dbcdc..0000000000 --- a/pkg/workflow/scheduler/scheduler.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package scheduler - -import ( - "context" - - "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/template" -) - -/* interface Scheduler follows the iterator-pattern, it provides templates which need instantiate. */ -type Scheduler interface { - ScheduleNext(ctx context.Context) (nextTemplates []template.Template, parentNodeName string, err error) -} diff --git a/pkg/workflow/scheduler/serial_scheduler.go b/pkg/workflow/scheduler/serial_scheduler.go deleted file mode 100644 index c0b2ea5f24..0000000000 --- a/pkg/workflow/scheduler/serial_scheduler.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package scheduler - -import ( - "context" - "fmt" - - "github.com/chaos-mesh/chaos-mesh/pkg/workflow/errors" - "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/node" - "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/template" - "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/workflow" -) - -type serialScheduler struct { - workflowSpec workflow.WorkflowSpec - nodeStatus node.Node - treeNode node.NodeTreeNode -} - -func NewSerialScheduler(workflowSpec workflow.WorkflowSpec, nodeStatus node.Node, treeNode node.NodeTreeNode) *serialScheduler { - return &serialScheduler{workflowSpec: workflowSpec, nodeStatus: nodeStatus, treeNode: treeNode} -} - -func (it *serialScheduler) ScheduleNext(ctx context.Context) (nextTemplates []template.Template, parentNodeName string, err error) { - op := "serialScheduler.ScheduleNext" - parentTemplate, err := it.workflowSpec.FetchTemplateByName(it.nodeStatus.TemplateName()) - if err != nil { - return nil, "", err - } - - if parentTemplate.TemplateType() != template.Serial { - return nil, "", fmt.Errorf("%s is not serail", it.nodeStatus.TemplateName()) - } - - serialTemplate, err := template.ParseSerialTemplate(parentTemplate) - if err != nil { - return nil, "", err - } - - childrenTemplateNames := serialTemplate.SerialChildrenList() - - if it.treeNode.Children().Length() >= len(childrenTemplateNames) { - // TODO: unexpected situation, warn log - return nil, "", errors.NewNoMoreTemplateInSerialTemplateError(op, it.workflowSpec.Name(), it.treeNode.TemplateName(), it.treeNode.Name()) - } - - targetName := childrenTemplateNames[it.treeNode.Children().Length()] - targetTemplate, err := it.workflowSpec.FetchTemplateByName(targetName) - if err != nil { - return nil, "", err - } - - return []template.Template{targetTemplate}, it.nodeStatus.Name(), nil -} diff --git a/pkg/workflow/scheduler/serial_scheduler_test.go b/pkg/workflow/scheduler/serial_scheduler_test.go deleted file mode 100644 index 865f14808b..0000000000 --- a/pkg/workflow/scheduler/serial_scheduler_test.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package scheduler - -import ( - "context" - "errors" - "testing" - - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/assert" - - workflowerrors "github.com/chaos-mesh/chaos-mesh/pkg/workflow/errors" - "github.com/chaos-mesh/chaos-mesh/pkg/workflow/mock/model/mock_node" - "github.com/chaos-mesh/chaos-mesh/pkg/workflow/mock/model/mock_template" - "github.com/chaos-mesh/chaos-mesh/pkg/workflow/mock/model/mock_workflow" - "github.com/chaos-mesh/chaos-mesh/pkg/workflow/model/template" -) - -func TestScheduleWithSerial(t *testing.T) { - - tests := []struct { - name string - childrenTemplates []string - succeedChildren int - expectedScheduledTemplates []string - expectedError error - }{ - { - name: "no-schedule", - childrenTemplates: nil, - succeedChildren: 0, - expectedScheduledTemplates: nil, - expectedError: workflowerrors.ErrNoMoreTemplateInSerialTemplate, - }, { - name: "alternative-no-schedule", - childrenTemplates: []string{}, - succeedChildren: 0, - expectedScheduledTemplates: nil, - expectedError: workflowerrors.ErrNoMoreTemplateInSerialTemplate, - }, { - name: "schedule-one-by-one-0", - childrenTemplates: []string{"child-0", "child-1", "child-2"}, - succeedChildren: 0, - expectedScheduledTemplates: []string{"child-0"}, - expectedError: nil, - }, { - name: "schedule-one-by-one-1", - childrenTemplates: []string{"child-0", "child-1", "child-2"}, - succeedChildren: 1, - expectedScheduledTemplates: []string{"child-1"}, - expectedError: nil, - }, { - name: "schedule-one-by-one-2", - childrenTemplates: []string{"child-0", "child-1", "child-2"}, - succeedChildren: 2, - expectedScheduledTemplates: []string{"child-2"}, - expectedError: nil, - }, { - name: "schedule-one-by-one-final", - childrenTemplates: []string{"child-0", "child-1", "child-2"}, - succeedChildren: 3, - expectedScheduledTemplates: nil, - expectedError: workflowerrors.ErrNoMoreTemplateInSerialTemplate, - }, { - name: "schedule-duplicated-template-0", - childrenTemplates: []string{"child-0", "child-1", "child-0", "child-1"}, - succeedChildren: 0, - expectedScheduledTemplates: []string{"child-0"}, - expectedError: nil, - }, { - name: "schedule-duplicated-template-1", - childrenTemplates: []string{"child-0", "child-1", "child-0", "child-1"}, - succeedChildren: 1, - expectedScheduledTemplates: []string{"child-1"}, - expectedError: nil, - }, { - name: "schedule-duplicated-template-2", - childrenTemplates: []string{"child-0", "child-1", "child-0", "child-1"}, - succeedChildren: 2, - expectedScheduledTemplates: []string{"child-0"}, - expectedError: nil, - }, { - name: "schedule-duplicated-template-3", - childrenTemplates: []string{"child-0", "child-1", "child-0", "child-1"}, - succeedChildren: 3, - expectedScheduledTemplates: []string{"child-1"}, - expectedError: nil, - }, { - name: "schedule-duplicated-template-4", - childrenTemplates: []string{"child-0", "child-1", "child-0", "child-1"}, - succeedChildren: 4, - expectedScheduledTemplates: nil, - expectedError: workflowerrors.ErrNoMoreTemplateInSerialTemplate, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - mockctl := gomock.NewController(t) - const serialTemplateName = "mock-serial" - const serialNodeName = serialTemplateName + "-0000" - const workflowName = "mock-workflow" - - mockSerialTemplate := mock_template.NewMockSerialTemplate(mockctl) - mockSerialTemplate.EXPECT().TemplateType().Return(template.Serial).AnyTimes() - mockSerialTemplate.EXPECT().SerialChildrenList().Return(test.childrenTemplates).AnyTimes() - - mockWorkflowSpec := mock_workflow.NewMockWorkflowSpec(mockctl) - mockWorkflowSpec.EXPECT().Name().Return(workflowName).AnyTimes() - - mockTreeNode := mock_node.NewMockNodeTreeNode(mockctl) - nodeTreeChildren := mock_node.NewMockNodeTreeChildren(mockctl) - mockTreeNode.EXPECT().Name().Return(serialNodeName).AnyTimes() - mockTreeNode.EXPECT().Children().Return(nodeTreeChildren).AnyTimes() - mockTreeNode.EXPECT().TemplateName().Return(serialTemplateName).AnyTimes() - nodeTreeChildren.EXPECT().Length().Return(test.succeedChildren).AnyTimes() - - mockNode := mock_node.NewMockNode(mockctl) - mockNode.EXPECT().Name().Return(serialNodeName).AnyTimes() - mockNode.EXPECT().TemplateName().Return(serialTemplateName).AnyTimes() - - mockWorkflowSpec.EXPECT().FetchTemplateByName(gomock.Eq(serialTemplateName)).Return(mockSerialTemplate, nil).AnyTimes() - for _, childTemplate := range test.childrenTemplates { - mockChildTemplate := mock_template.NewMockSerialTemplate(mockctl) - mockChildTemplate.EXPECT().Name().Return(childTemplate).AnyTimes() - mockWorkflowSpec.EXPECT().FetchTemplateByName(gomock.Eq(childTemplate)).Return(mockChildTemplate, nil).AnyTimes() - } - - scheduler := NewSerialScheduler(mockWorkflowSpec, mockNode, mockTreeNode) - nextTemplates, parentNodeName, err := scheduler.ScheduleNext(context.TODO()) - if test.expectedError != nil { - assert.Error(t, err) - assert.True(t, errors.Is(err, test.expectedError)) - } else { - assert.NoError(t, err) - assert.Equal(t, serialNodeName, parentNodeName) - var names []string - for _, item := range nextTemplates { - names = append(names, item.Name()) - } - assert.Equal(t, test.expectedScheduledTemplates, names) - } - }) - } -} diff --git a/pkg/workflow/task/collector/collector.go b/pkg/workflow/task/collector/collector.go new file mode 100644 index 0000000000..37ca08e379 --- /dev/null +++ b/pkg/workflow/task/collector/collector.go @@ -0,0 +1,69 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package collector + +import ( + "context" + + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// Collector is a set of tools for collecting parameters/context from user defined task +type Collector interface { + CollectContext(ctx context.Context) (env map[string]interface{}, err error) +} + +type ComposeCollector struct { + collectors []Collector +} + +func (it *ComposeCollector) CollectContext(ctx context.Context) (env map[string]interface{}, err error) { + if len(it.collectors) == 0 { + return nil, nil + } + if len(it.collectors) == 1 { + return it.collectors[0].CollectContext(ctx) + } + + result := make(map[string]interface{}) + for _, collector := range it.collectors { + temp, err := collector.CollectContext(ctx) + if err != nil { + return nil, err + } + mapExtend(result, temp) + } + return result, nil +} + +// mapExtend will merge another map into the origin map, value with duplicated key will be replaced. +// origin map should not be nil +func mapExtend(origin map[string]interface{}, another map[string]interface{}) { + if origin == nil || another == nil { + return + } + for k, v := range another { + origin[k] = v + } +} + +func DefaultCollector(kubeClient client.Client, restConfig *rest.Config, namespace, podName, containerName string) Collector { + return &ComposeCollector{collectors: []Collector{ + NewExitCodeCollector(kubeClient, namespace, podName, containerName), + NewStdoutCollector(restConfig, namespace, podName, containerName), + }} +} diff --git a/pkg/workflow/task/collector/exit_code.go b/pkg/workflow/task/collector/exit_code.go new file mode 100644 index 0000000000..4a7d7b256d --- /dev/null +++ b/pkg/workflow/task/collector/exit_code.go @@ -0,0 +1,77 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package collector + +import ( + "context" + + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const ExitCode string = "exitCode" + +type ExitCodeCollector struct { + kubeClient client.Client + namespace string + podName string + containerName string +} + +func NewExitCodeCollector(kubeClient client.Client, namespace string, podName string, containerName string) *ExitCodeCollector { + return &ExitCodeCollector{kubeClient: kubeClient, namespace: namespace, podName: podName, containerName: containerName} +} + +func (it *ExitCodeCollector) CollectContext(ctx context.Context) (env map[string]interface{}, err error) { + var pod corev1.Pod + err = it.kubeClient.Get(ctx, types.NamespacedName{ + Namespace: it.namespace, + Name: it.podName, + }, &pod) + + if apierrors.IsNotFound(err) { + return nil, nil + } + + if err != nil { + return nil, err + } + + var targetContainerStatus corev1.ContainerStatus + found := false + for _, containerStatus := range pod.Status.ContainerStatuses { + if containerStatus.Name == it.containerName { + targetContainerStatus = containerStatus + found = true + break + } + } + + if !found { + return nil, errors.Errorf("no such contaienr called %s in pod %s/%s", it.containerName, pod.Namespace, pod.Name) + } + + if targetContainerStatus.State.Terminated == nil { + return nil, errors.Errorf("container %s in pod %s/%s is waiting or running, not in ternimated", it.containerName, pod.Namespace, pod.Name) + } + + return map[string]interface{}{ + ExitCode: targetContainerStatus.State.Terminated.ExitCode, + }, nil +} diff --git a/pkg/workflow/task/collector/stdout.go b/pkg/workflow/task/collector/stdout.go new file mode 100644 index 0000000000..410c069dab --- /dev/null +++ b/pkg/workflow/task/collector/stdout.go @@ -0,0 +1,59 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package collector + +import ( + "context" + "strings" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" +) + +const Stdout string = "stdout" + +type StdoutCollector struct { + restConfig *rest.Config + namespace string + podName string + containerName string +} + +func NewStdoutCollector(restConfig *rest.Config, namespace string, podName string, containerName string) *StdoutCollector { + return &StdoutCollector{restConfig: restConfig, namespace: namespace, podName: podName, containerName: containerName} +} + +func (it *StdoutCollector) CollectContext(ctx context.Context) (env map[string]interface{}, err error) { + client, err := kubernetes.NewForConfig(it.restConfig) + if err != nil { + return nil, err + } + + request := client.CoreV1().Pods(it.namespace).GetLogs(it.podName, &v1.PodLogOptions{ + TypeMeta: metav1.TypeMeta{}, + Container: it.containerName, + }) + + var bytes []byte + if bytes, err = request.Do(ctx).Raw(); err != nil { + return nil, err + } + stdout := strings.TrimSpace(string(bytes)) + + return map[string]interface{}{Stdout: stdout}, nil +} diff --git a/pkg/workflow/task/collector/valued_collector.go b/pkg/workflow/task/collector/valued_collector.go new file mode 100644 index 0000000000..b2942cb305 --- /dev/null +++ b/pkg/workflow/task/collector/valued_collector.go @@ -0,0 +1,46 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package collector + +import ( + "encoding/json" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type ValuedCollector struct { + status v1alpha1.ConditionalBranchesStatus +} + +func NewValuedCollector(status v1alpha1.ConditionalBranchesStatus) *ValuedCollector { + return &ValuedCollector{status: status} +} + +func (it *ValuedCollector) CollectContext() (env map[string]interface{}, err error) { + if len(it.status.Context) == 0 { + return nil, nil + } + result := make(map[string]interface{}) + for _, jsonString := range it.status.Context { + var tmp map[string]interface{} + err := json.Unmarshal([]byte(jsonString), &tmp) + if err != nil { + return nil, err + } + mapExtend(result, tmp) + } + return result, err +} diff --git a/pkg/workflow/task/doc.go b/pkg/workflow/task/doc.go new file mode 100644 index 0000000000..14b173141f --- /dev/null +++ b/pkg/workflow/task/doc.go @@ -0,0 +1,17 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Package task contains the tools for build an customized job and assert the condition branches + +package task diff --git a/pkg/workflow/task/evaluator.go b/pkg/workflow/task/evaluator.go new file mode 100644 index 0000000000..b272a643de --- /dev/null +++ b/pkg/workflow/task/evaluator.go @@ -0,0 +1,61 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package task + +import ( + "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/expr" +) + +type Evaluator struct { + logger logr.Logger + kubeclient client.Client +} + +func NewEvaluator(logger logr.Logger, kubeclient client.Client) *Evaluator { + return &Evaluator{logger: logger, kubeclient: kubeclient} +} + +func (it *Evaluator) EvaluateConditionBranches(tasks []v1alpha1.ConditionalBranch, resultEnv map[string]interface{}) (branches []v1alpha1.ConditionalBranchStatus, err error) { + + var result []v1alpha1.ConditionalBranchStatus + for _, task := range tasks { + it.logger.V(4).Info("evaluate for expression", "expression", task.Expression, "env", resultEnv) + var evalResult corev1.ConditionStatus + eval, err := expr.EvalBool(task.Expression, resultEnv) + + if err != nil { + it.logger.Error(err, "failed to evaluate expression", "expression", task.Expression, "env", resultEnv) + evalResult = corev1.ConditionUnknown + } else { + if eval { + evalResult = corev1.ConditionTrue + } else { + evalResult = corev1.ConditionFalse + } + } + + result = append(result, v1alpha1.ConditionalBranchStatus{ + Target: task.Target, + EvaluationResult: evalResult, + }) + } + return result, nil +} diff --git a/pkg/workflow/task/pod.go b/pkg/workflow/task/pod.go new file mode 100644 index 0000000000..3135d1e0c0 --- /dev/null +++ b/pkg/workflow/task/pod.go @@ -0,0 +1,53 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package task + +import ( + corev1 "k8s.io/api/core/v1" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +const ( + PodMetadataVolumeName = "podmetadata" + PodMetadataAnnotationsVolumePath = "" + PodMetadataMountPath = "/var/run/chaos-mesh/" +) + +func SpawnPodForTask(task v1alpha1.Task) (corev1.PodSpec, error) { + deepCopiedContainer := task.Container.DeepCopy() + if len(deepCopiedContainer.Resources.Limits) == 0 { + deepCopiedContainer.Resources.Limits.Cpu().SetMilli(1000) + deepCopiedContainer.Resources.Limits.Memory().Set(1000) + } + result := corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyNever, + Volumes: attachVolumes(task), + Containers: []corev1.Container{ + *deepCopiedContainer, + }, + } + return result, nil +} + +func attachVolumes(task v1alpha1.Task) []corev1.Volume { + var result []corev1.Volume + + // TODO: downwards API and configmaps + + result = append(result, task.Volumes...) + return result +} diff --git a/revive.toml b/revive.toml index 18892d1662..360e42e508 100644 --- a/revive.toml +++ b/revive.toml @@ -1,9 +1,24 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ignoreGeneratedHeader = false severity = "error" confidence = 0.8 errorCode = 1 warningCode = 0 +# https://github.com/mgechev/revive#recommended-configuration [rule.blank-imports] [rule.context-as-argument] [rule.dot-imports] @@ -11,39 +26,38 @@ warningCode = 0 [rule.error-strings] [rule.error-naming] [rule.if-return] -[rule.package-comments] +[rule.increment-decrement] +# FIXME: resolve warnings and uncomment. +# [rule.var-naming] +# severity = "warning" +# FIXME: resolve warnings and uncomment. +# [rule.package-comments] +# severity = "warning" [rule.range] [rule.receiver-naming] [rule.indent-error-flow] [rule.empty-block] [rule.superfluous-else] -[rule.modifies-parameter] +# FIXME: resolve warnings and uncomment. +# [rule.unused-parameter] +# severity = "warning" +[rule.redefines-builtin-id] -# Add these once issues are fixed -#[rule.var-naming] -# severity = "warning" -#[rule.confusing-naming] -# severity = "warning" [rule.confusing-results] - severity = "warning" [rule.flag-parameter] severity = "warning" -#[rule.unused-parameter] -# severity = "warning" -# Decide whether we want these rules +# Decide whether we want these rules. # [rule.exported] -# Already checked by megacheck +# Already checked by megacheck. # [rule.unreachable-code] -# Adding these will slow down the linter -# They are already provided by megacheck -# [rule.unexported-return] +# Adding these slows down the linter because they are already provided by megacheck. # [rule.time-naming] +# [rule.unexported-return] # [rule.errorf] -# Adding these will slow down the linter -# Not sure if they are already provided by megacheck -# [rule.var-declaration] +# Adding these slows down the linter but not sure if they are already provided by megacheck. # [rule.context-keys-type] +# [rule.var-declaration] diff --git a/static/chaos-mesh-social-preview.png b/static/chaos-mesh-social-preview.png index 21606c425b..a0ab09935c 100644 Binary files a/static/chaos-mesh-social-preview.png and b/static/chaos-mesh-social-preview.png differ diff --git a/static/chaos-mesh.png b/static/chaos-mesh.png new file mode 100644 index 0000000000..242a85390d Binary files /dev/null and b/static/chaos-mesh.png differ diff --git a/static/chaos-mesh.svg b/static/chaos-mesh.svg deleted file mode 100644 index 6b02860a44..0000000000 --- a/static/chaos-mesh.svg +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/static/cncf-white.png b/static/cncf-white.png new file mode 100644 index 0000000000..d7ed54edc8 Binary files /dev/null and b/static/cncf-white.png differ diff --git a/static/cncf.png b/static/cncf.png new file mode 100644 index 0000000000..c6548f47b8 Binary files /dev/null and b/static/cncf.png differ diff --git a/static/logo-white.svg b/static/logo-white.svg new file mode 100644 index 0000000000..b3e21ae251 --- /dev/null +++ b/static/logo-white.svg @@ -0,0 +1,17 @@ + + diff --git a/static/logo.svg b/static/logo.svg index 2fc491a08b..1018beb289 100644 --- a/static/logo.svg +++ b/static/logo.svg @@ -1 +1,17 @@ - \ No newline at end of file + + diff --git a/test/action.go b/test/action.go deleted file mode 100644 index da254b1c36..0000000000 --- a/test/action.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package test - -import ( - "fmt" - "os/exec" - "strings" - "time" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/util/wait" - - apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/kubernetes" - "k8s.io/klog" - aggregatorclientset "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset" - - "github.com/chaos-mesh/chaos-mesh/test/e2e/e2econst" - e2eutil "github.com/chaos-mesh/chaos-mesh/test/e2e/util" -) - -const ( - operatorChartName = "chaos-mesh" -) - -// OperatorAction describe the common operation during test (e2e/stability/etc..) -type OperatorAction interface { - CleanCRDOrDie() - DeployOperator(config OperatorConfig) error - InstallCRD(config OperatorConfig) error -} - -// NewOperatorAction create an OperatorAction interface instance -func NewOperatorAction( - kubeCli kubernetes.Interface, - aggrCli aggregatorclientset.Interface, - apiExtCli apiextensionsclientset.Interface, - cfg *Config) OperatorAction { - - oa := &operatorAction{ - kubeCli: kubeCli, - aggrCli: aggrCli, - apiExtCli: apiExtCli, - cfg: cfg, - } - return oa -} - -func (oa *operatorAction) DeployOperator(info OperatorConfig) error { - klog.Infof("create namespace chaos-testing") - cmd := fmt.Sprintf(`kubectl create ns %s`, e2econst.ChaosMeshNamespace) - klog.Infof(cmd) - output, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput() - if err != nil { - return fmt.Errorf("failed to create namespace chaos-testing: %v %s", err, string(output)) - } - klog.Infof("deploying chaos-mesh:%v", info.ReleaseName) - cmd = fmt.Sprintf(`helm install %s %s --namespace %s --set %s`, - info.ReleaseName, - oa.operatorChartPath(info.Tag), - info.Namespace, - info.operatorHelmSetValue()) - klog.Info(cmd) - res, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput() - if err != nil { - return fmt.Errorf("failed to deploy operator: %v, %s", err, string(res)) - } - klog.Infof("start to waiting chaos-mesh ready") - err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - - ls := &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/instance": "chaos-mesh", - }, - } - l, err := metav1.LabelSelectorAsSelector(ls) - if err != nil { - klog.Errorf("failed to get selector, err:%v", err) - return false, nil - } - pods, err := oa.kubeCli.CoreV1().Pods(info.Namespace).List(metav1.ListOptions{LabelSelector: l.String()}) - if err != nil { - klog.Errorf("failed to get chaos-mesh pods, err:%v", err) - return false, nil - } - for _, pod := range pods.Items { - if pod.Status.Phase != corev1.PodRunning { - return false, nil - } - } - return true, nil - }) - if err != nil { - return err - } - return e2eutil.WaitForAPIServicesAvailable(oa.aggrCli, labels.Everything()) -} - -func (oa *operatorAction) InstallCRD(info OperatorConfig) error { - klog.Infof("deploying chaos-mesh crd :%v", info.ReleaseName) - oa.runKubectlOrDie("apply", "-f", oa.manifestPath("e2e/crd.yaml"), "--validate=false") - e2eutil.WaitForCRDsEstablished(oa.apiExtCli, labels.Everything()) - // workaround for https://github.com/kubernetes/kubernetes/issues/65517 - klog.Infof("force sync kubectl cache") - cmdArgs := []string{"sh", "-c", "rm -rf ~/.kube/cache ~/.kube/http-cache"} - _, err := exec.Command(cmdArgs[0], cmdArgs[1:]...).CombinedOutput() - if err != nil { - klog.Fatalf("Failed to run '%s': %v", strings.Join(cmdArgs, " "), err) - } - return nil -} - -func (oa *operatorAction) CleanCRDOrDie() { - oa.runKubectlOrDie("delete", "crds", "--all") -} diff --git a/test/cmd/e2e_helper/Dockerfile b/test/cmd/e2e_helper/Dockerfile deleted file mode 100644 index abeeb93812..0000000000 --- a/test/cmd/e2e_helper/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM golang:alpine3.10 - -WORKDIR /src - -COPY main.go /src -COPY go.mod /src - -RUN go build -o test main.go - -FROM alpine:3.12 - -COPY --from=0 /src/test /bin - -ENTRYPOINT ["/bin/test"] diff --git a/test/cmd/e2e_helper/go.mod b/test/cmd/e2e_helper/go.mod deleted file mode 100644 index 2183000d18..0000000000 --- a/test/cmd/e2e_helper/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/chaos-mesh/chaos-mesh/test/cmd/e2e_helper - -go 1.15 - -require github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68 // indirect diff --git a/test/cmd/e2e_helper/go.sum b/test/cmd/e2e_helper/go.sum deleted file mode 100644 index 7786d40e06..0000000000 --- a/test/cmd/e2e_helper/go.sum +++ /dev/null @@ -1,42 +0,0 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= -github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68 h1:hkGVFjz+plgr5UfxZUTPFbUFIF/Km6/s+RVRIRHLrrY= -github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= -github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg= -github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= -github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/test/cmd/e2e_helper/main.go b/test/cmd/e2e_helper/main.go deleted file mode 100644 index 36d317d8a6..0000000000 --- a/test/cmd/e2e_helper/main.go +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "bytes" - "encoding/json" - "flag" - "fmt" - "io" - "io/ioutil" - "net" - "net/http" - "os" - "path/filepath" - "time" - - "github.com/containerd/cgroups" -) - -func main() { - port := flag.Int("port", 8080, "listen port") - dataDir := flag.String("data-dir", "/var/run/data", "data dir is the dir to write temp file, only used in io test") - - flag.Parse() - - s := newServer(*dataDir) - err := s.setupUDPServer() - if err != nil { - fmt.Println("failed to serve udp server", err) - os.Exit(1) - } - - addr := fmt.Sprintf("0.0.0.0:%d", *port) - if err := http.ListenAndServe(addr, s.mux); err != nil { - fmt.Println("failed to serve http server", err) - os.Exit(1) - } -} - -type server struct { - mux *http.ServeMux - dataDir string - - // ONLY FOR TEST: a buf without lock - recvBuf []byte -} - -func newServer(dataDir string) *server { - s := &server{ - mux: http.NewServeMux(), - dataDir: dataDir, - recvBuf: make([]byte, 5), - } - s.mux.HandleFunc("/ping", pong) - s.mux.HandleFunc("/time", s.timer) - s.mux.HandleFunc("/io", s.ioTest) - s.mux.HandleFunc("/mistake", s.mistakeTest) - s.mux.HandleFunc("/network/send", s.networkSendTest) - s.mux.HandleFunc("/network/recv", s.networkRecvTest) - s.mux.HandleFunc("/network/ping", s.networkPingTest) - s.mux.HandleFunc("/dns", s.dnsTest) - s.mux.HandleFunc("/stress", s.stressCondition) - return s -} - -func pong(w http.ResponseWriter, _ *http.Request) { - w.Write([]byte("pong")) -} - -func (s *server) setupUDPServer() error { - pc, err := net.ListenPacket("udp", "0.0.0.0:1070") - if err != nil { - return err - } - - go func() { - for { - _, _, err := pc.ReadFrom(s.recvBuf) - if err != nil { - return - } - } - }() - - return nil -} - -// a handler to print out the current time -func (s *server) timer(w http.ResponseWriter, _ *http.Request) { - w.Write([]byte(time.Now().Format(time.RFC3339Nano))) -} - -// a handler to test io chaos -func (s *server) mistakeTest(w http.ResponseWriter, _ *http.Request) { - path := filepath.Join(s.dataDir, "e2e-test") - origData := []byte("hello world!!!!!!!!!!!!") - - err := ioutil.WriteFile(path, origData, 0644) - if err != nil { - w.Write([]byte(fmt.Sprintf("failed to write file %v", err))) - return - } - gotData, err := ioutil.ReadFile(path) - if err != nil { - w.Write([]byte(err.Error())) - return - } - result := bytes.Equal(origData, gotData) - if result { - w.Write([]byte("false")) - return - } - for i := 0; i < 10; i++ { - tmp, err := ioutil.ReadFile(path) - if err != nil { - w.Write([]byte(err.Error())) - } - if !bytes.Equal(tmp, gotData) { - w.Write([]byte("true")) - return - } - } - w.Write([]byte("err")) -} - -// a handler to test io chaos -func (s *server) ioTest(w http.ResponseWriter, _ *http.Request) { - t1 := time.Now() - f, err := ioutil.TempFile(s.dataDir, "e2e-test") - if err != nil { - w.Write([]byte(fmt.Sprintf("failed to create temp file %v", err))) - return - } - if _, err := f.Write([]byte("hello world")); err != nil { - w.Write([]byte(fmt.Sprintf("failed to write file %v", err))) - return - } - t2 := time.Now() - w.Write([]byte(t2.Sub(t1).String())) -} - -// a handler to test dns chaos -func (s *server) dnsTest(w http.ResponseWriter, r *http.Request) { - - url, ok := r.URL.Query()["url"] - - if !ok || len(url[0]) < 1 { - http.Error(w, "failed", http.StatusBadRequest) - return - } - - ips, err := net.LookupIP(url[0]) - if err != nil { - http.Error(w, "failed", http.StatusBadRequest) - return - } - - if len(ips) == 0 { - http.Error(w, "failed", http.StatusBadRequest) - return - } - - w.Write([]byte(ips[0].String())) -} - -type networkSendTestBody struct { - TargetIP string `json:"targetIP"` -} - -// a handler to test network chaos -func (s *server) networkPingTest(w http.ResponseWriter, r *http.Request) { - var body networkSendTestBody - - err := json.NewDecoder(r.Body).Decode(&body) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - c := http.Client{ - Timeout: 2 * time.Second, - } - startTime := time.Now() - resp, err := c.Get(fmt.Sprintf("http://%s:8080/ping", body.TargetIP)) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - defer resp.Body.Close() - - endTime := time.Now() - out, err := ioutil.ReadAll(resp.Body) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - if string(out) != "pong" { - http.Error(w, "response is not pong", http.StatusBadRequest) - return - } - - w.Write([]byte(fmt.Sprintf("OK %d", endTime.UnixNano()-startTime.UnixNano()))) -} - -// a handler to test network chaos -func (s *server) networkSendTest(w http.ResponseWriter, r *http.Request) { - var body networkSendTestBody - - err := json.NewDecoder(r.Body).Decode(&body) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - conn, err := net.DialUDP("udp", nil, &net.UDPAddr{ - IP: net.ParseIP(body.TargetIP), - Port: 1070, - }) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - defer conn.Close() - - n, err := io.WriteString(conn, "ping\n") - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - if n != 5 { - http.Error(w, "udp send less than 5 bytes", http.StatusBadRequest) - return - } - w.Write([]byte("send successfully\n")) -} - -// a handler to test network chaos -func (s *server) networkRecvTest(w http.ResponseWriter, r *http.Request) { - w.Write(s.recvBuf) - - for index := range s.recvBuf { - s.recvBuf[index] = 0 - } -} - -func (s *server) stressCondition(w http.ResponseWriter, r *http.Request) { - control, err := cgroups.Load(cgroups.V1, cgroups.PidPath(1)) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - stats, err := control.Stat(cgroups.IgnoreNotExist) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - response, err := json.Marshal(map[string]uint64{ - "cpuTime": stats.CPU.Usage.Total, - "memoryUsage": stats.Memory.Usage.Usage, - }) - if err != nil { - http.Error(w, "fail to marshal response", http.StatusInternalServerError) - return - } - - w.Write(response) -} diff --git a/test/cmd/multithread_tracee/main.c b/test/cmd/multithread_tracee/main.c index 7b74fa8b39..3aee5eb60f 100644 --- a/test/cmd/multithread_tracee/main.c +++ b/test/cmd/multithread_tracee/main.c @@ -1,3 +1,19 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ #include #include #include diff --git a/test/cmd/timer/main.go b/test/cmd/timer/main.go index 047f1a3c98..27974117eb 100644 --- a/test/cmd/timer/main.go +++ b/test/cmd/timer/main.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package main diff --git a/test/config.go b/test/config.go deleted file mode 100644 index d9114b43c5..0000000000 --- a/test/config.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package test - -// Config describe the basic config for the operator test -type Config struct { - ChartDir string - ManifestDir string - Tag string - ManagerImage string - ManagerTag string - DaemonImage string - DaemonTag string - E2EImage string - ChaosDNSImage string - InstallChaosMesh bool - EnableDashboard bool -} - -// NewDefaultConfig describe the default configuration for operator test -func NewDefaultConfig() *Config { - return &Config{ - ChartDir: "/charts", - ManifestDir: "/manifests", - Tag: "e2e", - ManagerImage: "localhost:5000/pingcap/chaos-mesh", - ManagerTag: "latest", - DaemonImage: "localhost:5000/pingcap/chaos-daemon", - DaemonTag: "latest", - E2EImage: "localhost:5000/pingcap/e2e-helper:latest", - ChaosDNSImage: "localhost:5000/pingcap/chaos-dns:latest", - InstallChaosMesh: false, - EnableDashboard: false, - } -} diff --git a/test/e2e/chaos/basic.go b/test/e2e/chaos/basic.go deleted file mode 100644 index fb217a6ea5..0000000000 --- a/test/e2e/chaos/basic.go +++ /dev/null @@ -1,436 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package chaos - -import ( - "context" - "fmt" - "net/http" - "strconv" - "time" - - "github.com/onsi/ginkgo" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - restClient "k8s.io/client-go/rest" - "k8s.io/kubernetes/test/e2e/framework" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/portforward" - e2econfig "github.com/chaos-mesh/chaos-mesh/test/e2e/config" - "github.com/chaos-mesh/chaos-mesh/test/e2e/e2econst" - "github.com/chaos-mesh/chaos-mesh/test/e2e/util" - "github.com/chaos-mesh/chaos-mesh/test/pkg/fixture" - - // testcases - dnschaostestcases "github.com/chaos-mesh/chaos-mesh/test/e2e/chaos/dnschaos" - iochaostestcases "github.com/chaos-mesh/chaos-mesh/test/e2e/chaos/iochaos" - networkchaostestcases "github.com/chaos-mesh/chaos-mesh/test/e2e/chaos/networkchaos" - podchaostestcases "github.com/chaos-mesh/chaos-mesh/test/e2e/chaos/podchaos" - sidecartestcases "github.com/chaos-mesh/chaos-mesh/test/e2e/chaos/sidecar" - stresstestcases "github.com/chaos-mesh/chaos-mesh/test/e2e/chaos/stresschaos" - timechaostestcases "github.com/chaos-mesh/chaos-mesh/test/e2e/chaos/timechaos" -) - -var _ = ginkgo.Describe("[Basic]", func() { - f := framework.NewDefaultFramework("chaos-mesh") - var ns string - var fwCancel context.CancelFunc - var fw portforward.PortForward - var kubeCli kubernetes.Interface - var config *restClient.Config - var cli client.Client - c := http.Client{ - Timeout: 10 * time.Second, - } - - ginkgo.BeforeEach(func() { - ns = f.Namespace.Name - ctx, cancel := context.WithCancel(context.Background()) - clientRawConfig, err := e2econfig.LoadClientRawConfig() - framework.ExpectNoError(err, "failed to load raw config") - fw, err = portforward.NewPortForwarder(ctx, e2econfig.NewSimpleRESTClientGetter(clientRawConfig), true) - framework.ExpectNoError(err, "failed to create port forwarder") - fwCancel = cancel - kubeCli = f.ClientSet - config, err = framework.LoadConfig() - framework.ExpectNoError(err, "config error") - scheme := runtime.NewScheme() - _ = clientgoscheme.AddToScheme(scheme) - _ = v1alpha1.AddToScheme(scheme) - cli, err = client.New(config, client.Options{Scheme: scheme}) - framework.ExpectNoError(err, "create client error") - }) - - ginkgo.AfterEach(func() { - if fwCancel != nil { - fwCancel() - } - }) - - ginkgo.Context("[PodChaos]", func() { - ginkgo.Context("[PodFailure]", func() { - ginkgo.It("[Schedule]", func() { - podchaostestcases.TestcasePodFailureOnceThenDelete(ns, kubeCli, cli) - }) - ginkgo.It("[Pause]", func() { - podchaostestcases.TestcasePodFailurePauseThenUnPause(ns, kubeCli, cli) - }) - }) - ginkgo.Context("[PodKill]", func() { - ginkgo.It("[Schedule]", func() { - podchaostestcases.TestcasePodKillOnceThenDelete(ns, kubeCli, cli) - }) - ginkgo.It("[Pause]", func() { - podchaostestcases.TestcasePodKillPauseThenUnPause(ns, kubeCli, cli) - }) - }) - ginkgo.Context("[ContainerKill]", func() { - ginkgo.It("[Schedule]", func() { - podchaostestcases.TestcaseContainerKillOnceThenDelete(ns, kubeCli, cli) - }) - ginkgo.It("[Pause]", func() { - podchaostestcases.TestcaseContainerKillPauseThenUnPause(ns, kubeCli, cli) - }) - }) - }) - - // time chaos case in [TimeChaos] context - ginkgo.Context("[TimeChaos]", func() { - - var err error - var port uint16 - var pfCancel context.CancelFunc - - ginkgo.JustBeforeEach(func() { - svc := fixture.NewE2EService("timer", ns) - _, err = kubeCli.CoreV1().Services(ns).Create(svc) - framework.ExpectNoError(err, "create service error") - nd := fixture.NewTimerDeployment("timer", ns) - _, err = kubeCli.AppsV1().Deployments(ns).Create(nd) - framework.ExpectNoError(err, "create timer deployment error") - err = util.WaitDeploymentReady("timer", ns, kubeCli) - framework.ExpectNoError(err, "wait timer deployment ready error") - _, port, pfCancel, err = portforward.ForwardOnePort(fw, ns, "svc/timer", 8080) - framework.ExpectNoError(err, "create helper port-forward failed") - }) - - ginkgo.JustAfterEach(func() { - if pfCancel != nil { - pfCancel() - } - }) - - // time skew chaos case in [TimeSkew] context - ginkgo.Context("[TimeSkew]", func() { - - ginkgo.It("[Schedule]", func() { - timechaostestcases.TestcaseTimeSkewOnceThenRecover(ns, cli, c, port) - }) - - ginkgo.It("[Pause]", func() { - timechaostestcases.TestcaseTimeSkewPauseThenUnpause(ns, cli, c, port) - }) - - ginkgo.It("[StartAtWaiting]", func() { - timechaostestcases.TestcaseTimeSkewStartAtWaitingThenIntoRunning(ns, cli, c, port) - }) - }) - }) - - // io chaos case in [IOChaos] context - ginkgo.Context("[IOChaos]", func() { - - var ( - err error - port uint16 - pfCancel context.CancelFunc - ) - - ginkgo.JustBeforeEach(func() { - svc := fixture.NewE2EService("io", ns) - _, err = kubeCli.CoreV1().Services(ns).Create(svc) - framework.ExpectNoError(err, "create service error") - nd := fixture.NewIOTestDeployment("io-test", ns) - _, err = kubeCli.AppsV1().Deployments(ns).Create(nd) - framework.ExpectNoError(err, "create io-test deployment error") - err = util.WaitDeploymentReady("io-test", ns, kubeCli) - framework.ExpectNoError(err, "wait io-test deployment ready error") - _, port, pfCancel, err = portforward.ForwardOnePort(fw, ns, "svc/io", 8080) - framework.ExpectNoError(err, "create helper io port port-forward failed") - }) - - ginkgo.JustAfterEach(func() { - if pfCancel != nil { - pfCancel() - } - }) - - // io chaos case in [IODelay] context - ginkgo.Context("[IODelay]", func() { - - ginkgo.It("[Schedule]", func() { - iochaostestcases.TestcaseIODelayDurationForATimeThenRecover(ns, cli, c, port) - }) - - ginkgo.It("[Pause]", func() { - iochaostestcases.TestcaseIODelayDurationForATimePauseAndUnPause(ns, cli, c, port) - }) - ginkgo.It("[SpecifyContainer]", func() { - iochaostestcases.TestcaseIODelayWithSpecifiedContainer(ns, cli, c, port) - }) - ginkgo.It("[WrongSpec]", func() { - iochaostestcases.TestcaseIODelayWithWrongSpec(ns, cli, c, port) - }) - }) - - // io chaos case in [IOError] context - ginkgo.Context("[IOErrno]", func() { - - ginkgo.It("[Schedule]", func() { - iochaostestcases.TestcaseIOErrorDurationForATimeThenRecover(ns, cli, c, port) - }) - ginkgo.It("[Pause]", func() { - iochaostestcases.TestcaseIOErrorDurationForATimePauseAndUnPause(ns, cli, c, port) - }) - ginkgo.It("[SpecifyContainer]", func() { - iochaostestcases.TestcaseIOErrorWithSpecifiedContainer(ns, cli, c, port) - }) - }) - - // io mistake case in [IOMistake] context - ginkgo.Context("[IOMistake]", func() { - - ginkgo.It("[Schedule]", func() { - iochaostestcases.TestcaseIOMistakeDurationForATimeThenRecover(ns, cli, c, port) - }) - ginkgo.It("[Pause]", func() { - iochaostestcases.TestcaseIOMistakeDurationForATimePauseAndUnPause(ns, cli, c, port) - }) - ginkgo.It("[SpecifyContainer]", func() { - iochaostestcases.TestcaseIOMistakeWithSpecifiedContainer(ns, cli, c, port) - }) - }) - }) - - ginkgo.Context("[Sidecar Config]", func() { - var ( - cmName string - cmNamespace string - ) - - // delete the created config map in each test case - ginkgo.JustAfterEach(func() { - kubeCli.CoreV1().ConfigMaps(cmNamespace).Delete(cmName, &metav1.DeleteOptions{}) - }) - - ginkgo.Context("[Template Config]", func() { - - ginkgo.It("[InValid ConfigMap key]", func() { - cmName = "incorrect-key-name" - cmNamespace = e2econst.ChaosMeshNamespace - sidecartestcases.TestcaseInvalidConfigMapKey(ns, cmNamespace, cmName, kubeCli, cli) - }) - - ginkgo.It("[InValid Configuration]", func() { - cmName = "incorrect-configuration" - cmNamespace = e2econst.ChaosMeshNamespace - sidecartestcases.TestcaseInvalidConfiguration(ns, cmNamespace, cmName, kubeCli, cli) - }) - }) - - ginkgo.Context("[Injection Config]", func() { - ginkgo.It("[No Template]", func() { - cmName = "no-template-name" - cmNamespace = e2econst.ChaosMeshNamespace - sidecartestcases.TestcaseNoTemplate(ns, cmNamespace, cmName, kubeCli, cli) - }) - - ginkgo.It("[No Template Args]", func() { - cmName = "no-template-args" - cmNamespace = e2econst.ChaosMeshNamespace - sidecartestcases.TestcaseNoTemplateArgs(ns, cmNamespace, cmName, kubeCli, cli) - }) - }) - }) - - ginkgo.Context("[NetworkChaos]", func() { - var err error - - var networkPeers []*v1.Pod - var ports []uint16 - var pfCancels []context.CancelFunc - - ginkgo.JustBeforeEach(func() { - ports = []uint16{} - networkPeers = []*v1.Pod{} - for index := 0; index < 4; index++ { - name := fmt.Sprintf("network-peer-%d", index) - - svc := fixture.NewE2EService(name, ns) - _, err = kubeCli.CoreV1().Services(ns).Create(svc) - framework.ExpectNoError(err, "create service error") - nd := fixture.NewNetworkTestDeployment(name, ns, map[string]string{"partition": strconv.Itoa(index % 2)}) - _, err = kubeCli.AppsV1().Deployments(ns).Create(nd) - framework.ExpectNoError(err, "create network-peer deployment error") - err = util.WaitDeploymentReady(name, ns, kubeCli) - framework.ExpectNoError(err, "wait network-peer deployment ready error") - - pod, err := getPod(kubeCli, ns, name) - framework.ExpectNoError(err, "select network-peer pod error") - networkPeers = append(networkPeers, pod) - - _, port, pfCancel, err := portforward.ForwardOnePort(fw, ns, "svc/"+svc.Name, 8080) - ports = append(ports, port) - pfCancels = append(pfCancels, pfCancel) - framework.ExpectNoError(err, "create helper io port port-forward failed") - } - }) - - ginkgo.Context("[ForbidHostNetwork]", func() { - ginkgo.It("[Schedule]", func() { - networkchaostestcases.TestcaseForbidHostNetwork(ns, kubeCli, cli) - }) - }) - - ginkgo.Context("[NetworkPartition]", func() { - ginkgo.It("[Schedule]", func() { - networkchaostestcases.TestcaseNetworkPartition(ns, cli, networkPeers, ports, c) - }) - }) - - ginkgo.Context("[Netem]", func() { - ginkgo.It("[Schedule]", func() { - networkchaostestcases.TestcaseNetworkDelay(ns, cli, networkPeers, ports, c) - }) - ginkgo.It("[PeersCrossoverWithDirectionBoth]", func() { - networkchaostestcases.TestcasePeersCrossover(ns, cli, networkPeers, ports, c) - }) - }) - - ginkgo.JustAfterEach(func() { - for _, cancel := range pfCancels { - cancel() - } - }) - }) - // DNS chaos case in [DNSChaos] context - ginkgo.Context("[DNSChaos]", func() { - var err error - var port uint16 - - ginkgo.JustBeforeEach(func() { - name := "network-peer" - - svc := fixture.NewE2EService(name, ns) - _, err = kubeCli.CoreV1().Services(ns).Create(svc) - framework.ExpectNoError(err, "create service error") - nd := fixture.NewNetworkTestDeployment(name, ns, map[string]string{"partition": "0"}) - _, err = kubeCli.AppsV1().Deployments(ns).Create(nd) - framework.ExpectNoError(err, "create network-peer deployment error") - err = util.WaitDeploymentReady(name, ns, kubeCli) - framework.ExpectNoError(err, "wait network-peer deployment ready error") - - _, err = getPod(kubeCli, ns, name) - framework.ExpectNoError(err, "select network-peer pod error") - - _, port, _, err = portforward.ForwardOnePort(fw, ns, "svc/"+svc.Name, 8080) - framework.ExpectNoError(err, "create helper io port port-forward failed") - }) - ginkgo.It("[RANDOM]", func() { - dnschaostestcases.TestcaseDNSRandom(ns, cli, port, c) - }) - - ginkgo.It("[ERROR]", func() { - dnschaostestcases.TestcaseDNSError(ns, cli, port, c) - }) - }) - // DNS chaos case in [StressChaos] context - ginkgo.Context("[StressChaos]", func() { - var err error - - var ports []uint16 - var stressPeers []*v1.Pod - var pfCancels []context.CancelFunc - - ginkgo.JustBeforeEach(func() { - ports = []uint16{} - stressPeers = []*v1.Pod{} - for index := 0; index < 2; index++ { - name := fmt.Sprintf("stress-peer-%d", index) - - svc := fixture.NewE2EService(name, ns) - _, err = kubeCli.CoreV1().Services(ns).Create(svc) - framework.ExpectNoError(err, "create service error") - nd := fixture.NewStressTestDeployment(name, ns, map[string]string{"partition": strconv.Itoa(index % 2)}) - _, err = kubeCli.AppsV1().Deployments(ns).Create(nd) - framework.ExpectNoError(err, "create network-peer deployment error") - err = util.WaitDeploymentReady(name, ns, kubeCli) - framework.ExpectNoError(err, "wait network-peer deployment ready error") - - pod, err := getPod(kubeCli, ns, name) - framework.ExpectNoError(err, "select network-peer pod error") - stressPeers = append(stressPeers, pod) - - _, port, pfCancel, err := portforward.ForwardOnePort(fw, ns, "svc/"+svc.Name, 8080) - ports = append(ports, port) - pfCancels = append(pfCancels, pfCancel) - framework.ExpectNoError(err, "create helper io port port-forward failed") - } - }) - - ginkgo.It("[CPU]", func() { - stresstestcases.TestcaseCPUStressInjectionOnceThenRecover(ns, cli, stressPeers, ports, c) - }) - - // TODO: unstable test - // ginkgo.It("[Memory]", func() { - // stresstestcases.TestcaseMemoryStressInjectionOnceThenRecover(ns, cli, stressPeers, ports, c) - // }) - - ginkgo.JustAfterEach(func() { - for _, cancel := range pfCancels { - cancel() - } - }) - }) -}) - -func getPod(kubeCli kubernetes.Interface, ns string, appLabel string) (*v1.Pod, error) { - listOption := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(map[string]string{ - "app": appLabel, - }).String(), - } - - pods, err := kubeCli.CoreV1().Pods(ns).List(listOption) - if err != nil { - return nil, err - } - - if len(pods.Items) > 1 { - return nil, fmt.Errorf("select more than one pod") - } - - if len(pods.Items) == 0 { - return nil, fmt.Errorf("cannot select any pod") - } - - return &pods.Items[0], nil -} diff --git a/test/e2e/chaos/iochaos/io_delay.go b/test/e2e/chaos/iochaos/io_delay.go deleted file mode 100644 index 45b8c22ca4..0000000000 --- a/test/e2e/chaos/iochaos/io_delay.go +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package iochaos - -import ( - "context" - "net/http" - "strings" - "time" - - . "github.com/onsi/ginkgo" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/klog" - "k8s.io/kubernetes/test/e2e/framework" - "k8s.io/utils/pointer" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/test/e2e/util" -) - -func TestcaseIODelayDurationForATimeThenRecover( - ns string, - cli client.Client, - c http.Client, - port uint16, -) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - By("waiting on e2e helper ready") - err := util.WaitE2EHelperReady(c, port) - framework.ExpectNoError(err, "wait e2e helper ready error") - By("create IO delay chaos CRD objects") - ioChaos := &v1alpha1.IoChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: "io-chaos", - Namespace: ns, - }, - Spec: v1alpha1.IoChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "io"}, - }, - Action: v1alpha1.IoLatency, - Mode: v1alpha1.OnePodMode, - VolumePath: "/var/run/data", - Path: "/var/run/data/*", - Delay: "1s", - Percent: 100, - Duration: pointer.StringPtr("9m"), - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", - }, - }, - } - err = cli.Create(ctx, ioChaos) - framework.ExpectNoError(err, "create io chaos error") - By("waiting for assertion IO delay") - err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { - dur, _ := getPodIODelay(c, port) - second := dur.Seconds() - klog.Infof("get io delay %fs", second) - // IO Delay >= 1s - if second >= 1 { - return true, nil - } - return false, nil - }) - framework.ExpectNoError(err, "io chaos doesn't work as expected") - By("apply io chaos successfully") - - By("delete chaos CRD objects") - // delete chaos CRD - err = cli.Delete(ctx, ioChaos) - framework.ExpectNoError(err, "failed to delete io chaos") - By("waiting for assertion recovering") - err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { - dur, _ := getPodIODelay(c, port) - second := dur.Seconds() - klog.Infof("get io delay %fs", second) - // IO Delay shouldn't longer than 1s - if second >= 1 { - return false, nil - } - return true, nil - }) - framework.ExpectNoError(err, "fail to recover io chaos") -} - -func TestcaseIODelayDurationForATimePauseAndUnPause( - ns string, - cli client.Client, - c http.Client, - port uint16, -) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - By("waiting for e2e helper ready") - err := util.WaitE2EHelperReady(c, port) - framework.ExpectNoError(err, "wait e2e helper ready error") - - By("create io chaos crd object") - ioChaos := &v1alpha1.IoChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: "io-chaos", - Namespace: ns, - }, - Spec: v1alpha1.IoChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "io"}, - }, - Action: v1alpha1.IoLatency, - Mode: v1alpha1.OnePodMode, - VolumePath: "/var/run/data", - Path: "/var/run/data/*", - Delay: "10ms", - Percent: 100, - Duration: pointer.StringPtr("9m"), - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", - }, - }, - } - err = cli.Create(ctx, ioChaos) - framework.ExpectNoError(err, "error occurs while applying io chaos") - - By("waiting for assertion io chaos") - err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { - dur, _ := getPodIODelay(c, port) - - ms := dur.Milliseconds() - klog.Infof("get io delay %dms", ms) - // IO Delay >= 500ms - if ms >= 10 { - return true, nil - } - return false, nil - }) - framework.ExpectNoError(err, "io chaos doesn't work as expected") - - chaosKey := types.NamespacedName{ - Namespace: ns, - Name: "io-chaos", - } - - By("pause io delay chaos experiment") - // pause experiment - err = util.PauseChaos(ctx, cli, ioChaos) - framework.ExpectNoError(err, "pause chaos error") - - By("waiting for assertion about pause") - err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - chaos := &v1alpha1.IoChaos{} - err = cli.Get(ctx, chaosKey, chaos) - framework.ExpectNoError(err, "get io chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhasePaused { - return true, nil - } - return false, err - }) - framework.ExpectNoError(err, "check paused chaos failed") - - // wait 1 min to check whether io delay still exists - err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { - dur, _ := getPodIODelay(c, port) - - ms := dur.Milliseconds() - klog.Infof("get io delay %dms", ms) - // IO Delay shouldn't longer than 10ms - if ms > 10 { - return false, nil - } - return true, nil - }) - framework.ExpectNoError(err, "fail to recover io chaos") - - By("resume io delay chaos experiment") - // resume experiment - err = util.UnPauseChaos(ctx, cli, ioChaos) - framework.ExpectNoError(err, "resume chaos error") - - By("assert that io delay is effective again") - err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { - chaos := &v1alpha1.IoChaos{} - err = cli.Get(ctx, chaosKey, chaos) - framework.ExpectNoError(err, "get io chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhaseRunning { - return true, nil - } - return false, err - }) - framework.ExpectNoError(err, "check resumed chaos failed") - - err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { - dur, _ := getPodIODelay(c, port) - - ms := dur.Milliseconds() - klog.Infof("get io delay %dms", ms) - // IO Delay >= 10ms - if ms >= 10 { - return true, nil - } - return false, nil - }) - framework.ExpectNoError(err, "io chaos doesn't work as expected") - - By("cleanup") - // cleanup - cli.Delete(ctx, ioChaos) -} - -func TestcaseIODelayWithSpecifiedContainer( - ns string, - cli client.Client, - c http.Client, - port uint16) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - err := util.WaitE2EHelperReady(c, port) - framework.ExpectNoError(err, "wait e2e helper ready error") - - containerName := "io" - ioChaos := &v1alpha1.IoChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: "io-chaos", - Namespace: ns, - }, - Spec: v1alpha1.IoChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "io"}, - }, - Action: v1alpha1.IoLatency, - Mode: v1alpha1.OnePodMode, - VolumePath: "/var/run/data", - Path: "/var/run/data/*", - Delay: "10ms", - Percent: 100, - ContainerName: &containerName, - Duration: pointer.StringPtr("9m"), - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", - }, - }, - } - err = cli.Create(ctx, ioChaos) - framework.ExpectNoError(err, "create io chaos error") - - err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { - dur, _ := getPodIODelay(c, port) - - ms := dur.Milliseconds() - klog.Infof("get io delay %dms", ms) - // IO Delay >= 10ms - if ms >= 10 { - return true, nil - } - return false, nil - }) - framework.ExpectNoError(err, "io chaos doesn't work as expected") - klog.Infof("apply io chaos successfully") - - err = cli.Delete(ctx, ioChaos) - framework.ExpectNoError(err, "failed to delete io chaos") - - err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (bool, error) { - dur, _ := getPodIODelay(c, port) - - ms := dur.Milliseconds() - klog.Infof("get io delay %dms", ms) - // IO Delay shouldn't longer than 10ms - if ms >= 10 { - return false, nil - } - return true, nil - }) - framework.ExpectNoError(err, "fail to recover io chaos") -} - -func TestcaseIODelayWithWrongSpec( - ns string, - cli client.Client, - c http.Client, - port uint16, -) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - By("waiting on e2e helper ready") - err := util.WaitE2EHelperReady(c, port) - framework.ExpectNoError(err, "wait e2e helper ready error") - By("create IO delay chaos CRD objects") - ioChaos := &v1alpha1.IoChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: "io-chaos", - Namespace: ns, - }, - Spec: v1alpha1.IoChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "io"}, - }, - Action: v1alpha1.IoLatency, - Mode: v1alpha1.OnePodMode, - VolumePath: "/var/run/data/123", - Path: "/var/run/data/*", - Delay: "1s", - Percent: 100, - Duration: pointer.StringPtr("9m"), - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", - }, - }, - } - err = cli.Create(ctx, ioChaos) - framework.ExpectNoError(err, "create io chaos error") - err = wait.PollImmediate(5*time.Second, 30*time.Second, func() (bool, error) { - err := cli.Get(ctx, types.NamespacedName{Namespace: ioChaos.ObjectMeta.Namespace, Name: ioChaos.ObjectMeta.Name}, ioChaos) - if err != nil { - return false, err - } - errStr := ioChaos.Status.ChaosStatus.FailedMessage - klog.Infof("get chaos err: %s", errStr) - if strings.Contains(errStr, "Toda startup takes too long or an error occurs") { - return true, nil - } - return false, nil - }) - framework.ExpectNoError(err, "A wrong chaos spec should raise an error") -} diff --git a/test/e2e/chaos/iochaos/misc.go b/test/e2e/chaos/iochaos/misc.go deleted file mode 100644 index 3a1f3ef1e3..0000000000 --- a/test/e2e/chaos/iochaos/misc.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package iochaos - -import ( - "errors" - "fmt" - "io/ioutil" - "net/http" - "strings" - "time" -) - -// get pod io delay -func getPodIODelay(c http.Client, port uint16) (time.Duration, error) { - resp, err := c.Get(fmt.Sprintf("http://localhost:%d/io", port)) - if err != nil { - return 0, err - } - - out, err := ioutil.ReadAll(resp.Body) - defer resp.Body.Close() - if err != nil { - return 0, err - } - - result := string(out) - if strings.Contains(result, "failed to write file") { - return 0, errors.New(result) - } - dur, err := time.ParseDuration(result) - if err != nil { - return 0, err - } - - return dur, nil -} - -func getPodIoMistake(c http.Client, port uint16) (bool, error) { - resp, err := c.Get(fmt.Sprintf("http://localhost:%d/mistake", port)) - if err != nil { - return false, err - } - - out, err := ioutil.ReadAll(resp.Body) - defer resp.Body.Close() - if err != nil { - return false, err - } - - result := string(out) - fmt.Println("e2e server io mistake test response: ", resp, result) - if strings.Contains(result, "true") { - return true, nil - } - if strings.Contains(result, "false") { - return false, nil - } - if strings.Contains(result, "err") { - return false, errors.New(result) - } - return false, errors.New("Unexpected reply from e2e server") -} diff --git a/test/e2e/chaos/networkchaos/misc.go b/test/e2e/chaos/networkchaos/misc.go deleted file mode 100644 index ab02a8ad91..0000000000 --- a/test/e2e/chaos/networkchaos/misc.go +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package networkchaos - -import ( - "bytes" - "fmt" - "io/ioutil" - "net/http" - "strconv" - "strings" - "sync" - "time" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/klog" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -const ( - networkConditionBlocked = "blocked" - networkConditionSlow = "slow" - networkConditionGood = "good" -) - -func recvUDPPacket(c http.Client, port uint16) (string, error) { - klog.Infof("sending request to http://localhost:%d/network/recv", port) - resp, err := c.Get(fmt.Sprintf("http://localhost:%d/network/recv", port)) - if err != nil { - return "", err - } - - out, err := ioutil.ReadAll(resp.Body) - defer resp.Body.Close() - if err != nil { - return "", err - } - - result := string(out) - return result, nil -} - -func sendUDPPacket(c http.Client, port uint16, targetIP string) error { - body := []byte(fmt.Sprintf("{\"targetIP\":\"%s\"}", targetIP)) - klog.Infof("sending request to http://localhost:%d/network/send with body: %s", port, string(body)) - - resp, err := c.Post(fmt.Sprintf("http://localhost:%d/network/send", port), "application/json", bytes.NewReader(body)) - if err != nil { - return err - } - - out, err := ioutil.ReadAll(resp.Body) - defer resp.Body.Close() - if err != nil { - return err - } - - result := string(out) - if result != "send successfully\n" { - return fmt.Errorf("doesn't send successfully") - } - - klog.Info("send request successfully") - return nil -} - -func testNetworkDelay(c http.Client, port uint16, targetIP string) (int64, error) { - body := []byte(fmt.Sprintf("{\"targetIP\":\"%s\"}", targetIP)) - klog.Infof("sending request to localhost:%d with body: %s", port, string(body)) - - resp, err := c.Post(fmt.Sprintf("http://localhost:%d/network/ping", port), "application/json", bytes.NewReader(body)) - if err != nil { - return 0, err - } - - out, err := ioutil.ReadAll(resp.Body) - defer resp.Body.Close() - if err != nil { - return 0, err - } - - result := string(out) - parts := strings.Split(result, " ") - if len(parts) != 2 { - return 0, fmt.Errorf("the length of parts is not 2 %v", parts) - } - - if parts[0] != "OK" { - return 0, fmt.Errorf("the first part of response is not OK") - } - - return strconv.ParseInt(parts[1], 10, 64) -} - -func makeNetworkPartitionChaos( - namespace, name string, fromLabelSelectors, toLabelSelectors map[string]string, - fromPodMode, toPodMode v1alpha1.PodMode, - direction v1alpha1.Direction, - duration *string, - schedulerSpec *v1alpha1.SchedulerSpec, -) *v1alpha1.NetworkChaos { - var target *v1alpha1.Target - if toLabelSelectors != nil { - target = &v1alpha1.Target{ - TargetSelector: v1alpha1.SelectorSpec{ - Namespaces: []string{namespace}, - LabelSelectors: toLabelSelectors, - }, - TargetMode: toPodMode, - } - } - - return &v1alpha1.NetworkChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: v1alpha1.NetworkChaosSpec{ - Action: v1alpha1.PartitionAction, - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{namespace}, - LabelSelectors: fromLabelSelectors, - }, - Mode: fromPodMode, - Direction: direction, - Target: target, - Duration: duration, - Scheduler: schedulerSpec, - }, - } -} - -func makeNetworkDelayChaos( - namespace, name string, fromLabelSelectors, toLabelSelectors map[string]string, - fromPodMode, toPodMode v1alpha1.PodMode, direction v1alpha1.Direction, tcparam v1alpha1.TcParameter, duration *string, - schedulerSpec *v1alpha1.SchedulerSpec, -) *v1alpha1.NetworkChaos { - var target *v1alpha1.Target - if toLabelSelectors != nil { - target = &v1alpha1.Target{ - TargetSelector: v1alpha1.SelectorSpec{ - Namespaces: []string{namespace}, - LabelSelectors: toLabelSelectors, - }, - TargetMode: toPodMode, - } - } - - return &v1alpha1.NetworkChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: v1alpha1.NetworkChaosSpec{ - Action: v1alpha1.DelayAction, - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{namespace}, - LabelSelectors: fromLabelSelectors, - }, - Mode: fromPodMode, - TcParameter: tcparam, - Duration: duration, - Scheduler: schedulerSpec, - Target: target, - Direction: direction, - }, - } -} - -func probeNetworkCondition(c http.Client, peers []*corev1.Pod, ports []uint16, bidirection bool) map[string][][]int { - result := make(map[string][][]int) - - testDelay := func(from int, to int) (int64, error) { - return testNetworkDelay(c, ports[from], peers[to].Status.PodIP) - } - - for source := 0; source < len(peers); source++ { - initialTarget := source + 1 - if bidirection { - initialTarget = 0 - } - for target := initialTarget; target < len(peers); target++ { - if target == source { - continue - } - - connectable := true - - var ( - wg sync.WaitGroup - link1, link2 bool - ) - wg.Add(2) - go func() { - defer wg.Done() - // case 1-1: source to target blocked? - klog.Infof("testing connectivity from %s to %s", peers[source].Name, peers[target].Name) - link1 = couldConnect(c, ports[source], peers[target].Status.PodIP, ports[target]) - - }() - - go func() { - defer wg.Done() - // case 1-2: target to source blocked? - klog.Infof("testing connectivity from %s to %s", peers[target].Name, peers[source].Name) - link2 = couldConnect(c, ports[target], peers[source].Status.PodIP, ports[source]) - }() - wg.Wait() - - if !link1 { - klog.Infof("%s could not connect to %s", peers[source].Name, peers[target].Name) - result[networkConditionBlocked] = append(result[networkConditionBlocked], []int{source, target}) - connectable = false - } - if !link2 { - klog.Infof("%s could not connect to %s", peers[target].Name, peers[source].Name) - result[networkConditionBlocked] = append(result[networkConditionBlocked], []int{target, source}) - connectable = false - } - - if !connectable { - continue - } - - // case 2: slow network - klog.Infof("testing delay from %s to %s", peers[source].Name, peers[target].Name) - delay, err := testDelay(source, target) - if err != nil { - klog.Errorf("error from %d to %d: %v", source, target, err) - continue - } - - klog.Infof("delay from %d to %d: %d", source, target, delay) - if delay > 100*1e6 { - klog.Infof("detect slow network from %s to %s", peers[source].Name, peers[target].Name) - result[networkConditionSlow] = append(result[networkConditionSlow], []int{source, target}) - continue - } - - // case 3: otherwise, good network - klog.Infof("good network from %d to %d", source, target) - result[networkConditionGood] = append(result[networkConditionGood], []int{source, target}) - } - } - - return result -} - -func couldConnect(c http.Client, sourcePort uint16, targetPodIP string, targetPort uint16) bool { - err := sendUDPPacket(c, sourcePort, targetPodIP) - if err != nil { - klog.Infof("Error: %v", err) - return false - } - - time.Sleep(time.Second) - - data, err := recvUDPPacket(c, targetPort) - if err != nil { - klog.Infof("Error: %v, Data: %s", err, data) - return false - } - - // FIXME: slow network may also make this happens - if data != "ping\n" { - klog.Infof("mismatch data return: %s, it may happens under bad network", data) - } - - return true -} diff --git a/test/e2e/chaos/networkchaos/network_partition.go b/test/e2e/chaos/networkchaos/network_partition.go deleted file mode 100644 index 247adb84db..0000000000 --- a/test/e2e/chaos/networkchaos/network_partition.go +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package networkchaos - -import ( - "context" - "net/http" - "strings" - "time" - - . "github.com/onsi/ginkgo" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes" - "k8s.io/klog" - "k8s.io/kubernetes/test/e2e/framework" - "k8s.io/utils/pointer" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/test/e2e/util" - "github.com/chaos-mesh/chaos-mesh/test/pkg/fixture" -) - -// TestcaseForbidHostNetwork We do NOT allow that inject chaos on a pod which uses hostNetwork -func TestcaseForbidHostNetwork( - ns string, - kubeCli kubernetes.Interface, - cli client.Client, -) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - By("preparing experiment pods") - name := "network-peer-4" - nd := fixture.NewNetworkTestDeployment(name, ns, map[string]string{"partition": "0"}) - nd.Spec.Template.Spec.HostNetwork = true - _, err := kubeCli.AppsV1().Deployments(ns).Create(nd) - framework.ExpectNoError(err, "create network-peer deployment error") - err = util.WaitDeploymentReady(name, ns, kubeCli) - framework.ExpectNoError(err, "wait network-peer deployment ready error") - - By("create network partition chaos CRD objects") - networkPartition := makeNetworkPartitionChaos( - ns, "network-chaos-1", - map[string]string{"app": "network-peer-4"}, - map[string]string{"app": "network-peer-1"}, - v1alpha1.OnePodMode, - v1alpha1.OnePodMode, - v1alpha1.To, - pointer.StringPtr("9m"), - &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", - }, - ) - - err = cli.Create(ctx, networkPartition.DeepCopy()) - framework.ExpectNoError(err, "create network chaos error") - - By("waiting for rejecting for network chaos with hostNetwork") - err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { - err = cli.Get(ctx, types.NamespacedName{ - Namespace: ns, - Name: "network-chaos-1", - }, networkPartition) - if err != nil { - return false, err - } - experimentPhase := networkPartition.Status.ChaosStatus.Experiment.Phase - klog.Infof("current chaos phase: %s", experimentPhase) - if experimentPhase == v1alpha1.ExperimentPhaseFailed { - return true, nil - } - return false, nil - }) - - framework.ExpectNoError(err, "failed to waiting on ExperimentPhaseFailed state with chaos") - framework.ExpectEqual(networkPartition.Status.ChaosStatus.Experiment.Phase, v1alpha1.ExperimentPhaseFailed) - framework.ExpectEqual(strings.Contains(networkPartition.Status.ChaosStatus.FailedMessage, "it's dangerous to inject network chaos on a pod"), true) -} - -func TestcaseNetworkPartition( - ns string, - cli client.Client, - networkPeers []*corev1.Pod, - ports []uint16, - c http.Client, -) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - By("prepare experiment playground") - for index := range networkPeers { - err := util.WaitE2EHelperReady(c, ports[index]) - - framework.ExpectNoError(err, "wait e2e helper ready error") - } - - var result map[string][][]int - wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { - result = probeNetworkCondition(c, networkPeers, ports, false) - if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { - return false, nil - } - return true, nil - }) - framework.ExpectEqual(len(result[networkConditionBlocked]), 0) - framework.ExpectEqual(len(result[networkConditionSlow]), 0) - - var ( - testDelayDuration = pointer.StringPtr("9m") - testDelaySchedulerSpec = &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", - } - ) - - baseNetworkPartition := makeNetworkPartitionChaos( - ns, "network-chaos-1", - map[string]string{"app": "network-peer-0"}, - map[string]string{"app": "network-peer-1"}, - v1alpha1.OnePodMode, - v1alpha1.OnePodMode, - v1alpha1.To, - testDelayDuration, - testDelaySchedulerSpec, - ) - - By("block from peer-0 to peer-1") - err := cli.Create(ctx, baseNetworkPartition.DeepCopy()) - framework.ExpectNoError(err, "create network chaos error") - - wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { - result = probeNetworkCondition(c, networkPeers, ports, false) - if len(result[networkConditionBlocked]) != 1 || len(result[networkConditionSlow]) != 0 { - return false, nil - } - return true, nil - }) - framework.ExpectEqual(result[networkConditionBlocked], [][]int{{0, 1}}) - framework.ExpectEqual(len(result[networkConditionSlow]), 0) - - By("recover") - err = cli.Delete(ctx, baseNetworkPartition.DeepCopy()) - framework.ExpectNoError(err, "delete network chaos error") - - wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { - result = probeNetworkCondition(c, networkPeers, ports, false) - if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { - return false, nil - } - return true, nil - }) - framework.ExpectEqual(len(result[networkConditionBlocked]), 0) - framework.ExpectEqual(len(result[networkConditionSlow]), 0) - - By("block both from peer-0 to peer-1 and from peer-1 to peer-0") - bothDirectionNetworkPartition := makeNetworkPartitionChaos( - ns, "network-chaos-1", - map[string]string{"app": "network-peer-0"}, - map[string]string{"app": "network-peer-1"}, - v1alpha1.OnePodMode, - v1alpha1.OnePodMode, - v1alpha1.Both, - testDelayDuration, - testDelaySchedulerSpec, - ) - err = cli.Create(ctx, bothDirectionNetworkPartition.DeepCopy()) - framework.ExpectNoError(err, "create network chaos error") - - wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { - result = probeNetworkCondition(c, networkPeers, ports, false) - if len(result[networkConditionBlocked]) != 2 || len(result[networkConditionSlow]) != 0 { - return false, nil - } - return true, nil - }) - framework.ExpectEqual(result[networkConditionBlocked], [][]int{{0, 1}, {1, 0}}) - framework.ExpectEqual(len(result[networkConditionSlow]), 0) - - By("recover") - err = cli.Delete(ctx, bothDirectionNetworkPartition.DeepCopy()) - framework.ExpectNoError(err, "delete network chaos error") - - wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { - result = probeNetworkCondition(c, networkPeers, ports, false) - if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { - return false, nil - } - return true, nil - }) - framework.ExpectEqual(len(result[networkConditionBlocked]), 0) - framework.ExpectEqual(len(result[networkConditionSlow]), 0) - - By("block from peer-1 to peer-0") - fromDirectionNetworkPartition := makeNetworkPartitionChaos( - ns, "network-chaos-1", - map[string]string{"app": "network-peer-0"}, - map[string]string{"app": "network-peer-1"}, - v1alpha1.OnePodMode, - v1alpha1.OnePodMode, - v1alpha1.From, - testDelayDuration, - testDelaySchedulerSpec, - ) - - err = cli.Create(ctx, fromDirectionNetworkPartition.DeepCopy()) - framework.ExpectNoError(err, "create network chaos error") - - wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { - result = probeNetworkCondition(c, networkPeers, ports, false) - if len(result[networkConditionBlocked]) != 1 || len(result[networkConditionSlow]) != 0 { - return false, nil - } - return true, nil - }) - framework.ExpectEqual(result[networkConditionBlocked], [][]int{{1, 0}}) - framework.ExpectEqual(len(result[networkConditionSlow]), 0) - - By("recover") - err = cli.Delete(ctx, fromDirectionNetworkPartition.DeepCopy()) - framework.ExpectNoError(err, "delete network chaos error") - - wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { - result = probeNetworkCondition(c, networkPeers, ports, false) - if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { - return false, nil - } - return true, nil - }) - framework.ExpectEqual(len(result[networkConditionBlocked]), 0) - framework.ExpectEqual(len(result[networkConditionSlow]), 0) - - By("network partition 1") - - bothDirectionWithPartitionNetworkPartition := makeNetworkPartitionChaos( - ns, "network-chaos-1", - map[string]string{"app": "network-peer-0"}, - map[string]string{"partition": "1"}, - v1alpha1.OnePodMode, - v1alpha1.AllPodMode, - v1alpha1.Both, - testDelayDuration, - testDelaySchedulerSpec, - ) - err = cli.Create(ctx, bothDirectionWithPartitionNetworkPartition.DeepCopy()) - framework.ExpectNoError(err, "create network chaos error") - - wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { - result = probeNetworkCondition(c, networkPeers, ports, false) - if len(result[networkConditionBlocked]) != 4 || len(result[networkConditionSlow]) != 0 { - return false, nil - } - return true, nil - }) - framework.ExpectEqual(result[networkConditionBlocked], [][]int{{0, 1}, {1, 0}, {0, 3}, {3, 0}}) - framework.ExpectEqual(len(result[networkConditionSlow]), 0) - - By("recover") - err = cli.Delete(ctx, bothDirectionWithPartitionNetworkPartition.DeepCopy()) - framework.ExpectNoError(err, "delete network chaos error") - - wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { - result = probeNetworkCondition(c, networkPeers, ports, false) - if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { - return false, nil - } - return true, nil - }) - framework.ExpectEqual(len(result[networkConditionBlocked]), 0) - framework.ExpectEqual(len(result[networkConditionSlow]), 0) - - By("multiple network partition chaos on peer-0") - anotherNetworkPartition := makeNetworkPartitionChaos( - ns, "network-chaos-2", - map[string]string{"app": "network-peer-0"}, - map[string]string{"partition": "0"}, - v1alpha1.OnePodMode, - v1alpha1.AllPodMode, - v1alpha1.To, - testDelayDuration, - testDelaySchedulerSpec, - ) - err = cli.Create(ctx, bothDirectionWithPartitionNetworkPartition.DeepCopy()) - framework.ExpectNoError(err, "create network chaos error") - err = cli.Create(ctx, anotherNetworkPartition.DeepCopy()) - framework.ExpectNoError(err, "create network chaos error") - - wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { - result = probeNetworkCondition(c, networkPeers, ports, false) - if len(result[networkConditionBlocked]) != 5 || len(result[networkConditionSlow]) != 0 { - return false, nil - } - return true, nil - }) - framework.ExpectEqual(result[networkConditionBlocked], [][]int{{0, 1}, {1, 0}, {0, 2}, {0, 3}, {3, 0}}) - framework.ExpectEqual(len(result[networkConditionSlow]), 0) - - By("recover") - err = cli.Delete(ctx, bothDirectionWithPartitionNetworkPartition.DeepCopy()) - framework.ExpectNoError(err, "delete network chaos error") - err = cli.Delete(ctx, anotherNetworkPartition.DeepCopy()) - framework.ExpectNoError(err, "delete network chaos error") - - wait.Poll(time.Second, 15*time.Second, func() (done bool, err error) { - klog.Info("retry probeNetworkCondition") - result = probeNetworkCondition(c, networkPeers, ports, false) - if len(result[networkConditionBlocked]) != 0 || len(result[networkConditionSlow]) != 0 { - return false, nil - } - return true, nil - }) - framework.ExpectEqual(len(result[networkConditionBlocked]), 0) - framework.ExpectEqual(len(result[networkConditionSlow]), 0) -} diff --git a/test/e2e/chaos/podchaos/container_kill.go b/test/e2e/chaos/podchaos/container_kill.go deleted file mode 100644 index eb6ab3a353..0000000000 --- a/test/e2e/chaos/podchaos/container_kill.go +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package podchaos - -import ( - "context" - "time" - - . "github.com/onsi/ginkgo" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes" - "k8s.io/kubernetes/test/e2e/framework" - "k8s.io/utils/pointer" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/test/e2e/util" - "github.com/chaos-mesh/chaos-mesh/test/pkg/fixture" -) - -func TestcaseContainerKillOnceThenDelete(ns string, kubeCli kubernetes.Interface, cli client.Client) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - nd := fixture.NewCommonNginxDeployment("nginx", ns, 1) - _, err := kubeCli.AppsV1().Deployments(ns).Create(nd) - framework.ExpectNoError(err, "create nginx deployment error") - err = util.WaitDeploymentReady("nginx", ns, kubeCli) - framework.ExpectNoError(err, "wait nginx deployment ready error") - - listOption := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(map[string]string{ - "app": "nginx", - }).String(), - } - var originalRestartTimes int32 - pods, err := kubeCli.CoreV1().Pods(ns).List(listOption) - framework.ExpectNoError(err, "fail to get pods") - pod := pods.Items[0] - for _, cs := range pod.Status.ContainerStatuses { - if cs.Name == "nginx" { - originalRestartTimes = cs.RestartCount - break - } - } - - containerKillChaos := &v1alpha1.PodChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: "nginx-container-kill", - Namespace: ns, - }, - Spec: v1alpha1.PodChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ - ns, - }, - LabelSelectors: map[string]string{ - "app": "nginx", - }, - }, - Action: v1alpha1.ContainerKillAction, - Mode: v1alpha1.OnePodMode, - ContainerName: "nginx", - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10s", - }, - }, - } - err = cli.Create(ctx, containerKillChaos) - framework.ExpectNoError(err, "create container kill chaos error") - - err = wait.PollImmediate(5*time.Second, 5*time.Minute, func() (done bool, err error) { - listOption := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(map[string]string{ - "app": "nginx", - }).String(), - } - pods, err := kubeCli.CoreV1().Pods(ns).List(listOption) - if err != nil { - return false, nil - } - if len(pods.Items) != 1 { - return false, nil - } - pod := pods.Items[0] - for _, cs := range pod.Status.ContainerStatuses { - if cs.Name == "nginx" && ((!cs.Ready && cs.LastTerminationState.Terminated != nil) || cs.RestartCount > originalRestartTimes) { - return true, nil - } - } - return false, nil - }) - framework.ExpectNoError(err, "container kill apply failed") - - err = cli.Delete(ctx, containerKillChaos) - framework.ExpectNoError(err, "failed to delete container kill chaos") - - By("success to perform container kill") - err = wait.PollImmediate(5*time.Second, 5*time.Minute, func() (done bool, err error) { - listOption := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(map[string]string{ - "app": "nginx", - }).String(), - } - pods, err := kubeCli.CoreV1().Pods(ns).List(listOption) - if err != nil { - return false, nil - } - if len(pods.Items) != 1 { - return false, nil - } - pod := pods.Items[0] - for _, cs := range pod.Status.ContainerStatuses { - if cs.Name == "nginx" && cs.Ready && cs.State.Running != nil { - return true, nil - } - } - return false, nil - }) - framework.ExpectNoError(err, "container kill recover failed") - -} - -func TestcaseContainerKillPauseThenUnPause(ns string, kubeCli kubernetes.Interface, cli client.Client) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - nd := fixture.NewCommonNginxDeployment("nginx", ns, 1) - _, err := kubeCli.AppsV1().Deployments(ns).Create(nd) - framework.ExpectNoError(err, "create nginx deployment error") - err = util.WaitDeploymentReady("nginx", ns, kubeCli) - framework.ExpectNoError(err, "wait nginx deployment ready error") - - var pods *corev1.PodList - var newPods *corev1.PodList - listOption := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(map[string]string{ - "app": "nginx", - }).String(), - } - pods, err = kubeCli.CoreV1().Pods(ns).List(listOption) - framework.ExpectNoError(err, "get nginx pods error") - - // Get the running nginx container ID - containerID := pods.Items[0].Status.ContainerStatuses[0].ContainerID - - containerKillChaos := &v1alpha1.PodChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: "nginx-container-kill", - Namespace: ns, - }, - Spec: v1alpha1.PodChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ - ns, - }, - LabelSelectors: map[string]string{ - "app": "nginx", - }, - }, - Action: v1alpha1.ContainerKillAction, - Mode: v1alpha1.OnePodMode, - ContainerName: "nginx", - Duration: pointer.StringPtr("9m"), - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", - }, - }, - } - err = cli.Create(ctx, containerKillChaos) - framework.ExpectNoError(err, "create container kill chaos error") - - chaosKey := types.NamespacedName{ - Namespace: ns, - Name: "nginx-container-kill", - } - - // nginx container is killed as expected - err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - newPods, err = kubeCli.CoreV1().Pods(ns).List(listOption) - framework.ExpectNoError(err, "get nginx pods error") - return containerID != newPods.Items[0].Status.ContainerStatuses[0].ContainerID, nil - }) - framework.ExpectNoError(err, "wait container kill failed") - - // pause experiment - err = util.PauseChaos(ctx, cli, containerKillChaos) - framework.ExpectNoError(err, "pause chaos error") - - err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - chaos := &v1alpha1.PodChaos{} - err = cli.Get(ctx, chaosKey, chaos) - framework.ExpectNoError(err, "get pod chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhasePaused { - return true, nil - } - return false, err - }) - framework.ExpectNoError(err, "check paused chaos failed") - - // wait for 1 minutes and check whether nginx container will be killed or not - pods, err = kubeCli.CoreV1().Pods(ns).List(listOption) - framework.ExpectNoError(err, "get nginx pods error") - containerID = pods.Items[0].Status.ContainerStatuses[0].ContainerID - err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { - newPods, err = kubeCli.CoreV1().Pods(ns).List(listOption) - framework.ExpectNoError(err, "get nginx pods error") - return containerID != newPods.Items[0].Status.ContainerStatuses[0].ContainerID, nil - }) - framework.ExpectError(err, "wait container not killed failed") - framework.ExpectEqual(err.Error(), wait.ErrWaitTimeout.Error()) - - // resume experiment - err = util.UnPauseChaos(ctx, cli, containerKillChaos) - framework.ExpectNoError(err, "resume chaos error") - - err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - chaos := &v1alpha1.PodChaos{} - err = cli.Get(ctx, chaosKey, chaos) - framework.ExpectNoError(err, "get pod chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhaseRunning { - return true, nil - } - return false, err - }) - framework.ExpectNoError(err, "check resumed chaos failed") - - // nginx container is killed by resumed experiment - pods, err = kubeCli.CoreV1().Pods(ns).List(listOption) - framework.ExpectNoError(err, "get nginx pods error") - containerID = pods.Items[0].Status.ContainerStatuses[0].ContainerID - err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - newPods, err = kubeCli.CoreV1().Pods(ns).List(listOption) - framework.ExpectNoError(err, "get nginx pods error") - return containerID != newPods.Items[0].Status.ContainerStatuses[0].ContainerID, nil - }) - framework.ExpectNoError(err, "wait container killed failed") - -} diff --git a/test/e2e/chaos/podchaos/misc.go b/test/e2e/chaos/podchaos/misc.go deleted file mode 100644 index 079b0b4d35..0000000000 --- a/test/e2e/chaos/podchaos/misc.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package podchaos - -import ( - "time" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes" -) - -func waitPodRunning(name, namespace string, cli kubernetes.Interface) error { - return wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - pod, err := cli.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{}) - if err != nil { - return false, nil - } - if pod.Status.Phase != corev1.PodRunning { - return false, nil - } - return true, nil - }) -} diff --git a/test/e2e/chaos/podchaos/pod_kill.go b/test/e2e/chaos/podchaos/pod_kill.go deleted file mode 100644 index deb36b33d3..0000000000 --- a/test/e2e/chaos/podchaos/pod_kill.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package podchaos - -import ( - "context" - "time" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/test/e2e/util" - "github.com/chaos-mesh/chaos-mesh/test/pkg/fixture" - - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes" - "k8s.io/kubernetes/test/e2e/framework" - "k8s.io/utils/pointer" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -func TestcasePodKillOnceThenDelete(ns string, kubeCli kubernetes.Interface, cli client.Client) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - pod := fixture.NewCommonNginxPod("nginx", ns) - _, err := kubeCli.CoreV1().Pods(ns).Create(pod) - framework.ExpectNoError(err, "create nginx pod error") - err = waitPodRunning("nginx", ns, kubeCli) - framework.ExpectNoError(err, "wait nginx running error") - - podKillChaos := &v1alpha1.PodChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: "nginx-kill", - Namespace: ns, - }, - Spec: v1alpha1.PodChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ - ns, - }, - LabelSelectors: map[string]string{ - "app": "nginx", - }, - }, - Action: v1alpha1.PodKillAction, - Mode: v1alpha1.OnePodMode, - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10s", - }, - }, - } - err = cli.Create(ctx, podKillChaos) - framework.ExpectNoError(err, "create pod chaos error") - - err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - _, err = kubeCli.CoreV1().Pods(ns).Get("nginx", metav1.GetOptions{}) - if err != nil && apierrors.IsNotFound(err) { - return true, nil - } - return false, nil - }) - framework.ExpectNoError(err, "Pod kill chaos perform failed") - -} -func TestcasePodKillPauseThenUnPause(ns string, kubeCli kubernetes.Interface, cli client.Client) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - nd := fixture.NewCommonNginxDeployment("nginx", ns, 3) - _, err := kubeCli.AppsV1().Deployments(ns).Create(nd) - framework.ExpectNoError(err, "create nginx deployment error") - err = util.WaitDeploymentReady("nginx", ns, kubeCli) - framework.ExpectNoError(err, "wait nginx deployment ready error") - - var pods *corev1.PodList - var newPods *corev1.PodList - listOption := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(map[string]string{ - "app": "nginx", - }).String(), - } - pods, err = kubeCli.CoreV1().Pods(ns).List(listOption) - framework.ExpectNoError(err, "get nginx pods error") - - podKillChaos := &v1alpha1.PodChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: "nginx-kill", - Namespace: ns, - }, - Spec: v1alpha1.PodChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "nginx"}, - }, - Action: v1alpha1.PodKillAction, - Mode: v1alpha1.OnePodMode, - Duration: pointer.StringPtr("9m"), - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", - }, - }, - } - err = cli.Create(ctx, podKillChaos) - framework.ExpectNoError(err, "create pod chaos error") - - chaosKey := types.NamespacedName{ - Namespace: ns, - Name: "nginx-kill", - } - - // some pod is killed as expected - err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - newPods, err = kubeCli.CoreV1().Pods(ns).List(listOption) - framework.ExpectNoError(err, "get nginx pods error") - return !fixture.HaveSameUIDs(pods.Items, newPods.Items), nil - }) - framework.ExpectNoError(err, "wait pod killed failed") - - // pause experiment - err = util.PauseChaos(ctx, cli, podKillChaos) - framework.ExpectNoError(err, "pause chaos error") - - err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - chaos := &v1alpha1.PodChaos{} - err = cli.Get(ctx, chaosKey, chaos) - framework.ExpectNoError(err, "get pod chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhasePaused { - return true, nil - } - return false, err - }) - framework.ExpectNoError(err, "check paused chaos failed") - - // wait for 1 minutes and no pod is killed - pods, err = kubeCli.CoreV1().Pods(ns).List(listOption) - framework.ExpectNoError(err, "get nginx pods error") - err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { - newPods, err = kubeCli.CoreV1().Pods(ns).List(listOption) - framework.ExpectNoError(err, "get nginx pods error") - return !fixture.HaveSameUIDs(pods.Items, newPods.Items), nil - }) - framework.ExpectError(err, "wait pod not killed failed") - framework.ExpectEqual(err.Error(), wait.ErrWaitTimeout.Error()) - - // resume experiment - err = util.UnPauseChaos(ctx, cli, podKillChaos) - framework.ExpectNoError(err, "resume chaos error") - - err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - chaos := &v1alpha1.PodChaos{} - err = cli.Get(ctx, chaosKey, chaos) - framework.ExpectNoError(err, "get pod chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhaseRunning { - return true, nil - } - return false, err - }) - framework.ExpectNoError(err, "check resumed chaos failed") - - // some pod is killed by resumed experiment - err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - newPods, err = kubeCli.CoreV1().Pods(ns).List(listOption) - framework.ExpectNoError(err, "get nginx pods error") - return !fixture.HaveSameUIDs(pods.Items, newPods.Items), nil - }) - framework.ExpectNoError(err, "wait pod killed failed") - -} diff --git a/test/e2e/chaos/sidecar/misc.go b/test/e2e/chaos/sidecar/misc.go deleted file mode 100644 index e8c460bda6..0000000000 --- a/test/e2e/chaos/sidecar/misc.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package sidecar - -import ( - "context" - "strings" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/klog" - "k8s.io/utils/exec" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/test/e2e/e2econst" -) - -func createTemplateConfig( - ctx context.Context, - cli client.Client, - name string, - data map[string]string, -) error { - cm := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: e2econst.ChaosMeshNamespace, - Name: name, - Labels: map[string]string{ - "app.kubernetes.io/component": "template", - }, - }, - Data: data, - } - return cli.Create(ctx, cm) -} - -func createInjectionConfig( - ctx context.Context, - cli client.Client, - ns, name string, - data map[string]string, -) error { - cm := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: ns, - Name: name, - Labels: map[string]string{ - "app.kubernetes.io/component": "webhook", - }, - }, - Data: data, - } - return cli.Create(ctx, cm) -} - -// enableWebhook enables webhook on the specific namespace -func enableWebhook(ns string) error { - args := []string{"label", "ns", ns, "--overwrite", "admission-webhook=enabled"} - out, err := exec.New().Command("kubectl", args...).CombinedOutput() - if err != nil { - klog.Fatalf("Failed to run 'kubectl %s'\nCombined output: %q\nError: %v", strings.Join(args, " "), string(out), err) - } - return nil -} diff --git a/test/e2e/chaos/stresschaos/misc.go b/test/e2e/chaos/stresschaos/misc.go deleted file mode 100644 index f80e72542d..0000000000 --- a/test/e2e/chaos/stresschaos/misc.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2021 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package stresschaos - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/klog" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -func makeMemoryStressChaos( - namespace, name string, - podNs, podAppName string, memorySize string, worker int, -) *v1alpha1.StressChaos { - return &v1alpha1.StressChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: v1alpha1.StressChaosSpec{ - Mode: v1alpha1.AllPodMode, - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{podNs}, - LabelSelectors: map[string]string{ - "app": podAppName, - }, - }, - Stressors: &v1alpha1.Stressors{ - MemoryStressor: &v1alpha1.MemoryStressor{ - Size: memorySize, - Stressor: v1alpha1.Stressor{Workers: worker}, - }, - }, - }, - } -} - -func makeCPUStressChaos( - namespace, name string, - podNs, podAppName string, worker int, load int, -) *v1alpha1.StressChaos { - return &v1alpha1.StressChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: v1alpha1.StressChaosSpec{ - Mode: v1alpha1.AllPodMode, - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{podNs}, - LabelSelectors: map[string]string{ - "app": podAppName, - }, - }, - Stressors: &v1alpha1.Stressors{ - CPUStressor: &v1alpha1.CPUStressor{ - Load: &load, - Stressor: v1alpha1.Stressor{Workers: worker}, - }, - }, - }, - } -} - -type StressCondition struct { - CpuTime uint64 `json:"cpuTime"` - MemoryUsage uint64 `json:"memoryUsage"` -} - -func getStressCondition(c http.Client, port uint16) (*StressCondition, error) { - klog.Infof("sending request to http://localhost:%d/stress", port) - - resp, err := c.Get(fmt.Sprintf("http://localhost:%d/stress", port)) - if err != nil { - return nil, err - } - - out, err := ioutil.ReadAll(resp.Body) - defer resp.Body.Close() - if err != nil { - return nil, err - } - - condition := &StressCondition{} - err = json.Unmarshal(out, condition) - if err != nil { - return nil, err - } - - return condition, nil -} - -func probeStressCondition( - c http.Client, peers []*corev1.Pod, ports []uint16, -) (map[int]*StressCondition, error) { - stressConditions := make(map[int]*StressCondition) - - for index, port := range ports { - stressCondition, err := getStressCondition(c, port) - if err != nil { - return nil, err - } - - stressConditions[index] = stressCondition - } - - return stressConditions, nil -} diff --git a/test/e2e/chaos/testcasetemplate/template.go b/test/e2e/chaos/testcasetemplate/template.go deleted file mode 100644 index 3c51afe4c1..0000000000 --- a/test/e2e/chaos/testcasetemplate/template.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package testcasetemplate - -import ( - . "github.com/onsi/ginkgo" - "k8s.io/client-go/kubernetes" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -func TestcaseTemplate( - ns string, - kubeCli kubernetes.Interface, - cli client.Client, - // any other parameters that you need fetch from context -) { - // describe test steps with By() statement - // here are some examples. - By("preparing experiment pods") - // some logic to create pod which will be injected chaos - By("create pod failure chaos CRD objects") - // create chaos CRD - By("waiting for assertion some pod fall into failure") - // assert that chaos is effective - By("delete pod failure chaos CRD objects") - // delete chaos CRD - By("waiting for assertion recovering") - // assert that chaos has gone -} diff --git a/test/e2e/chaos/timechaos/misc.go b/test/e2e/chaos/timechaos/misc.go deleted file mode 100644 index 021473ef8e..0000000000 --- a/test/e2e/chaos/timechaos/misc.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package timechaos - -import ( - "fmt" - "io/ioutil" - "net/http" - "time" -) - -// get pod current time in nanosecond -func getPodTimeNS(c http.Client, port uint16) (*time.Time, error) { - resp, err := c.Get(fmt.Sprintf("http://localhost:%d/time", port)) - if err != nil { - return nil, err - } - - out, err := ioutil.ReadAll(resp.Body) - defer resp.Body.Close() - if err != nil { - return nil, err - } - - t, err := time.Parse(time.RFC3339Nano, string(out)) - if err != nil { - return nil, err - } - return &t, nil -} diff --git a/test/e2e/chaos/timechaos/time_skew.go b/test/e2e/chaos/timechaos/time_skew.go deleted file mode 100644 index 7f959a8039..0000000000 --- a/test/e2e/chaos/timechaos/time_skew.go +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package timechaos - -import ( - "context" - "fmt" - "net/http" - "time" - - . "github.com/onsi/ginkgo" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/kubernetes/test/e2e/framework" - "k8s.io/utils/pointer" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/test/e2e/util" -) - -func TestcaseTimeSkewOnceThenRecover( - ns string, - cli client.Client, - c http.Client, - port uint16, -) { - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - By("wait e2e helper ready") - err := util.WaitE2EHelperReady(c, port) - framework.ExpectNoError(err, "wait e2e helper ready error") - - By("create chaos CRD objects") - initTime, err := getPodTimeNS(c, port) - framework.ExpectNoError(err, "failed to get pod time") - - timeChaos := &v1alpha1.TimeChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: "timer-time-chaos", - Namespace: ns, - }, - Spec: v1alpha1.TimeChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "timer"}, - }, - Mode: v1alpha1.OnePodMode, - Duration: pointer.StringPtr("9m"), - TimeOffset: "-1h", - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", - }, - }, - } - err = cli.Create(ctx, timeChaos) - framework.ExpectNoError(err, "create time chaos error") - - By("waiting for assertion") - err = wait.PollImmediate(5*time.Second, 5*time.Minute, func() (done bool, err error) { - podTime, err := getPodTimeNS(c, port) - framework.ExpectNoError(err, "failed to get pod time") - if podTime.Before(*initTime) { - return true, nil - } - return false, nil - }) - framework.ExpectNoError(err, "time chaos doesn't work as expected") - - By("delete chaos CRD objects") - err = cli.Delete(ctx, timeChaos) - framework.ExpectNoError(err, "failed to delete time chaos") - - By("waiting for assertion recovering") - err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { - podTime, err := getPodTimeNS(c, port) - framework.ExpectNoError(err, "failed to get pod time") - // since there is no timechaos now, current pod time should not be earlier - // than the init time - if podTime.Before(*initTime) { - return true, nil - } - return false, nil - }) - framework.ExpectError(err, "wait no timechaos error") - framework.ExpectEqual(err.Error(), wait.ErrWaitTimeout.Error()) - By("success to perform time chaos") -} - -func TestcaseTimeSkewPauseThenUnpause( - ns string, - cli client.Client, - c http.Client, - port uint16, -) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - By("wait e2e helper ready") - err := util.WaitE2EHelperReady(c, port) - framework.ExpectNoError(err, "wait e2e helper ready error") - - initTime, err := getPodTimeNS(c, port) - framework.ExpectNoError(err, "failed to get pod time") - - By("create chaos CRD objects") - timeChaos := &v1alpha1.TimeChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: "timer-time-chaos", - Namespace: ns, - }, - Spec: v1alpha1.TimeChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "timer"}, - }, - Mode: v1alpha1.OnePodMode, - Duration: pointer.StringPtr("9m"), - TimeOffset: "-1h", - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: "@every 10m", - }, - }, - } - err = cli.Create(ctx, timeChaos) - framework.ExpectNoError(err, "create time chaos error") - - By("waiting for assertion") - err = wait.PollImmediate(5*time.Second, 5*time.Minute, func() (done bool, err error) { - podTime, err := getPodTimeNS(c, port) - framework.ExpectNoError(err, "failed to get pod time") - if podTime.Before(*initTime) { - return true, nil - } - return false, nil - }) - framework.ExpectNoError(err, "time chaos doesn't work as expected") - - chaosKey := types.NamespacedName{ - Namespace: ns, - Name: "timer-time-chaos", - } - - By("pause time skew chaos experiment") - // pause experiment - err = util.PauseChaos(ctx, cli, timeChaos) - framework.ExpectNoError(err, "pause chaos error") - - By("assert pause is effective") - err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - chaos := &v1alpha1.TimeChaos{} - err = cli.Get(ctx, chaosKey, chaos) - framework.ExpectNoError(err, "get time chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhasePaused { - return true, nil - } - return false, err - }) - framework.ExpectNoError(err, "check paused chaos failed") - - // wait for 1 minutes and check timer - framework.ExpectNoError(err, "get timer pod error") - err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { - podTime, err := getPodTimeNS(c, port) - framework.ExpectNoError(err, "failed to get pod time") - if podTime.Before(*initTime) { - return true, nil - } - return false, nil - }) - framework.ExpectError(err, "wait time chaos paused error") - framework.ExpectEqual(err.Error(), wait.ErrWaitTimeout.Error()) - - By("resume time skew chaos experiment") - err = util.UnPauseChaos(ctx, cli, timeChaos) - framework.ExpectNoError(err, "resume chaos error") - - By("assert chaos experiment resumed") - err = wait.Poll(5*time.Second, 5*time.Minute, func() (done bool, err error) { - chaos := &v1alpha1.TimeChaos{} - err = cli.Get(ctx, chaosKey, chaos) - framework.ExpectNoError(err, "get time chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhaseRunning { - return true, nil - } - return false, err - }) - framework.ExpectNoError(err, "check resumed chaos failed") - - // timechaos is running again, we want to check pod - // whether time is earlier than init time, - err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (done bool, err error) { - podTime, err := getPodTimeNS(c, port) - framework.ExpectNoError(err, "failed to get pod time") - if podTime.Before(*initTime) { - return true, nil - } - return false, nil - }) - framework.ExpectNoError(err, "time chaos failed") - - By("delete chaos CRD objects") - cli.Delete(ctx, timeChaos) -} - -func TestcaseTimeSkewStartAtWaitingThenIntoRunning( - ns string, - cli client.Client, - c http.Client, - port uint16, -) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - By("wait e2e helper ready") - err := util.WaitE2EHelperReady(c, port) - framework.ExpectNoError(err, "wait e2e helper ready error") - - By("create cron") - minuteNow := time.Now().Minute() - crontab := fmt.Sprintf("%d * * * *", (minuteNow+3)%60) - - By("create chaos CRD objects") - initTime, err := getPodTimeNS(c, port) - framework.ExpectNoError(err, "failed to get pod time") - - timeChaos := &v1alpha1.TimeChaos{ - ObjectMeta: metav1.ObjectMeta{ - Name: "timer-time-chaos", - Namespace: ns, - }, - Spec: v1alpha1.TimeChaosSpec{ - Selector: v1alpha1.SelectorSpec{ - Namespaces: []string{ns}, - LabelSelectors: map[string]string{"app": "timer"}, - }, - Mode: v1alpha1.OnePodMode, - Duration: pointer.StringPtr("9m"), - TimeOffset: "-1h", - Scheduler: &v1alpha1.SchedulerSpec{ - Cron: crontab, - }, - }, - } - err = cli.Create(ctx, timeChaos) - framework.ExpectNoError(err, "create time chaos error") - - chaosKey := types.NamespacedName{ - Namespace: ns, - Name: "timer-time-chaos", - } - - By("assert into waiting and chaos not take effect") - err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { - chaos := &v1alpha1.TimeChaos{} - err = cli.Get(ctx, chaosKey, chaos) - framework.ExpectNoError(err, "get time chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhaseWaiting { - return true, nil - } - return false, err - }) - framework.ExpectNoError(err, "check chaos in waiting failed") - - err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) { - podTime, err := getPodTimeNS(c, port) - framework.ExpectNoError(err, "failed to get pod time") - if podTime.Before(*initTime) { - return true, nil - } - return false, nil - }) - framework.ExpectError(err, "time chaos take effect, start error") - framework.ExpectEqual(err.Error(), wait.ErrWaitTimeout.Error()) - - By("assert into running and taking effect") - err = wait.Poll(5*time.Second, 3*time.Minute, func() (done bool, err error) { - chaos := &v1alpha1.TimeChaos{} - err = cli.Get(ctx, chaosKey, chaos) - framework.ExpectNoError(err, "get time chaos error") - if chaos.Status.Experiment.Phase == v1alpha1.ExperimentPhaseRunning { - return true, nil - } - return false, err - }) - framework.ExpectNoError(err, "check chaos in running failed") - - err = wait.PollImmediate(5*time.Second, 1*time.Minute, func() (done bool, err error) { - podTime, err := getPodTimeNS(c, port) - framework.ExpectNoError(err, "failed to get pod time") - if podTime.Before(*initTime) { - return true, nil - } - return false, nil - }) - framework.ExpectNoError(err, "time chaos doesn't work as expected") - - By("delete chaos CRD objects") - cli.Delete(ctx, timeChaos) -} diff --git a/test/e2e/config/config.go b/test/e2e/config/config.go deleted file mode 100644 index 5153762b9f..0000000000 --- a/test/e2e/config/config.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package config - -import ( - "flag" - - "k8s.io/client-go/tools/clientcmd" - clientcmdapi "k8s.io/client-go/tools/clientcmd/api" - "k8s.io/kubernetes/test/e2e/framework" - - "github.com/chaos-mesh/chaos-mesh/test" -) - -// TestConfig for the test config -var TestConfig = test.NewDefaultConfig() - -// RegisterOperatorFlags registers flags for chaos-mesh. -func RegisterOperatorFlags(flags *flag.FlagSet) { - flags.StringVar(&TestConfig.ManagerImage, "manager-image", "pingcap/chaos-mesh", "chaos-mesh image") - flags.StringVar(&TestConfig.ManagerTag, "manager-image-tag", "latest", "chaos-mesh image tag") - flags.StringVar(&TestConfig.DaemonImage, "daemon-image", "pingcap/chaos-daemon", "chaos-daemon image") - flags.StringVar(&TestConfig.DaemonTag, "daemon-image-tag", "latest", "chaos-daemon image tag") - flags.StringVar(&TestConfig.E2EImage, "e2e-image", "pingcap/e2e-helper:latest", "e2e helper image") - flags.StringVar(&TestConfig.ChaosDNSImage, "chaos-dns-image", "pingcap/coredns:v0.2.0", "chaos-dns image") - flags.BoolVar(&TestConfig.InstallChaosMesh, "install-chaos-mesh", false, "automatically install chaos-mesh") - flags.BoolVar(&TestConfig.EnableDashboard, "enable-dashboard", false, "enable Chaos Dashboard") -} - -// LoadClientRawConfig would provide client raw config -func LoadClientRawConfig() (clientcmdapi.Config, error) { - loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() - loadingRules.ExplicitPath = framework.TestContext.KubeConfig - overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults} - if framework.TestContext.KubeContext != "" { - overrides.CurrentContext = framework.TestContext.KubeContext - } - return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides).RawConfig() -} diff --git a/test/e2e/config/restclientgetter.go b/test/e2e/config/restclientgetter.go deleted file mode 100644 index 070b101634..0000000000 --- a/test/e2e/config/restclientgetter.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package config - -import ( - "path/filepath" - "regexp" - "strings" - "time" - - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/client-go/discovery" - diskcached "k8s.io/client-go/discovery/cached/disk" - "k8s.io/client-go/rest" - "k8s.io/client-go/restmapper" - "k8s.io/client-go/tools/clientcmd" - clientcmdapi "k8s.io/client-go/tools/clientcmd/api" - "k8s.io/client-go/util/homedir" -) - -var defaultCacheDir = filepath.Join(homedir.HomeDir(), ".kube", "http-cache") - -// simpleRestClientGetter implements genericclioptions.RESTClientGetter -type simpleRestClientGetter struct { - clientcmdapi.Config -} - -// ToRESTConfig returns restconfig -func (getter *simpleRestClientGetter) ToRESTConfig() (*rest.Config, error) { - return getter.ToRawKubeConfigLoader().ClientConfig() -} - -// ToDiscoveryClient returns discovery client -func (getter *simpleRestClientGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { - config, err := getter.ToRESTConfig() - if err != nil { - return nil, err - } - - config.Burst = 100 - - httpCacheDir := defaultCacheDir - discoveryCacheDir := computeDiscoverCacheDir(filepath.Join(homedir.HomeDir(), ".kube", "cache", "discovery"), config.Host) - - return diskcached.NewCachedDiscoveryClientForConfig(config, discoveryCacheDir, httpCacheDir, time.Duration(10*time.Minute)) -} - -// ToRESTMapper returns a restmapper -func (getter *simpleRestClientGetter) ToRESTMapper() (meta.RESTMapper, error) { - discoveryClient, err := getter.ToDiscoveryClient() - if err != nil { - return nil, err - } - - mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) - expander := restmapper.NewShortcutExpander(mapper, discoveryClient) - return expander, nil -} - -// ToRawKubeConfigLoader return kubeconfig loader as-is -func (getter *simpleRestClientGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig { - return clientcmd.NewDefaultClientConfig(getter.Config, &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults}) -} - -// overlyCautiousIllegalFileCharacters matches characters that *might* not be supported. Windows is really restrictive, so this is really restrictive -var overlyCautiousIllegalFileCharacters = regexp.MustCompile(`[^(\w/\.)]`) - -// computeDiscoverCacheDir takes the parentDir and the host and comes up with a "usually non-colliding" name. -func computeDiscoverCacheDir(parentDir, host string) string { - // strip the optional scheme from host if its there: - schemelessHost := strings.Replace(strings.Replace(host, "https://", "", 1), "http://", "", 1) - // now do a simple collapse of non-AZ09 characters. Collisions are possible but unlikely. Even if we do collide the problem is short lived - safeHost := overlyCautiousIllegalFileCharacters.ReplaceAllString(schemelessHost, "_") - return filepath.Join(parentDir, safeHost) -} - -// NewSimpleRESTClientGetter initializes a new genericclioptions.RESTClientGetter from clientcmdapi.Config. -func NewSimpleRESTClientGetter(config clientcmdapi.Config) genericclioptions.RESTClientGetter { - return &simpleRestClientGetter{config} -} diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go deleted file mode 100644 index 106d90e0f3..0000000000 --- a/test/e2e/e2e.go +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package e2e - -import ( - // load pprof - _ "net/http/pprof" - "os/exec" - - "github.com/onsi/ginkgo" - v1 "k8s.io/api/core/v1" - apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/klog" - aggregatorclientset "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset" - "k8s.io/kubernetes/test/e2e/framework" - e2elog "k8s.io/kubernetes/test/e2e/framework/log" - e2epod "k8s.io/kubernetes/test/e2e/framework/pod" - utilnet "k8s.io/utils/net" - - "github.com/chaos-mesh/chaos-mesh/test" - e2econfig "github.com/chaos-mesh/chaos-mesh/test/e2e/config" - - // ensure auth plugins are loaded - _ "k8s.io/client-go/plugin/pkg/client/auth" -) - -// This is modified from framework.SetupSuite(). -// setupSuite is the boilerplate that can be used to setup ginkgo test suites, on the SynchronizedBeforeSuite step. -// There are certain operations we only want to run once per overall test invocation -// (such as deleting old namespaces, or verifying that all system pods are running. -// Because of the way Ginkgo runs tests in parallel, we must use SynchronizedBeforeSuite -// to ensure that these operations only run on the first parallel Ginkgo node. -func setupSuite() { - // Run only on Ginkgo node 1 - - c, err := framework.LoadClientset() - if err != nil { - klog.Fatal("Error loading client: ", err) - } - - // Delete any namespaces except those created by the system. This ensures no - // lingering resources are left over from a previous test run. - if framework.TestContext.CleanStart { - deleted, err := framework.DeleteNamespaces(c, nil, /* deleteFilter */ - []string{ - metav1.NamespaceSystem, - metav1.NamespaceDefault, - metav1.NamespacePublic, - v1.NamespaceNodeLease, - // kind local path provisioner namespace since 0.7.0 - // https://github.com/kubernetes-sigs/kind/blob/v0.7.0/pkg/build/node/storage.go#L35 - "local-path-storage", - }) - if err != nil { - e2elog.Failf("Error deleting orphaned namespaces: %v", err) - } - klog.Infof("Waiting for deletion of the following namespaces: %v", deleted) - if err := framework.WaitForNamespacesDeleted(c, deleted, framework.NamespaceCleanupTimeout); err != nil { - e2elog.Failf("Failed to delete orphaned namespaces %v: %v", deleted, err) - } - } - - // In large clusters we may get to this point but still have a bunch - // of nodes without Routes created. Since this would make a node - // unschedulable, we need to wait until all of them are schedulable. - framework.ExpectNoError(framework.WaitForAllNodesSchedulable(c, framework.TestContext.NodeSchedulableTimeout)) - - //// If NumNodes is not specified then auto-detect how many are scheduleable and not tainted - //if framework.TestContext.CloudConfig.NumNodes == framework.DefaultNumNodes { - // framework.TestContext.CloudConfig.NumNodes = len(framework.GetReadySchedulableNodesOrDie(c).Items) - //} - - // Ensure all pods are running and ready before starting tests (otherwise, - // cluster infrastructure pods that are being pulled or started can block - // test pods from running, and tests that ensure all pods are running and - // ready will fail). - podStartupTimeout := framework.TestContext.SystemPodsStartupTimeout - // TODO: In large clusters, we often observe a non-starting pods due to - // #41007. To avoid those pods preventing the whole test runs (and just - // wasting the whole run), we allow for some not-ready pods (with the - // number equal to the number of allowed not-ready nodes). - if err := e2epod.WaitForPodsRunningReady(c, metav1.NamespaceSystem, int32(framework.TestContext.MinStartupPods), int32(framework.TestContext.AllowedNotReadyNodes), podStartupTimeout, map[string]string{}); err != nil { - framework.DumpAllNamespaceInfo(c, metav1.NamespaceSystem) - framework.LogFailedContainers(c, metav1.NamespaceSystem, e2elog.Logf) - e2elog.Failf("Error waiting for all pods to be running and ready: %v", err) - } - - //if err := framework.WaitForDaemonSets(c, metav1.NamespaceSystem, int32(framework.TestContext.AllowedNotReadyNodes), framework.TestContext.SystemDaemonsetStartupTimeout); err != nil { - // e2elog.Logf("WARNING: Waiting for all daemonsets to be ready failed: %v", err) - //} - - dc := c.DiscoveryClient - - serverVersion, serverErr := dc.ServerVersion() - if serverErr != nil { - e2elog.Logf("Unexpected server error retrieving version: %v", serverErr) - } - if serverVersion != nil { - e2elog.Logf("kube-apiserver version: %s", serverVersion.GitVersion) - } -} - -var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { - if e2econfig.TestConfig.InstallChaosMesh { - ginkgo.By("Clear all helm releases") - helmClearCmd := "helm ls --all --short | xargs -n 1 -r helm delete --purge" - if err := exec.Command("sh", "-c", helmClearCmd).Run(); err != nil { - framework.Failf("failed to clear helm releases (cmd: %q, error: %v", helmClearCmd, err) - } - ginkgo.By("Clear non-kubernetes apiservices") - clearNonK8SAPIServicesCmd := "kubectl delete apiservices -l kube-aggregator.kubernetes.io/automanaged!=onstart" - if err := exec.Command("sh", "-c", clearNonK8SAPIServicesCmd).Run(); err != nil { - framework.Failf("failed to clear non-kubernetes apiservices (cmd: %q, error: %v", clearNonK8SAPIServicesCmd, err) - } - - setupSuite() - - // Get clients - config, err := framework.LoadConfig() - framework.ExpectNoError(err, "failed to load config") - kubeCli, err := kubernetes.NewForConfig(config) - framework.ExpectNoError(err, "failed to create clientset") - aggrCli, err := aggregatorclientset.NewForConfig(config) - framework.ExpectNoError(err, "failed to create clientset") - apiExtCli, err := apiextensionsclientset.NewForConfig(config) - framework.ExpectNoError(err, "failed to create clientset") - oa := test.NewOperatorAction(kubeCli, aggrCli, apiExtCli, e2econfig.TestConfig) - ocfg := test.NewDefaultOperatorConfig() - ocfg.Manager.Image = e2econfig.TestConfig.ManagerImage - ocfg.Manager.Tag = e2econfig.TestConfig.ManagerTag - ocfg.Daemon.Image = e2econfig.TestConfig.DaemonImage - ocfg.Daemon.Tag = e2econfig.TestConfig.DaemonTag - ocfg.DNSImage = e2econfig.TestConfig.ChaosDNSImage - ocfg.EnableDashboard = e2econfig.TestConfig.EnableDashboard - - oa.CleanCRDOrDie() - err = oa.InstallCRD(ocfg) - framework.ExpectNoError(err, "failed to install crd") - err = oa.DeployOperator(ocfg) - framework.ExpectNoError(err, "failed to install chaos-mesh") - } - return nil -}, func(data []byte) { - // Run on all Ginkgo nodes - setupSuitePerGinkgoNode() -}) - -var _ = ginkgo.SynchronizedAfterSuite(func() { - framework.CleanupSuite() -}, func() { - framework.AfterSuiteActions() -}) - -func setupSuitePerGinkgoNode() { - c, err := framework.LoadClientset() - if err != nil { - klog.Fatal("Error loading client: ", err) - } - framework.TestContext.IPFamily = getDefaultClusterIPFamily(c) - e2elog.Logf("Cluster IP family: %s", framework.TestContext.IPFamily) -} - -// getDefaultClusterIPFamily obtains the default IP family of the cluster -// using the Cluster IP address of the kubernetes service created in the default namespace -// This unequivocally identifies the default IP family because services are single family -// TODO: dual-stack may support multiple families per service -// but we can detect if a cluster is dual stack because pods have two addresses (one per family) -func getDefaultClusterIPFamily(c kubernetes.Interface) string { - // Get the ClusterIP of the kubernetes service created in the default namespace - svc, err := c.CoreV1().Services(metav1.NamespaceDefault).Get("kubernetes", metav1.GetOptions{}) - if err != nil { - e2elog.Failf("Failed to get kubernetes service ClusterIP: %v", err) - } - - if utilnet.IsIPv6String(svc.Spec.ClusterIP) { - return "ipv6" - } - return "ipv4" -} diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go deleted file mode 100644 index 604f94f2bd..0000000000 --- a/test/e2e/e2e_test.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package e2e - -import ( - "flag" - "fmt" - "math/rand" - "os" - "testing" - "time" - - "github.com/onsi/ginkgo" - ginkgoconfig "github.com/onsi/ginkgo/config" - "github.com/onsi/gomega" - runtimeutils "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/client-go/tools/clientcmd" - "k8s.io/component-base/logs" - "k8s.io/klog" - "k8s.io/kubernetes/test/e2e/framework" - "k8s.io/kubernetes/test/e2e/framework/config" - e2elog "k8s.io/kubernetes/test/e2e/framework/log" - "k8s.io/kubernetes/test/e2e/framework/testfiles" - "k8s.io/kubernetes/test/e2e/framework/viperconfig" - - e2econfig "github.com/chaos-mesh/chaos-mesh/test/e2e/config" - - // test sources - _ "github.com/chaos-mesh/chaos-mesh/test/e2e/chaos" -) - -var viperConfig = flag.String("viper-config", "", "The name of a viper config file (https://github.com/spf13/viper#what-is-viper). All e2e command line parameters can also be configured in such a file. May contain a path and may or may not contain the file suffix. The default is to look for an optional file with `e2e` as base name. If a file is specified explicitly, it must be present.") - -// handleFlags sets up all flags and parses the command line. -func handleFlags() { - config.CopyFlags(config.Flags, flag.CommandLine) - framework.RegisterCommonFlags(flag.CommandLine) - hackRegisterClusterFlags(flag.CommandLine) - e2econfig.RegisterOperatorFlags(flag.CommandLine) - flag.Parse() -} - -func TestMain(m *testing.M) { - // Register test flags, then parse flags. - handleFlags() - - // Now that we know which Viper config (if any) was chosen, - // parse it and update those options which weren't already set via command line flags - // (which have higher priority). - if err := viperconfig.ViperizeFlags(*viperConfig, "e2e", flag.CommandLine); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - - framework.AfterReadingAllFlags(&framework.TestContext) - - if framework.TestContext.RepoRoot != "" { - testfiles.AddFileSource(testfiles.RootFileSource{Root: framework.TestContext.RepoRoot}) - } - - rand.Seed(time.Now().UnixNano()) - os.Exit(m.Run()) -} - -func TestE2E(t *testing.T) { - RunE2ETests(t) -} - -func RunE2ETests(t *testing.T) { - runtimeutils.ReallyCrash = true - logs.InitLogs() - defer logs.FlushLogs() - - gomega.RegisterFailHandler(e2elog.Fail) - - // Run tests through the Ginkgo runner with output to console + JUnit for Jenkins - var r []ginkgo.Reporter - klog.Infof("Starting e2e run %q on Ginkgo node %d", framework.RunID, ginkgoconfig.GinkgoConfig.ParallelNode) - - ginkgo.RunSpecsWithDefaultAndCustomReporters(t, "chaosmesh e2e suit", r) -} - -// we hack framework.RegisterClusterFlags to avoid redefine flag error -// caused by controller-runtime client -func hackRegisterClusterFlags(flags *flag.FlagSet) { - framework.TestContext.KubeConfig = os.Getenv("KUBECONFIG") - if len(framework.TestContext.KubeConfig) < 1 { - klog.Fatalf("KUBECONFIG ENV NOT SET") - } - flags.BoolVar(&framework.TestContext.VerifyServiceAccount, "e2e-verify-service-account", true, "If true tests will verify the service account before running.") - flags.StringVar(&framework.TestContext.KubeContext, clientcmd.FlagContext, "", "kubeconfig context to use/override. If unset, will use value from 'current-context'") - flags.StringVar(&framework.TestContext.KubeAPIContentType, "kube-api-content-type", "application/vnd.kubernetes.protobuf", "ContentType used to communicate with apiserver") - - flags.StringVar(&framework.TestContext.KubeVolumeDir, "volume-dir", "/var/lib/kubelet", "Path to the directory containing the kubelet volumes.") - flags.StringVar(&framework.TestContext.CertDir, "cert-dir", "", "Path to the directory containing the certs. Default is empty, which doesn't use certs.") - flags.StringVar(&framework.TestContext.RepoRoot, "repo-root", "../../", "Root directory of kubernetes repository, for finding test files.") - flags.StringVar(&framework.TestContext.Provider, "provider", "", "The name of the Kubernetes provider (gce, gke, local, skeleton (the fallback if not set), etc.)") - flags.StringVar(&framework.TestContext.Tooling, "tooling", "", "The tooling in use (kops, gke, etc.)") - flags.StringVar(&framework.TestContext.OutputDir, "e2e-output-dir", "/tmp", "Output directory for interesting/useful test data, like performance data, benchmarks, and other metrics.") - flags.StringVar(&framework.TestContext.Prefix, "prefix", "e2e", "A prefix to be added to cloud resources created during testing.") - flags.StringVar(&framework.TestContext.MasterOSDistro, "master-os-distro", "debian", "The OS distribution of cluster master (debian, ubuntu, gci, coreos, or custom).") - flags.StringVar(&framework.TestContext.NodeOSDistro, "node-os-distro", "debian", "The OS distribution of cluster VM instances (debian, ubuntu, gci, coreos, or custom).") - flags.StringVar(&framework.TestContext.ClusterMonitoringMode, "cluster-monitoring-mode", "standalone", "The monitoring solution that is used in the cluster.") - flags.StringVar(&framework.TestContext.ClusterDNSDomain, "dns-domain", "cluster.local", "The DNS Domain of the cluster.") - - flags.IntVar(&framework.TestContext.MinStartupPods, "minStartupPods", 0, "The number of pods which we need to see in 'Running' state with a 'Ready' condition of true, before we try running tests. This is useful in any cluster which needs some base pod-based services running before it can be used.") - flags.DurationVar(&framework.TestContext.SystemPodsStartupTimeout, "system-pods-startup-timeout", 10*time.Minute, "Timeout for waiting for all system pods to be running before starting tests.") - flags.DurationVar(&framework.TestContext.NodeSchedulableTimeout, "node-schedulable-timeout", 30*time.Minute, "Timeout for waiting for all nodes to be schedulable.") - flags.DurationVar(&framework.TestContext.SystemDaemonsetStartupTimeout, "system-daemonsets-startup-timeout", 5*time.Minute, "Timeout for waiting for all system daemonsets to be ready.") - flags.StringVar(&framework.TestContext.EtcdUpgradeStorage, "etcd-upgrade-storage", "", "The storage version to upgrade to (either 'etcdv2' or 'etcdv3') if doing an etcd upgrade test.") - flags.StringVar(&framework.TestContext.EtcdUpgradeVersion, "etcd-upgrade-version", "", "The etcd binary version to upgrade to (e.g., '3.0.14', '2.3.7') if doing an etcd upgrade test.") - flags.StringVar(&framework.TestContext.GCEUpgradeScript, "gce-upgrade-script", "", "Script to use to upgrade a GCE cluster.") - flags.BoolVar(&framework.TestContext.CleanStart, "clean-start", false, "If true, purge all namespaces except default and system before running tests. This serves to Cleanup test namespaces from failed/interrupted e2e runs in a long-lived cluster.") - - nodeKiller := &framework.TestContext.NodeKiller - flags.BoolVar(&nodeKiller.Enabled, "node-killer", false, "Whether NodeKiller should kill any nodes.") - flags.Float64Var(&nodeKiller.FailureRatio, "node-killer-failure-ratio", 0.01, "Percentage of nodes to be killed") - flags.DurationVar(&nodeKiller.Interval, "node-killer-interval", 1*time.Minute, "Time between node failures.") - flags.Float64Var(&nodeKiller.JitterFactor, "node-killer-jitter-factor", 60, "Factor used to jitter node failures.") - flags.DurationVar(&nodeKiller.SimulatedDowntime, "node-killer-simulated-downtime", 10*time.Minute, "A delay between node death and recreation") -} diff --git a/test/e2e/e2econst/const.go b/test/e2e/e2econst/const.go deleted file mode 100644 index e195b1c1b6..0000000000 --- a/test/e2e/e2econst/const.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package e2econst - -const ( - PauseImage = "gcr.io/google-containers/pause:latest" - ChaosMeshNamespace = "chaos-testing" - ChaosControllerManager = "chaos-controller-manager" -) diff --git a/test/e2e/util/util.go b/test/e2e/util/util.go deleted file mode 100644 index 8f0bb15be0..0000000000 --- a/test/e2e/util/util.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package util - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "time" - - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes" - "sigs.k8s.io/controller-runtime/pkg/client" - - apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" - apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/util/wait" - apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" - aggregatorclientset "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset" - "k8s.io/kubernetes/test/e2e/framework" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" -) - -// WaitForAPIServicesAvailable waits for apiservices to be available -func WaitForAPIServicesAvailable(client aggregatorclientset.Interface, selector labels.Selector) error { - isAvailable := func(status apiregistrationv1.APIServiceStatus) bool { - if status.Conditions == nil { - return false - } - for _, condition := range status.Conditions { - if condition.Type == apiregistrationv1.Available { - return condition.Status == apiregistrationv1.ConditionTrue - } - } - return false - } - return wait.PollImmediate(5*time.Second, 3*time.Minute, func() (bool, error) { - apiServiceList, err := client.ApiregistrationV1().APIServices().List(metav1.ListOptions{ - LabelSelector: selector.String(), - }) - if err != nil { - return false, err - } - for _, apiService := range apiServiceList.Items { - if !isAvailable(apiService.Status) { - framework.Logf("APIService %q is not available yet", apiService.Name) - return false, nil - } - } - for _, apiService := range apiServiceList.Items { - framework.Logf("APIService %q is available", apiService.Name) - } - return true, nil - }) -} - -// WaitForCRDsEstablished waits for all CRDs to be established -func WaitForCRDsEstablished(client apiextensionsclientset.Interface, selector labels.Selector) error { - isEstablished := func(status apiextensionsv1beta1.CustomResourceDefinitionStatus) bool { - if status.Conditions == nil { - return false - } - for _, condition := range status.Conditions { - if condition.Type == apiextensionsv1beta1.Established { - return condition.Status == apiextensionsv1beta1.ConditionTrue - } - } - return false - } - return wait.PollImmediate(5*time.Second, 3*time.Minute, func() (bool, error) { - crdList, err := client.ApiextensionsV1beta1().CustomResourceDefinitions().List(metav1.ListOptions{ - LabelSelector: selector.String(), - }) - if err != nil { - return false, err - } - for _, crd := range crdList.Items { - if !isEstablished(crd.Status) { - framework.Logf("CRD %q is not established yet", crd.Name) - return false, nil - } - } - for _, crd := range crdList.Items { - framework.Logf("CRD %q is established", crd.Name) - } - return true, nil - }) -} - -// WaitDeploymentReady waits for all pods which controlled by deployment to be ready. -func WaitDeploymentReady(name, namespace string, cli kubernetes.Interface) error { - return wait.Poll(2*time.Second, 5*time.Minute, func() (done bool, err error) { - d, err := cli.AppsV1().Deployments(namespace).Get(name, metav1.GetOptions{}) - if err != nil { - return false, nil - } - if d.Status.AvailableReplicas != *d.Spec.Replicas { - return false, nil - } - if d.Status.UpdatedReplicas != *d.Spec.Replicas { - return false, nil - } - return true, nil - }) -} - -func PauseChaos(ctx context.Context, cli client.Client, chaos runtime.Object) error { - var mergePatch []byte - mergePatch, _ = json.Marshal(map[string]interface{}{ - "metadata": map[string]interface{}{ - "annotations": map[string]string{v1alpha1.PauseAnnotationKey: "true"}, - }, - }) - return cli.Patch(ctx, chaos, client.ConstantPatch(types.MergePatchType, mergePatch)) -} - -func UnPauseChaos(ctx context.Context, cli client.Client, chaos runtime.Object) error { - var mergePatch []byte - mergePatch, _ = json.Marshal(map[string]interface{}{ - "metadata": map[string]interface{}{ - "annotations": map[string]string{v1alpha1.PauseAnnotationKey: "false"}, - }, - }) - return cli.Patch(ctx, chaos, client.ConstantPatch(types.MergePatchType, mergePatch)) -} - -func WaitE2EHelperReady(c http.Client, port uint16) error { - return wait.Poll(2*time.Second, 5*time.Minute, func() (done bool, err error) { - if _, err = c.Get(fmt.Sprintf("http://localhost:%d/ping", port)); err != nil { - return false, nil - } - return true, nil - }) -} diff --git a/test/image/e2e/Dockerfile b/test/image/e2e/Dockerfile deleted file mode 100644 index dd156ba118..0000000000 --- a/test/image/e2e/Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM alpine:3.12 - -ENV KUBECTL_VERSION=v1.12.2 -ENV HELM_VERSION=v3.5.3 - -RUN apk update && apk add --no-cache ca-certificates curl git openssl bash -RUN curl https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl \ - -o /usr/local/bin/kubectl && \ - chmod +x /usr/local/bin/kubectl && \ - curl https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz \ - -o helm-${HELM_VERSION}-linux-amd64.tar.gz && \ - tar -zxvf helm-${HELM_VERSION}-linux-amd64.tar.gz && \ - mv linux-amd64/helm /usr/local/bin/helm && \ - rm -rf linux-amd64 && \ - rm helm-${HELM_VERSION}-linux-amd64.tar.gz - - -ADD chaos-mesh /charts/e2e/chaos-mesh -ADD manifests /manifests/e2e - -ADD bin/ginkgo /usr/local/bin/ -ADD bin/e2e.test /usr/local/bin/ diff --git a/test/integration_test/README.md b/test/integration_test/README.md index 5d2075b30d..cb669b185e 100644 --- a/test/integration_test/README.md +++ b/test/integration_test/README.md @@ -8,8 +8,8 @@ You can install Chaos Mesh by commands: ```bash hack/local-up-chaos-mesh.sh -kubectl set env deployment/chaos-dashboard SECURITY_MODE=true -n chaos-testing -kubectl port-forward -n chaos-testing svc/chaos-dashboard 2333:2333 & +kubectl set env deployment/chaos-dashboard SECURITY_MODE=true -n chaos-mesh +kubectl port-forward -n chaos-mesh svc/chaos-dashboard 2333:2333 & ``` 2. Install localstack && aws client(optional) diff --git a/test/integration_test/auth-rbac-webhook/podchaos-example.yaml b/test/integration_test/auth-rbac-webhook/podchaos-example.yaml index 95fe0776c7..9bd65436f5 100644 --- a/test/integration_test/auth-rbac-webhook/podchaos-example.yaml +++ b/test/integration_test/auth-rbac-webhook/podchaos-example.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: PodChaos metadata: @@ -8,5 +22,3 @@ spec: selector: labelSelectors: "app.kubernetes.io/component": "no-applications-were-harmed" - scheduler: - cron: "@every 1m" diff --git a/test/integration_test/auth-rbac-webhook/rbac.yaml b/test/integration_test/auth-rbac-webhook/rbac.yaml index e252418315..bc10952c40 100644 --- a/test/integration_test/auth-rbac-webhook/rbac.yaml +++ b/test/integration_test/auth-rbac-webhook/rbac.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# --- apiVersion: v1 kind: ServiceAccount diff --git a/test/integration_test/auth-rbac-webhook/run.sh b/test/integration_test/auth-rbac-webhook/run.sh index a3b9520ee5..f8d7bda73c 100644 --- a/test/integration_test/auth-rbac-webhook/run.sh +++ b/test/integration_test/auth-rbac-webhook/run.sh @@ -1,17 +1,18 @@ #!/usr/bin/env bash - # Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# set -eu diff --git a/test/integration_test/aws/aws_chaos.yaml b/test/integration_test/aws/aws_chaos.yaml new file mode 100644 index 0000000000..1d476b85b7 --- /dev/null +++ b/test/integration_test/aws/aws_chaos.yaml @@ -0,0 +1,26 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: AWSChaos +metadata: + name: aws-ec2-stop + namespace: chaos-mesh +spec: + action: ec2-stop + secretName: "cloud-key-secret" + awsRegion: "us-east-1" + ec2Instance: "i-c849713a387c4feb7" + endpoint: "http://192.168.39.13:31566" + duration: "5s" diff --git a/test/integration_test/aws/aws_chaos_template.yaml b/test/integration_test/aws/aws_chaos_template.yaml index 8bc62979d6..927f040979 100644 --- a/test/integration_test/aws/aws_chaos_template.yaml +++ b/test/integration_test/aws/aws_chaos_template.yaml @@ -1,8 +1,22 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 -kind: AwsChaos +kind: AWSChaos metadata: name: aws-ec2-stop - namespace: chaos-testing + namespace: chaos-mesh spec: action: ec2-stop secretName: "cloud-key-secret" @@ -10,5 +24,3 @@ spec: ec2Instance: "instance-id-placeholder" endpoint: "endpoint-placeholder" duration: "5s" - scheduler: - cron: "@every 10s" \ No newline at end of file diff --git a/test/integration_test/aws/aws_secret.yaml b/test/integration_test/aws/aws_secret.yaml index ab4841b4c3..ac8815f37b 100644 --- a/test/integration_test/aws/aws_secret.yaml +++ b/test/integration_test/aws/aws_secret.yaml @@ -1,9 +1,24 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: v1 kind: Secret metadata: name: cloud-key-secret - namespace: chaos-testing + namespace: chaos-mesh type: Opaque stringData: aws_access_key_id: test - aws_secret_access_key: test \ No newline at end of file + aws_secret_access_key: test + aws_session_token: test diff --git a/test/integration_test/aws/run.sh b/test/integration_test/aws/run.sh old mode 100644 new mode 100755 index 0a8a5b6162..dfcfc0d64c --- a/test/integration_test/aws/run.sh +++ b/test/integration_test/aws/run.sh @@ -1,17 +1,18 @@ #!/usr/bin/env bash - # Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# set -eu @@ -20,9 +21,11 @@ cd $cur # wait localstash pod status to running for ((k=0; k<30; k++)); do - not_run_num=`kubectl get pods -l app.kubernetes.io/name=localstack --no-headers | grep -v Running | wc -l` - if [ $not_run_num == 0 ]; then + JSONPATH='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{"\n"}{end}' + not_ready_num=`kubectl get pods -l app.kubernetes.io/name=localstack --no-headers -o jsonpath="$JSONPATH" | grep "Ready=False" | wc -l` + + if [ $not_ready_num == 0 ]; then break fi @@ -30,6 +33,8 @@ for ((k=0; k<30; k++)); do done kubectl port-forward svc/localstack 4566:4566 & +# kill child process +trap 'kill $(jobs -p)' EXIT NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services localstack) NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}") @@ -37,6 +42,7 @@ LOCALSTACK_SERVER="http:\/\/$NODE_IP\:$NODE_PORT" aws configure set aws_access_key_id test aws configure set aws_secret_access_key test +aws configure set aws_session_token test aws configure set default.region us-east-1 aws configure set default.output_format text @@ -82,5 +88,3 @@ fi # clean kubectl delete -f aws_chaos.yaml helm uninstall localstack -# kill child process -trap 'kill $(jobs -p)' EXIT diff --git a/test/integration_test/chaosctl/debug.sh b/test/integration_test/chaosctl/debug.sh new file mode 100644 index 0000000000..d9d744b318 --- /dev/null +++ b/test/integration_test/chaosctl/debug.sh @@ -0,0 +1,206 @@ +#!/usr/bin/env bash +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +function file_must_contains() { + file=$1 + substring=$2 + match="" + if [ "$3" = "false" ]; then + match="-v" + fi + + grep $match "$substring" $file + if [ "$?" != "0" ]; then + echo "'$substring' not found in '$file'" + exit 1 + fi +} + +set -u +log_file="debug.log" +code=0 +cur=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + +pwd +echo "Deploy deployments and chaos for testing" +wget https://mirrors.chaos-mesh.org/v1.1.2/web-show/deploy.sh +# This is a temporary fix +# TODO: remove the following line after the new deploy.sh released +sed -i "s|image: pingcap/web-show|image: ghcr.io/chaos-mesh/web-show|g" deploy.sh +bash deploy.sh + +echo "Run networkchaos" + +cat <delay.yaml +apiVersion: chaos-mesh.org/v1alpha1 +kind: NetworkChaos +metadata: + name: web-show-network-delay +spec: + action: delay # the specific chaos action to inject + mode: one # the mode to run chaos action; supported modes are one/all/fixed/fixed-percent/random-max-percent + selector: # pods where to inject chaos actions + namespaces: + - default + labelSelectors: + "app": "web-show" # the label of the pod for chaos injection + delay: + latency: "10ms" + duration: "30s" # duration for the injected chaos experiment +EOF +kubectl apply -f delay.yaml + +echo "Checking chaosctl logs" +./bin/chaosctl logs >$log_file 2>&1 +if [ $? -ne 0 ]; then + echo "chaosctl logs failed" + code=1 +fi +file_must_contains $log_file "Controller manager Version:" true +file_must_contains $log_file "Chaos-daemon Version:" true +file_must_contains $log_file "\[chaos-dashboard" true + +echo "Checking chaosctl debug networkchaos" +./bin/chaosctl debug networkchaos web-show-network-delay >$log_file 2>&1 +if [ $? -ne 0 ]; then + echo "chaosctl debug networkchaos failed, exit code: $?, log file: $log_file" + echo "log file content:" + cat $log_file + code=1 +fi +file_must_contains $log_file "\[Chaos\]: web-show-network-delay" true +file_must_contains $log_file "1. \[ipset list\]" true +file_must_contains $log_file "2. \[tc qdisc list\]" true +file_must_contains $log_file "3. \[iptables list\]" true +file_must_contains $log_file "4. \[podnetworkchaos\]" true +echo "Cleaning up networkchaos" +kubectl delete -f delay.yaml +rm delay.yaml + +echo "Run httpchaos" + +cat <delay.yaml +apiVersion: chaos-mesh.org/v1alpha1 +kind: HTTPChaos +metadata: + name: web-show-http-delay +spec: + mode: one # the mode to run chaos action; supported modes are one/all/fixed/fixed-percent/random-max-percent + selector: # pods where to inject chaos actions + namespaces: + - default + labelSelectors: + "app": "web-show" # the label of the pod for chaos injection + target: Request + port: 8081 + path: "*" + delay: "10ms" + duration: "30s" # duration for the injected chaos experiment +EOF +kubectl apply -f delay.yaml +sleep 3 +echo "Checking chaosctl debug httpchaos" +./bin/chaosctl debug httpchaos web-show-http-delay >$log_file 2>&1 +if [ $? -ne 0 ]; then + echo "chaosctl debug httpchaos failed" + code=1 +fi +file_must_contains $log_file "\[Chaos\]: web-show-http-delay" true +file_must_contains $log_file "\[podhttpchaos\]" true +echo "Cleaning up httpchaos" +kubectl delete -f delay.yaml +rm delay.yaml + +echo "Run iochaos" + +cat <delay.yaml +apiVersion: chaos-mesh.org/v1alpha1 +kind: IOChaos +metadata: + name: web-show-io-delay +spec: + action: latency + mode: one # the mode to run chaos action; supported modes are one/all/fixed/fixed-percent/random-max-percent + selector: # pods where to inject chaos actions + namespaces: + - default + labelSelectors: + "app": "web-show" # the label of the pod for chaos injection + volumePath: /var/run/secrets/kubernetes.io/serviceaccount + path: "/var/run/secrets/kubernetes.io/serviceaccount/**/*" + delay: "10ms" + percent: 50 + duration: "30s" # duration for the injected chaos experiment +EOF +kubectl apply -f delay.yaml + +# IOChaos only supports x86_64 +# TODO: support IOChaos in aarch64, and remove this condition +if [[ "$(uname -m)" == "x86_64" ]]; then + echo "Checking chaosctl debug iochaos" + ./bin/chaosctl debug iochaos web-show-io-delay >$log_file 2>&1 + if [ $? -ne 0 ]; then + echo "chaosctl debug iochaos failed" + code=1 + fi + file_must_contains $log_file "\[Chaos\]: web-show-io-delay" true + file_must_contains $log_file "1. \[Mount Information\]" true + file_must_contains $log_file "\[file descriptors of PID:" true + file_must_contains $log_file "\[podiochaos\]" true + echo "Cleaning up iochaos" + kubectl delete -f delay.yaml + rm delay.yaml +fi + +echo "Run stresschaos" + +cat <stress.yaml +apiVersion: chaos-mesh.org/v1alpha1 +kind: StressChaos +metadata: + name: web-show-memory-stress +spec: + mode: one # the mode to run chaos action; supported modes are one/all/fixed/fixed-percent/random-max-percent + selector: # pods where to inject chaos actions + namespaces: + - default + labelSelectors: + "app": "web-show" # the label of the pod for chaos injection + stressors: + memory: + workers: 4 + size: '256MB' + duration: "30s" # duration for the injected chaos experiment +EOF +kubectl apply -f stress.yaml + +echo "Checking chaosctl debug stresschaos" +./bin/chaosctl debug stresschaos web-show-memory-stress >$log_file 2>&1 +if [ $? -ne 0 ]; then + echo "chaosctl debug stresschaos failed" + code=1 +fi +file_must_contains $log_file "\[Chaos\]: web-show-memory-stress" true +file_must_contains $log_file "1. \[cat /proc/cgroups\]" true +file_must_contains $log_file "\[memory.limit_in_bytes\]" true +echo "Cleaning up stresschaos" +kubectl delete -f stress.yaml +rm stress.yaml + +rm $log_file +bash deploy.sh -d +rm deploy.sh +exit $code diff --git a/test/integration_test/chaosctl/recover.sh b/test/integration_test/chaosctl/recover.sh new file mode 100644 index 0000000000..b913faffc7 --- /dev/null +++ b/test/integration_test/chaosctl/recover.sh @@ -0,0 +1,161 @@ +#!/usr/bin/env bash +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +function must_contains() { + message=$1 + substring=$2 + match="" + if [ "$3" = "false" ]; then + match="-v" + fi + + echo $message | grep $match "$substring" + if [ "$?" != "0" ]; then + echo "'$substring' not found in '$message'" + exit 1 + fi +} + +function get_high_latency() { + # the log looks like `64 bytes from 10.244.0.9: seq=0 ttl=63 time=0.240 ms` + # get the latency from log + latencies=$(kubectl exec busybox-0 -i -n busybox -- ping -c 10 busybox-1.busybox.busybox.svc | grep "bytes from" | sed 's/.*time=\([0-9]*\).[0-9]* ms.*/\1/g') + high_latency_num=0 + for latency in $latencies + do + if [[ "$latency" -ge "10" ]]; then + high_latency_num=`expr $high_latency_num + 1` + fi + done + echo $high_latency_num +} + +echo "Deploy web-show for testing" +curl https://mirrors.chaos-mesh.org/v1.1.2/web-show/deploy.sh | bash -s + +echo "Deploy busyboxplus for test" +kubectl run busyboxplus --image=radial/busyboxplus:curl -- sleep 3600 + +echo "deploy busybox for test" +kubectl apply -f https://raw.githubusercontent.com/chaos-mesh/apps/master/ping/busybox-statefulset.yaml + +echo "wait pods status to running" +for ((k=0; k<30; k++)); do + webshow_num=$(kubectl get pods -l app=web-show | grep "Running" | wc -l) + busyboxplus_num=$(kubectl get pods busyboxplus | grep "Running" | wc -l) + busybox_num=$(kubectl get pods --namespace busybox | grep "Running" | wc -l) + if [ $webshow_num == 1 ] && [ $busyboxplus_num == 1 ] && [ $busybox_num == 2 ]; then + break + fi + sleep 1 +done + +echo "Confirm web-show works well" +must_contains "$(kubectl exec busyboxplus -- sh -c "curl -I web-show.default:8081")" "HTTP/1.1 200 OK" true + +echo "Run networkchaos" + +cat <delay.yaml +apiVersion: chaos-mesh.org/v1alpha1 +kind: NetworkChaos +metadata: + name: network-delay + namespace: busybox +spec: + action: delay + mode: all + selector: + pods: + busybox: + - busybox-0 + delay: + latency: "10ms" + duration: "5s" + direction: to + target: + selector: + pods: + busybox: + - busybox-1 + mode: all +EOF +kubectl apply -f delay.yaml + +echo "Confirm networkchaos works well" +sleep 1 # TODO: better way to wait for chaos being injected + +high_latency_num=$(get_high_latency) + +# about half of the latency should be greater than 10ms +if [[ "$high_latency_num" -lt "3" ]] || [[ "$high_latency_num" -gt "6" ]]; then + echo "the chaos dosen't work as expect" + exit 1 +fi + +echo "Recover networkchaos" +./bin/chaosctl recover networkchaos busybox-0 -n busybox + +echo "Confirm httpchaos recovered" +high_latency_num=$(get_high_latency) + +if [[ "$high_latency_num" -gt "0" ]]; then + echo "the httpchaos dosen't recover" + exit 1 +fi + +echo "Cleaning up networkchaos" +kubectl delete -f delay.yaml +rm delay.yaml + +echo "Run httpchaos" + +cat <replace.yaml +apiVersion: chaos-mesh.org/v1alpha1 +kind: HTTPChaos +metadata: + name: web-show-http-replace +spec: + mode: one # the mode to run chaos action; supported modes are one/all/fixed/fixed-percent/random-max-percent + selector: # pods where to inject chaos actions + namespaces: + - default + labelSelectors: + "app": "web-show" # the label of the pod for chaos injection + target: Response + port: 8081 + path: "*" + replace: + code: 404 +EOF +kubectl apply -f replace.yaml + +echo "Confirm httpchaos works well" +sleep 1 # TODO: better way to wait for chaos being injected +must_contains "$(kubectl exec busyboxplus -- sh -c "curl -I web-show.default:8081")" "HTTP/1.1 404 Not Found" true + +echo "Recover httpchaos" +./bin/chaosctl recover httpchaos -l app=web-show + +echo "Confirm httpchaos recovered" +must_contains "$(kubectl exec busyboxplus -- sh -c "curl -I web-show.default:8081")" "HTTP/1.1 200 OK" true + +echo "Cleaning up httpchaos" +kubectl delete -f replace.yaml +rm replace.yaml + +kubectl delete pod busyboxplus +curl https://mirrors.chaos-mesh.org/v1.1.2/web-show/deploy.sh | bash -s -- -d +kubectl delete -f https://raw.githubusercontent.com/chaos-mesh/apps/master/ping/busybox-statefulset.yaml diff --git a/test/integration_test/chaosctl/run.sh b/test/integration_test/chaosctl/run.sh index 7c2433e9b2..d835a4ef62 100644 --- a/test/integration_test/chaosctl/run.sh +++ b/test/integration_test/chaosctl/run.sh @@ -1,59 +1,34 @@ #!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. +# Copyright 2022 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# + +test_dir=test/integration_test +pwd=`pwd` -set -u -code=0 -cur=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) -cd $cur/../../../bin +function run() { + script=$1 + echo "Running test $script..." + TEST_NAME="$(basename "$(dirname "$script")")" \ + PATH="$pwd/$test_dir/utils:$PATH" \ + bash +x "$script" +} -pwd -echo "deploy deployments and chaos for testing" -wget https://mirrors.chaos-mesh.org/v1.1.2/web-show/deploy.sh -bash deploy.sh -cat <delay.yaml -apiVersion: chaos-mesh.org/v1alpha1 -kind: NetworkChaos -metadata: - name: web-show-network-delay -spec: - action: delay # the specific chaos action to inject - mode: one # the mode to run chaos action; supported modes are one/all/fixed/fixed-percent/random-max-percent - selector: # pods where to inject chaos actions - namespaces: - - default - labelSelectors: - "app": "web-show" # the label of the pod for chaos injection - delay: - latency: "10ms" - duration: "30s" # duration for the injected chaos experiment - scheduler: # scheduler rules for the running time of the chaos experiments about pods. - cron: "@every 60s" -EOF -kubectl apply -f delay.yaml +scripts=(debug.sh recover.sh) -echo "Checking chaosctl function" -./chaosctl logs 1>/dev/null -status=$(./chaosctl debug -i networkchaos web-show-network-delay | grep "Execute as expected") -echo $status -if [[ -z "$status" ]]; then - echo "Chaos is not running as expected" - code=1 -fi -echo "Cleaning up" -kubectl delete -f delay.yaml -rm delay.yaml -bash deploy.sh -d -rm deploy.sh -exit $code +for name in $scripts; do + script="$test_dir/chaosctl/$name" + echo "run $script" + run $script +done diff --git a/test/integration_test/dashboard_authority/busybox-manager.yaml b/test/integration_test/dashboard_authority/busybox-manager.yaml index d835a8e95a..94d05123fb 100644 --- a/test/integration_test/dashboard_authority/busybox-manager.yaml +++ b/test/integration_test/dashboard_authority/busybox-manager.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: @@ -41,4 +55,4 @@ subjects: roleRef: kind: Role name: role-busybox-manager - apiGroup: rbac.authorization.k8s.io \ No newline at end of file + apiGroup: rbac.authorization.k8s.io diff --git a/test/integration_test/dashboard_authority/busybox-viewer.yaml b/test/integration_test/dashboard_authority/busybox-viewer.yaml index 87a52f5bd8..48f362b64d 100644 --- a/test/integration_test/dashboard_authority/busybox-viewer.yaml +++ b/test/integration_test/dashboard_authority/busybox-viewer.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: diff --git a/test/integration_test/dashboard_authority/cluster-manager.yaml b/test/integration_test/dashboard_authority/cluster-manager.yaml index f52ba1b046..bda77fa4b5 100644 --- a/test/integration_test/dashboard_authority/cluster-manager.yaml +++ b/test/integration_test/dashboard_authority/cluster-manager.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: @@ -6,8 +20,7 @@ rules: - apiGroups: [""] resources: ["pods", "namespaces"] verbs: ["get", "watch", "list"] -- apiGroups: - - chaos-mesh.org +- apiGroups: ["chaos-mesh.org"] resources: [ "*" ] verbs: - create @@ -24,7 +37,7 @@ kind: ServiceAccount apiVersion: v1 metadata: name: account-cluster-manager - namespace: chaos-testing + namespace: chaos-mesh --- @@ -35,8 +48,8 @@ metadata: subjects: - kind: ServiceAccount name: account-cluster-manager - namespace: chaos-testing + namespace: chaos-mesh roleRef: kind: ClusterRole name: cluster-role-test-manager - apiGroup: rbac.authorization.k8s.io \ No newline at end of file + apiGroup: rbac.authorization.k8s.io diff --git a/test/integration_test/dashboard_authority/cluster-viewer.yaml b/test/integration_test/dashboard_authority/cluster-viewer.yaml index 804e51e29a..7ea888c0af 100644 --- a/test/integration_test/dashboard_authority/cluster-viewer.yaml +++ b/test/integration_test/dashboard_authority/cluster-viewer.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: @@ -6,8 +20,7 @@ rules: - apiGroups: [""] resources: ["pods", "namespaces"] verbs: ["get", "watch", "list"] -- apiGroups: - - chaos-mesh.org +- apiGroups: ["chaos-mesh.org"] resources: [ "*" ] verbs: - get @@ -20,7 +33,7 @@ kind: ServiceAccount apiVersion: v1 metadata: name: account-cluster-viewer - namespace: chaos-testing + namespace: chaos-mesh --- @@ -31,8 +44,8 @@ metadata: subjects: - kind: ServiceAccount name: account-cluster-viewer - namespace: chaos-testing + namespace: chaos-mesh roleRef: kind: ClusterRole name: cluster-role-test-viewer - apiGroup: rbac.authorization.k8s.io \ No newline at end of file + apiGroup: rbac.authorization.k8s.io diff --git a/test/integration_test/dashboard_authority/run.sh b/test/integration_test/dashboard_authority/run.sh index 0f26097303..237a879c55 100644 --- a/test/integration_test/dashboard_authority/run.sh +++ b/test/integration_test/dashboard_authority/run.sh @@ -1,17 +1,18 @@ #!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. +# Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# set -eu @@ -42,8 +43,8 @@ kubectl apply -f ./cluster-viewer.yaml kubectl apply -f ./busybox-manager.yaml kubectl apply -f ./busybox-viewer.yaml -CLUSTER_MANAGER_TOKEN=`kubectl -n chaos-testing describe secret $(kubectl -n chaos-testing get secret | grep account-cluster-manager | awk '{print $1}') | grep "token:" | awk '{print $2}'` -CLUSTER_VIEWER_TOKEN=`kubectl -n chaos-testing describe secret $(kubectl -n chaos-testing get secret | grep account-cluster-viewer | awk '{print $1}') | grep "token:" | awk '{print $2}'` +CLUSTER_MANAGER_TOKEN=`kubectl -n chaos-mesh describe secret $(kubectl -n chaos-mesh get secret | grep account-cluster-manager | awk '{print $1}') | grep "token:" | awk '{print $2}'` +CLUSTER_VIEWER_TOKEN=`kubectl -n chaos-mesh describe secret $(kubectl -n chaos-mesh get secret | grep account-cluster-viewer | awk '{print $1}') | grep "token:" | awk '{print $2}'` BUSYBOX_MANAGER_TOKEN=`kubectl -n busybox describe secret $(kubectl -n busybox get secret | grep account-busybox-manager | awk '{print $1}') | grep "token:" | awk '{print $2}'` BUSYBOX_VIEWER_TOKEN=`kubectl -n busybox describe secret $(kubectl -n busybox get secret | grep account-busybox-viewer | awk '{print $1}') | grep "token:" | awk '{print $2}'` @@ -57,8 +58,8 @@ BUSYBOX_MANAGE_TOKEN_LIST=($CLUSTER_MANAGER_TOKEN $BUSYBOX_MANAGER_TOKEN) BUSYBOX_MANAGER_FORBIDDEN_TOKEN_LIST=($CLUSTER_VIEWER_TOKEN $BUSYBOX_VIEWER_TOKEN) BUSYBOX_VIEW_TOKEN_LIST=($CLUSTER_MANAGER_TOKEN $CLUSTER_VIEWER_TOKEN $BUSYBOX_MANAGER_TOKEN $BUSYBOX_VIEWER_TOKEN) -EXP_JSON='{"name": "ci-test", "namespace": "busybox", "scope": {"mode":"one", "namespace_selectors": ["busybox"]}, "target": {"kind": "NetworkChaos", "network_chaos": {"action": "delay", "delay": {"latency": "1ms"}}}}' -UPDATE_EXP_JSON='{"apiVersion": "chaos-mesh.org/v1alpha1", "kind": "NetworkChaos", "metadata": {"name": "ci-test", "namespace": "busybox"}, "spec": {"action": "delay", "latency": "2ms", "mode": "one"}}' +EXP_JSON='{"apiVersion": "chaos-mesh.org/v1alpha1", "kind": "NetworkChaos", "metadata": {"name": "ci-test", "namespace": "busybox"}, "spec": {"action": "delay", "delay": {"latency": "1ms"}, "mode":"one"}}' +UPDATE_EXP_JSON='{"apiVersion": "chaos-mesh.org/v1alpha1", "kind": "NetworkChaos", "metadata": {"name": "ci-test", "namespace": "busybox"}, "spec": {"action": "delay", "delay": {"latency": "2ms"}, "mode": "one"}}' function REQUEST() { declare -a TOKEN_LIST=("${!1}") @@ -83,11 +84,11 @@ function REQUEST() { echo "***** create chaos experiments *****" echo "viewer is forbidden to create experiments" -REQUEST BUSYBOX_MANAGER_FORBIDDEN_TOKEN_LIST[@] "POST" "/api/experiments/new" "create_exp.out" "is forbidden" +REQUEST BUSYBOX_MANAGER_FORBIDDEN_TOKEN_LIST[@] "POST" "/api/experiments" "create_exp.out" "is forbidden" echo "only manager can create experiments success" # here just use busybox manager because experiment can be created only one time -REQUEST BUSYBOX_MANAGER_TOKEN_LIST[@] "POST" "/api/experiments/new" "create_exp.out" '"name":"ci-test"' +REQUEST BUSYBOX_MANAGER_TOKEN_LIST[@] "POST" "/api/experiments" "create_exp.out" '"name":"ci-test"' echo "***** list chaos experiments *****" @@ -105,23 +106,23 @@ REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/experiments" "list_exp. REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/experiments?namespace=default" "list_exp.out" "is forbidden" -echo "***** get details of chaos experiments *****" - -echo "all token can view the experiments under namespace busybox" -REQUEST BUSYBOX_VIEW_TOKEN_LIST[@] "GET" "/api/experiments/detail/${EXP_UID}?namespace=busybox" "exp_detail.out" "Running" - - -echo "***** get state of chaos experiments *****" - -echo "all token can get the state of experiments under namespace busybox" -REQUEST BUSYBOX_VIEW_TOKEN_LIST[@] "GET" "/api/experiments/state?namespace=busybox" "exp_state.out" "Running" - -echo "cluster manager and viewer can get the state of experiments in the cluster" -REQUEST CLUSTER_VIEW_TOKEN_LIST[@] "GET" "/api/experiments/state" "exp_state.out" "Running" - -echo "busybox manager and viewer is forbidden to get the state of experiments in the cluster or other namespace" -REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/experiments/state" "exp_state.out" "is forbidden" -REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/experiments/state?namespace=default" "exp_state.out" "is forbidden" +#echo "***** get details of chaos experiments *****" +# +#echo "all token can view the experiments under namespace busybox" +#REQUEST BUSYBOX_VIEW_TOKEN_LIST[@] "GET" "/api/experiments/detail/${EXP_UID}?namespace=busybox" "exp_detail.out" "Running" +# +# +#echo "***** get state of chaos experiments *****" +# +#echo "all token can get the state of experiments under namespace busybox" +#REQUEST BUSYBOX_VIEW_TOKEN_LIST[@] "GET" "/api/experiments/state?namespace=busybox" "exp_state.out" "Running" +# +#echo "cluster manager and viewer can get the state of experiments in the cluster" +#REQUEST CLUSTER_VIEW_TOKEN_LIST[@] "GET" "/api/experiments/state" "exp_state.out" "Running" +# +#echo "busybox manager and viewer is forbidden to get the state of experiments in the cluster or other namespace" +#REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/experiments/state" "exp_state.out" "is forbidden" +#REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/experiments/state?namespace=default" "exp_state.out" "is forbidden" echo "***** pause chaos experiments *****" @@ -141,13 +142,14 @@ echo "only manager can pause experiments" REQUEST BUSYBOX_MANAGE_TOKEN_LIST[@] "PUT" "/api/experiments/start/${EXP_UID}?namespace=busybox" "restart_exp.out" "success" -echo "***** update chaos experiments *****" +# As we are discussing whether we should provide the ability to modify a chaos while running, these tests are removed now +# echo "***** update chaos experiments *****" -echo "viewer is forbidden to update experiments" -REQUEST BUSYBOX_MANAGER_FORBIDDEN_TOKEN_LIST[@] "PUT" "/api/experiments/update" "update_exp.out" "is forbidden" +# echo "viewer is forbidden to update experiments" +# REQUEST BUSYBOX_MANAGER_FORBIDDEN_TOKEN_LIST[@] "PUT" "/api/experiments/update" "update_exp.out" "is forbidden" -echo "only manager can update experiments" -REQUEST BUSYBOX_MANAGE_TOKEN_LIST[@] "PUT" "/api/experiments/update" "update_exp.out" '"name":"ci-test"' +# echo "only manager can update experiments" +# REQUEST BUSYBOX_MANAGE_TOKEN_LIST[@] "PUT" "/api/experiments/update" "update_exp.out" '"name":"ci-test"' echo "***** delete chaos experiments *****" @@ -165,7 +167,7 @@ echo "***** list events *****" echo "all token can list events under namespace busybox" REQUEST BUSYBOX_VIEW_TOKEN_LIST[@] "GET" "/api/events?namespace=busybox" "list_event.out" "ci-test" -EVENT_ID=`cat list_event.out | sed 's/.*\"event_id\":\([0-9]*\),.*/\1/g'` +EVENT_ID=`cat list_event.out | sed 's/.*\"id\":\([0-9]*\),.*/\1/g'` echo "cluster manager and viewer can list events in the cluster" REQUEST CLUSTER_VIEW_TOKEN_LIST[@] "GET" "/api/events" "list_event.out" "ci-test" @@ -175,30 +177,17 @@ REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/events" "list_event.out REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/events?namespace=default" "list_event.out" "can't list" -echo "***** list dry events *****" - -echo "all token can list dry events under namespace busybox" -REQUEST BUSYBOX_VIEW_TOKEN_LIST[@] "GET" "/api/events/dry?namespace=busybox" "list_dry_event.out" "ci-test" - -echo "cluster manager and viewer can list dry events in the cluster" -REQUEST CLUSTER_VIEW_TOKEN_LIST[@] "GET" "/api/events/dry" "list_dry_event.out" "ci-test" - -echo "busybox manager and viewer is forbidden to list dry events in the cluster or other namespace" -REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/events/dry" "list_dry_event.out" "can't list" -REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/events/dry?namespace=default" "list_dry_event.out" "can't list" - - echo "***** get event by id *****" echo "all token can get event under namespace busybox" -REQUEST BUSYBOX_VIEW_TOKEN_LIST[@] "GET" "/api/events/get?id=$EVENT_ID&namespace=busybox" "get_event.out" "experiment_id" +REQUEST BUSYBOX_VIEW_TOKEN_LIST[@] "GET" "/api/events/$EVENT_ID?namespace=busybox" "get_event.out" "ci-test" echo "cluster manager and viewer can get event in the cluster" -REQUEST CLUSTER_VIEW_TOKEN_LIST[@] "GET" "/api/events/get?id=$EVENT_ID" "get_event.out" "experiment_id" +REQUEST CLUSTER_VIEW_TOKEN_LIST[@] "GET" "/api/events/$EVENT_ID" "get_event.out" "ci-test" echo "busybox manager and viewer is forbidden to get event in the cluster or other namespace" -REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/events/get?id=$EVENT_ID" "get_event.out" "can't list" -REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/events/get?id=$EVENT_ID&namespace=default" "get_event.out" "can't list" +REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/events/$EVENT_ID" "get_event.out" "can't list" +REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/events/$EVENT_ID?namespace=default" "get_event.out" "can't list" echo "***** list archive chaos experiments *****" @@ -217,53 +206,55 @@ REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/archives?namespace=defa echo "***** get detail of archive chaos experiment *****" echo "all token can get the details of archive experiments under namespace busybox" -REQUEST BUSYBOX_VIEW_TOKEN_LIST[@] "GET" "/api/archives/detail?uid=${EXP_UID}&namespace=busybox" "detail_archives.out" '"name":"ci-test"' +REQUEST BUSYBOX_VIEW_TOKEN_LIST[@] "GET" "/api/archives/${EXP_UID}?namespace=busybox" "detail_archives.out" '"name":"ci-test"' echo "cluster manager and viewer can get the details of archive experiments in the cluster" -REQUEST CLUSTER_VIEW_TOKEN_LIST[@] "GET" "/api/archives/detail?uid=${EXP_UID}" "detail_archives.out" '"name":"ci-test"' +REQUEST CLUSTER_VIEW_TOKEN_LIST[@] "GET" "/api/archives/${EXP_UID}" "detail_archives.out" '"name":"ci-test"' echo "busybox manager and viewer is forbidden to get the details of archive experiments in the cluster or other namespace" -REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/archives/detail?uid=${EXP_UID}" "detail_archives.out" "can't list" -REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/archives/detail?uid=${EXP_UID}&namespace=default" "detail_archives.out" "can't list" - - -echo "***** get report of archive chaos experiment *****" - -echo "all token can get the report of archive experiments under namespace busybox" -REQUEST BUSYBOX_VIEW_TOKEN_LIST[@] "GET" "/api/archives/report?uid=${EXP_UID}&namespace=busybox" "report_archives.out" '"name":"ci-test"' - -echo "cluster manager and viewer can get the report of archive experiments in the cluster" -REQUEST CLUSTER_VIEW_TOKEN_LIST[@] "GET" "/api/archives/report?uid=${EXP_UID}" "report_archives.out" '"name":"ci-test"' - -echo "busybox manager and viewer is forbidden to get the report of archive experiments in the cluster or other namespace" -REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/archives/report?uid=${EXP_UID}" "report_archives.out" "can't list" -REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/archives/report?uid=${EXP_UID}&namespace=default" "report_archives.out" "can't list" - - -echo "***** delete archive chaos experiment *****" +REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/archives/${EXP_UID}" "detail_archives.out" "can't list" +REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/archives/${EXP_UID}?namespace=default" "detail_archives.out" "can't list" -echo "viewer is forbidden to delete archive experiments" -REQUEST BUSYBOX_MANAGER_FORBIDDEN_TOKEN_LIST[@] "DELETE" "/api/archives/${EXP_UID}?namespace=busybox" "delete_archives.out" "can't" -echo "only manager can delete archive experiments success" -# here use one manager token to delete it -REQUEST BUSYBOX_MANAGER_TOKEN_LIST[@] "DELETE" "/api/archives/${EXP_UID}?namespace=busybox" "delete_archives.out" "success" +#echo "***** get report of archive chaos experiment *****" +# +#echo "all token can get the report of archive experiments under namespace busybox" +#REQUEST BUSYBOX_VIEW_TOKEN_LIST[@] "GET" "/api/archives/report?uid=${EXP_UID}&namespace=busybox" "report_archives.out" '"name":"ci-test"' +# +#echo "cluster manager and viewer can get the report of archive experiments in the cluster" +#REQUEST CLUSTER_VIEW_TOKEN_LIST[@] "GET" "/api/archives/report?uid=${EXP_UID}" "report_archives.out" '"name":"ci-test"' +# +#echo "busybox manager and viewer is forbidden to get the report of archive experiments in the cluster or other namespace" +#REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/archives/report?uid=${EXP_UID}" "report_archives.out" "can't list" +#REQUEST CLUSTER_VIEW_FORBIDDEN_TOKEN_LIST[@] "GET" "/api/archives/report?uid=${EXP_UID}&namespace=default" "report_archives.out" "can't list" +# +# +#echo "***** delete archive chaos experiment *****" +# +#echo "viewer is forbidden to delete archive experiments" +#REQUEST BUSYBOX_MANAGER_FORBIDDEN_TOKEN_LIST[@] "DELETE" "/api/archives/${EXP_UID}?namespace=busybox" "delete_archives.out" "can't" +# +#echo "only manager can delete archive experiments success" +## here use one manager token to delete it +#REQUEST BUSYBOX_MANAGER_TOKEN_LIST[@] "DELETE" "/api/archives/${EXP_UID}?namespace=busybox" "delete_archives.out" "success" echo "***** test webhook authority ******" -EXP_JSON='{"name": "ci-test2", "namespace": "busybox", "scope": {"mode": "one", "namespace_selectors": ["busybox"]}, "target": {"kind": "NetworkChaos", "network_chaos": {"direction": "both", "target_scope": {"namespace_selectors": ["chaos-testing"], "mode": "one"}, "action": "delay", "delay": {"latency": "1ms"}}}}' -UPDATE_EXP_JSON='{"apiVersion": "chaos-mesh.org/v1alpha1", "kind": "NetworkChaos", "metadata": {"name": "ci-test2", "namespace": "busybox"}, "spec": {"direction": "both", "target": {"selector": {"namespaces": ["chaos-testing", "default" ]}, "mode": "one"}, "action": "delay", "latency": "2ms", "mode": "one"}}' +EXP_JSON='{"apiVersion": "chaos-mesh.org/v1alpha1", "kind": "NetworkChaos", "metadata": {"name": "ci-test2", "namespace": "busybox"}, "spec": {"direction": "both", "target": {"selector": {"namespaces": ["chaos-mesh"]}, "mode": "one"}, "action": "delay", "delay": {"latency": "1ms"}, "mode": "one"}}' +UPDATE_EXP_JSON='{"apiVersion": "chaos-mesh.org/v1alpha1", "kind": "NetworkChaos", "metadata": {"name": "ci-test2", "namespace": "busybox"}, "spec": {"direction": "both", "target": {"selector": {"namespaces": ["chaos-mesh", "default" ]}, "mode": "one"}, "action": "delay", "delay": {"latency": "2ms"}, "mode": "one"}}' + +# create experiment require the privileges of namespace busybox and chaos-mesh, so only cluster manager can create exp success +REQUEST CLUSTER_MANAGER_FORBIDDEN_TOKEN_LIST[@] "POST" "/api/experiments" "create_exp.out" 'is forbidden' -# create experiment require the privileges of namespace busybox and chaos-testing, so only cluster manager can create exp success -REQUEST CLUSTER_MANAGER_FORBIDDEN_TOKEN_LIST[@] "POST" "/api/experiments/new" "create_exp.out" 'is forbidden' +REQUEST CLUSTER_MANAGER_TOKEN_LIST[@] "POST" "/api/experiments" "create_exp.out" '"name":"ci-test2"' -REQUEST CLUSTER_MANAGER_TOKEN_LIST[@] "POST" "/api/experiments/new" "create_exp.out" '"name":"ci-test2"' +# update the experiment require the privileges of namespace busybox, chaos-mesh and default, so only cluster manager can update exp success -# update the experiment require the privileges of namespace busybox, chaos-testing and default, so only cluster manager can update exp success -REQUEST CLUSTER_MANAGER_FORBIDDEN_TOKEN_LIST[@] "PUT" "/api/experiments/update" "update_exp.out" "is forbidden" +# As we are discussing whether we should provide the ability to modify a chaos while running, these tests are removed now +# REQUEST CLUSTER_MANAGER_FORBIDDEN_TOKEN_LIST[@] "PUT" "/api/experiments/update" "update_exp.out" "is forbidden" -REQUEST CLUSTER_MANAGER_TOKEN_LIST[@] "PUT" "/api/experiments/update" "update_exp.out" '"name":"ci-test2"' +# REQUEST CLUSTER_MANAGER_TOKEN_LIST[@] "PUT" "/api/experiments/update" "update_exp.out" '"name":"ci-test2"' # delete experiment kubectl delete networkchaos.chaos-mesh.org ci-test2 -n busybox diff --git a/test/integration_test/jvm/exception.yaml b/test/integration_test/jvm/exception.yaml new file mode 100644 index 0000000000..6d25ce6b1f --- /dev/null +++ b/test/integration_test/jvm/exception.yaml @@ -0,0 +1,40 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +apiVersion: chaos-mesh.org/v1alpha1 +kind: Workflow +metadata: + namespace: chaos-mesh + name: workflow-jvm +spec: + entry: entry + templates: + - name: entry + templateType: Serial + deadline: 5m + children: + - exception + - name: exception + templateType: JVMChaos + deadline: 4m + jvmChaos: + selector: + namespaces: + - helloworld + mode: all + action: exception + class: Main + method: sayhello + exception: java.io.IOException("BOOM") diff --git a/test/integration_test/jvm/helloworld_pod.yaml b/test/integration_test/jvm/helloworld_pod.yaml new file mode 100644 index 0000000000..9abec802c5 --- /dev/null +++ b/test/integration_test/jvm/helloworld_pod.yaml @@ -0,0 +1,30 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +apiVersion: v1 +kind: Namespace +metadata: + name: helloworld +--- +apiVersion: v1 +kind: Pod +metadata: + name: helloworld + namespace: helloworld +spec: + containers: + - name: helloworld + image: xiang13225080/helloworld:v1.0 + imagePullPolicy: IfNotPresent diff --git a/test/integration_test/jvm/mysql_query.yaml b/test/integration_test/jvm/mysql_query.yaml new file mode 100644 index 0000000000..a8baa2c74b --- /dev/null +++ b/test/integration_test/jvm/mysql_query.yaml @@ -0,0 +1,68 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +apiVersion: v1 +kind: Service +metadata: + name: mysql-query + namespace: mysql + labels: + app: mysql-query +spec: + type: NodePort + ports: + - port: 8001 + protocol: TCP + nodePort: 30001 + selector: + app: mysql-query +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mysql-query + namespace: mysql +spec: + selector: + matchLabels: + app: mysql-query + replicas: 2 + template: + metadata: + labels: + app: mysql-query + spec: + containers: + - name: mysql-query + image: xiang13225080/mysqldemo:latest + imagePullPolicy: IfNotPresent + env: + - name: MYSQL_DSN + valueFrom: + configMapKeyRef: + name: tidb-config + key: DSN + - name: MYSQL_USER + valueFrom: + configMapKeyRef: + name: tidb-config + key: USER + - name: MYSQL_PASSWORD + valueFrom: + configMapKeyRef: + name: tidb-config + key: PASSWORD + ports: + - containerPort: 8001 diff --git a/test/integration_test/jvm/mysql_query_exception.yaml b/test/integration_test/jvm/mysql_query_exception.yaml new file mode 100644 index 0000000000..81724f6d32 --- /dev/null +++ b/test/integration_test/jvm/mysql_query_exception.yaml @@ -0,0 +1,30 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +apiVersion: chaos-mesh.org/v1alpha1 +kind: JVMChaos +metadata: + name: exception + namespace: mysql +spec: + action: mysql + mysqlConnectorVersion: '8' + database: mysql + table: user + exception: BOOM + mode: all + selector: + labelSelectors: + 'app': 'mysql-query' \ No newline at end of file diff --git a/test/integration_test/jvm/rule-data.yaml b/test/integration_test/jvm/rule-data.yaml new file mode 100644 index 0000000000..ee27b89ad5 --- /dev/null +++ b/test/integration_test/jvm/rule-data.yaml @@ -0,0 +1,27 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +apiVersion: chaos-mesh.org/v1alpha1 +kind: JVMChaos +metadata: + name: modify-return + namespace: helloworld +spec: + action: ruleData + ruleData: "RULE modify return value\nCLASS Main\nMETHOD getnum\nAT ENTRY\nIF true\nDO\n return 9999\nENDRULE" + mode: all + selector: + namespaces: + - helloworld \ No newline at end of file diff --git a/test/integration_test/jvm/run.sh b/test/integration_test/jvm/run.sh new file mode 100755 index 0000000000..9211585560 --- /dev/null +++ b/test/integration_test/jvm/run.sh @@ -0,0 +1,136 @@ +#!/usr/bin/env bash +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +set -eu + +cur=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +cd $cur + +echo "deploy a helloword pod which is implement with java" + +# source code: https://github.com/WangXiangUSTC/byteman-example/tree/main/example.helloworld +# this application will print log like this below: +# 0. Hello World +# 1. Hello World +# ... + +kubectl apply -f ./helloworld_pod.yaml + +echo "wait helloworld pod status to running" +for ((k=0; k<30; k++)); do + kubectl get pods --namespace helloworld > pods.status + cat pods.status + + run_num=`grep Running pods.status | wc -l` + pod_num=$((`cat pods.status | wc -l` - 1)) + if [ $run_num == $pod_num ]; then + break + fi + + sleep 1 +done + +function check_log() { + message=$1 + match="" + if [ "$2" = "false" ]; then + match="-v" + fi + + success=false + for ((k=0; k<10; k++)); do + line=`kubectl logs --tail=1 helloworld -n helloworld | grep $match "$message" | wc -l` + if [ "$line" = "1" ]; then + success=true + break + fi + + sleep 2 + done + + if [ "$success" = false ]; then + exit 1 + fi +} + +echo "create jvm chaos to update return value, and will print '9999. Hello World'" +kubectl apply -f ./rule-data.yaml +check_log "9999. Hello World" true + +echo "delete jvm chaos, and will not print '9999. Hello World'" +kubectl delete -f ./rule-data.yaml +check_log "9999. Hello World" false + +echo "create jvm chaos to throw exception, and will print 'Got an exception!java.io.IOException: BOOM'" +kubectl apply -f ./exception.yaml +check_log "Got an exception!java.io.IOException: BOOM" true + +echo "delete jvm chaos, and will not print 'Got an exception!java.io.IOException: BOOM'" +kubectl delete -f ./exception.yaml +check_log "Got an exception!java.io.IOException: BOOM" false + +echo "deploy TiDB service and mysql query Java application which used to query TiDB/MySQL" +kubectl apply -f tidb.yaml + +nodeIP=`kubectl get nodes -o wide | grep -Eo '([0-9]*\.){3}[0-9]*'` + +cat < tidb-configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: tidb-config + namespace: mysql +data: + DSN: "jdbc:mysql://${nodeIP}:30400/mysql" + USER: "root" + PASSWORD: "" +EOF + +kubectl apply -f tidb-configmap.yaml +kubectl apply -f mysql_query.yaml + +echo "wait tidb and mysql-query pod status to running" +for ((k=0; k<30; k++)); do + kubectl get pods --namespace mysql > pods.status + cat pods.status + + run_num=`grep Running pods.status | wc -l` + pod_num=$((`cat pods.status | wc -l` - 1)) + if [ $run_num == $pod_num ]; then + break + fi + + sleep 1 +done + +kubectl get events -n mysql +kubectl get nodes -o wide + +curl -X GET "http://${nodeIP}:30001/query?sql=SELECT%20*%20FROM%20mysql.user" > user_info.log +check_contains "root" user_info.log + +kubectl apply -f mysql_query_exception.yaml + +sleep 5 +curl -X GET "http://${nodeIP}:30001/query?sql=SELECT%20*%20FROM%20mysql.user" > user_info.log +check_contains "BOOM" user_info.log + +# TODO: more test + +echo "****** finish jvm chaos test ******" +# clean +kubectl delete -f ./helloworld_pod.yaml +rm pods.status diff --git a/test/integration_test/jvm/tidb.yaml b/test/integration_test/jvm/tidb.yaml new file mode 100644 index 0000000000..de83405b2b --- /dev/null +++ b/test/integration_test/jvm/tidb.yaml @@ -0,0 +1,57 @@ +# Copyright 2022 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +apiVersion: v1 +kind: Namespace +metadata: + name: mysql +--- +apiVersion: v1 +kind: Service +metadata: + name: tidb + namespace: mysql +spec: + type: NodePort + ports: + - port: 4000 + targetPort: 4000 + nodePort: 30400 + selector: + app: tidb +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: tidb + namespace: mysql +spec: + selector: + matchLabels: + app: tidb + strategy: + type: Recreate + template: + metadata: + labels: + app: tidb + spec: + containers: + - image: pingcap/tidb:v6.0.0 + name: tidb + env: + # uber-go/automaxprocs does NOT work with cgroup github in action, would let tidb panic + - name: GOMAXPROCS + value: "8" diff --git a/test/integration_test/network/delay_chaos.yaml b/test/integration_test/network/delay_chaos.yaml index 45cb73171b..e221ead4c7 100644 --- a/test/integration_test/network/delay_chaos.yaml +++ b/test/integration_test/network/delay_chaos.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# apiVersion: chaos-mesh.org/v1alpha1 kind: NetworkChaos metadata: @@ -13,8 +27,6 @@ spec: delay: latency: "10ms" duration: "5s" - scheduler: - cron: "@every 10s" direction: to target: selector: diff --git a/test/integration_test/network/run.sh b/test/integration_test/network/run.sh index effb92cb9d..699d88cd4e 100755 --- a/test/integration_test/network/run.sh +++ b/test/integration_test/network/run.sh @@ -1,17 +1,18 @@ #!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. +# Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# cur=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) cd $cur diff --git a/test/integration_test/physical_machine/chaos.yaml b/test/integration_test/physical_machine/chaos.yaml new file mode 100644 index 0000000000..4493eb5138 --- /dev/null +++ b/test/integration_test/physical_machine/chaos.yaml @@ -0,0 +1,26 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: PhysicalMachineChaos +metadata: + name: physical-stress-mem + namespace: chaos-mesh +spec: + action: stress-mem + address: + - CHAOSD_ADDRESS + mode: one + stress-mem: + size: 100MB diff --git a/test/integration_test/physical_machine/chaos_selector.yaml b/test/integration_test/physical_machine/chaos_selector.yaml new file mode 100644 index 0000000000..abc41dacd6 --- /dev/null +++ b/test/integration_test/physical_machine/chaos_selector.yaml @@ -0,0 +1,27 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: PhysicalMachineChaos +metadata: + name: physical-stress-mem + namespace: chaos-mesh +spec: + action: stress-mem + selector: + labelSelectors: + arch: amd64 + mode: one + stress-mem: + size: 100MB diff --git a/test/integration_test/physical_machine/physical_machine.yaml b/test/integration_test/physical_machine/physical_machine.yaml new file mode 100644 index 0000000000..c8cb7b832c --- /dev/null +++ b/test/integration_test/physical_machine/physical_machine.yaml @@ -0,0 +1,23 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: PhysicalMachine +metadata: + name: physicalmachine1 + namespace: chaos-mesh + labels: + arch: amd64 +spec: + address: CHAOSD_ADDRESS diff --git a/test/integration_test/physical_machine/run.sh b/test/integration_test/physical_machine/run.sh new file mode 100755 index 0000000000..b479049d9f --- /dev/null +++ b/test/integration_test/physical_machine/run.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +function check_chaosd_health() { + success=false + for ((k=0; k<30; k++)); do + status=`curl -w '%{http_code}' -s -o /dev/null $localIP:31768/api/system/health` + if [ ${status} = 200 ];then + success=true + break + fi + sleep 1 + done + + if [ "$success" = false ];then + echo "chaosd starts failed!" + exit 1 + fi + echo "chaosd starts succeed!" +} + +cur=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +cd $cur + +echo "download and deploy chaosd" +localIP=`ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | head -1` + +CHAOSD_VERSION=v1.1.0 +curl -fsSL -o chaosd-${CHAOSD_VERSION}-linux-amd64.tar.gz https://mirrors.chaos-mesh.org/chaosd-${CHAOSD_VERSION}-linux-amd64.tar.gz +tar zxvf chaosd-${CHAOSD_VERSION}-linux-amd64.tar.gz +./chaosd-${CHAOSD_VERSION}-linux-amd64/chaosd server --port 31768 > chaosd.log 2>&1 & +check_chaosd_health + +function judge_stress() { + have_stress=$1 + success=false + for ((k=0; k<10; k++)); do + stress_ng_num=`ps aux > test.temp && grep "stress-ng" test.temp | wc -l && rm test.temp` + if [ "$have_stress" = true ]; then + if [ ${stress_ng_num} -lt 1 ]; then + echo "stress-ng is not run when creating stress chaos on physical machine" + else + success=true + break + fi + else + if [ ${stress_ng_num} -gt 0 ]; then + echo "stress-ng is still running when delete stress chaos on physical machine" + else + success=true + break + fi + fi + + sleep 1 + done + + if [ "$success" = false ]; then + echo "[debug] chaos-controller-manager log:" + kubectl logs -n chaos-mesh -l app.kubernetes.io/component=controller-manager --tail=20 + + echo "" + echo "[debug]chaosd log:" + tail chaosd.log + exit 1 + fi +} + +echo "create physical machine chaos with address" +cp chaos.yaml chaos_tmp.yaml +sed -i 's/CHAOSD_ADDRESS/'$localIP'\:31768/g' chaos_tmp.yaml +kubectl apply -f chaos_tmp.yaml +judge_stress true + +kubectl delete -f chaos_tmp.yaml +judge_stress false + +echo "create physical machine" +cp physical_machine.yaml physical_machine_tmp.yaml +sed -i 's/CHAOSD_ADDRESS/'$localIP'\:31768/g' physical_machine_tmp.yaml +kubectl apply -f physical_machine_tmp.yaml + +echo "create physical machine chaos with selector" +kubectl apply -f chaos_selector.yaml +judge_stress true + +kubectl delete -f chaos_selector.yaml +judge_stress false + +echo "create physical machine schedule" +kubectl apply -f schedule.yaml +judge_stress true + +kubectl delete -f schedule.yaml +judge_stress false + +echo "create workflow include physical machine chaos" +kubectl apply -f workflow.yaml +judge_stress true + +kubectl delete -f workflow.yaml +judge_stress false + + +echo "****** finish physical machine chaos test ******" +# clean +rm chaosd-${CHAOSD_VERSION}-linux-amd64.tar.gz +rm -rf chaosd-${CHAOSD_VERSION}-linux-amd64 +rm *_tmp.yaml +rm chaosd.log +killall chaosd + +cd - diff --git a/test/integration_test/physical_machine/schedule.yaml b/test/integration_test/physical_machine/schedule.yaml new file mode 100644 index 0000000000..75c2c5b1e5 --- /dev/null +++ b/test/integration_test/physical_machine/schedule.yaml @@ -0,0 +1,34 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +kind: Schedule +apiVersion: chaos-mesh.org/v1alpha1 +metadata: + name: test + namespace: chaos-mesh +spec: + schedule: '@every 5s' + startingDeadlineSeconds: null + concurrencyPolicy: Forbid + historyLimit: 1 + type: PhysicalMachineChaos + physicalmachineChaos: + action: stress-mem + duration: 4s + selector: + labelSelectors: + arch: amd64 + mode: one + stress-mem: + size: 100MB diff --git a/test/integration_test/physical_machine/workflow.yaml b/test/integration_test/physical_machine/workflow.yaml new file mode 100644 index 0000000000..a1e7660bb5 --- /dev/null +++ b/test/integration_test/physical_machine/workflow.yaml @@ -0,0 +1,38 @@ +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: Workflow +metadata: + name: workflow-test + namespace: chaos-mesh +spec: + entry: entry + templates: + - name: entry + templateType: Serial + deadline: 1m + children: + - test + - name: test + templateType: PhysicalMachineChaos + deadline: 1m + physicalmachineChaos: + action: stress-mem + selector: + labelSelectors: + arch: amd64 + mode: one + stress-mem: + size: 100MB diff --git a/test/integration_test/run.sh b/test/integration_test/run.sh index 570c0dffcd..2da5390042 100755 --- a/test/integration_test/run.sh +++ b/test/integration_test/run.sh @@ -1,17 +1,18 @@ #!/usr/bin/env bash - -# Copyright 2020 Chaos Mesh Authors. +# Copyright 2021 Chaos Mesh Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# set -eu @@ -40,12 +41,18 @@ fi if [ "$test_case" == "*" ]; then for script in $test_dir/$test_case/run.sh; do + # jvmchaos and chaosd are not supported in aarch64 + # TODO: support JVMChaos / chaosd in aarch64, and remove this check + if [[ ($script == *"jvm"* || $script == *"physical_machine"*) && "$(uname -m)" == "aarch64" ]]; then + continue + fi + run $script done else for name in $test_case; do script="$test_dir/$name/run.sh" - echo "run $script" + echo "run $script" run $script done fi \ No newline at end of file diff --git a/test/integration_test/statuscheck/run.sh b/test/integration_test/statuscheck/run.sh new file mode 100644 index 0000000000..e042d0873f --- /dev/null +++ b/test/integration_test/statuscheck/run.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# Copyright Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +cur=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +cd $cur + +echo "****** test status check ******" +kubectl apply -f ./statuscheck.yaml + +echo "verification" +# TODO verification + +echo "****** finish status check test ******" +kubectl delete -f ./statuscheck.yaml +cd - diff --git a/test/integration_test/statuscheck/statuscheck.yaml b/test/integration_test/statuscheck/statuscheck.yaml new file mode 100644 index 0000000000..ec86ee860d --- /dev/null +++ b/test/integration_test/statuscheck/statuscheck.yaml @@ -0,0 +1,25 @@ +# Copyright Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: chaos-mesh.org/v1alpha1 +kind: StatusCheck +metadata: + name: status-check + namespace: chaos-mesh +spec: + type: HTTP + http: + url: http://123.123.123.123 + criteria: + statusCode: "200" diff --git a/test/pkg/timer/timer.go b/test/pkg/timer/timer.go index 299cb68dfc..c9839e6d41 100644 --- a/test/pkg/timer/timer.go +++ b/test/pkg/timer/timer.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package timer diff --git a/test/types.go b/test/types.go deleted file mode 100644 index 1628535273..0000000000 --- a/test/types.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package test - -import ( - "fmt" - "os/exec" - "path/filepath" - "strings" - - apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - "k8s.io/client-go/kubernetes" - "k8s.io/klog" - aggregatorclientset "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset" - "k8s.io/kubernetes/test/e2e/framework" -) - -const ( - imagePullPolicyIfNotPresent = "IfNotPresent" -) - -// OperatorConfig describe the configuration during installing chaos-mesh -type OperatorConfig struct { - Namespace string - ReleaseName string - Manager ManagerConfig - Daemon DaemonConfig - Tag string - DNSImage string - EnableDashboard bool -} - -// ManagerConfig describe the chaos-operator configuration during installing chaos-mesh -type ManagerConfig struct { - Image string - Tag string - ImagePullPolicy string -} - -// DaemonConfig describe the chaos-daemon configuration during installing chaos-mesh -type DaemonConfig struct { - Image string - Tag string - Runtime string - SocketPath string - ImagePullPolicy string -} - -// NewDefaultOperatorConfig create the default configuration for chaos-mesh test -func NewDefaultOperatorConfig() OperatorConfig { - return OperatorConfig{ - Namespace: "chaos-testing", - ReleaseName: "chaos-mesh", - Tag: "e2e", - Manager: ManagerConfig{ - Image: "localhost:5000/pingcap/chaos-mesh", - Tag: "latest", - ImagePullPolicy: imagePullPolicyIfNotPresent, - }, - Daemon: DaemonConfig{ - Image: "localhost:5000/pingcap/chaos-daemon", - Tag: "latest", - ImagePullPolicy: imagePullPolicyIfNotPresent, - Runtime: "containerd", - SocketPath: "/run/containerd/containerd.sock", - }, - DNSImage: "pingcap/coredns:v0.2.0", - } -} - -type operatorAction struct { - framework *framework.Framework - kubeCli kubernetes.Interface - aggrCli aggregatorclientset.Interface - apiExtCli apiextensionsclientset.Interface - cfg *Config -} - -func (oi *OperatorConfig) operatorHelmSetValue() string { - set := map[string]string{ - "controllerManager.image": fmt.Sprintf("%s:%s", oi.Manager.Image, oi.Manager.Tag), - "controllerManager.imagePullPolicy": oi.Manager.ImagePullPolicy, - "chaosDaemon.image": fmt.Sprintf("%s:%s", oi.Daemon.Image, oi.Daemon.Tag), - "chaosDaemon.runtime": oi.Daemon.Runtime, - "chaosDaemon.socketPath": oi.Daemon.SocketPath, - "chaosDaemon.imagePullPolicy": oi.Daemon.ImagePullPolicy, - "dnsServer.create": "true", - "dnsServer.image": oi.DNSImage, - "dashboard.create": fmt.Sprintf("%t", oi.EnableDashboard), - } - arr := make([]string, 0, len(set)) - for k, v := range set { - arr = append(arr, fmt.Sprintf("%s=%s", k, v)) - } - return fmt.Sprintf("\"%s\"", strings.Join(arr, ",")) -} - -func (oa *operatorAction) operatorChartPath(tag string) string { - return oa.chartPath(operatorChartName, tag) -} - -func (oa *operatorAction) chartPath(name string, tag string) string { - return filepath.Join(oa.cfg.ChartDir, tag, name) -} - -func (oa *operatorAction) manifestPath(tag string) string { - return filepath.Join(oa.cfg.ManifestDir, tag) -} - -func (oa *operatorAction) runKubectlOrDie(args ...string) string { - cmd := "kubectl" - klog.Infof("Running '%s %s'", cmd, strings.Join(args, " ")) - out, err := exec.Command(cmd, args...).CombinedOutput() - if err != nil { - klog.Fatalf("Failed to run '%s %s'\nCombined output: %q\nError: %v", cmd, strings.Join(args, " "), string(out), err) - } - klog.Infof("Combined output: %q", string(out)) - return string(out) -} diff --git a/tools.go b/tools.go deleted file mode 100644 index 805112a3df..0000000000 --- a/tools.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2020 Chaos Mesh Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build tools - -package tools - -import ( - _ "github.com/mgechev/revive" - _ "github.com/pingcap/failpoint/failpoint-ctl" - _ "github.com/swaggo/swag/cmd/swag" - _ "golang.org/x/tools/cmd/goimports" - _ "sigs.k8s.io/controller-tools/cmd/controller-gen" -) diff --git a/tools.json b/tools.json deleted file mode 100644 index fdb207f964..0000000000 --- a/tools.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "Tools": [ - { - "Repository": "gopkg.in/alecthomas/gometalinter.v2", - "Commit": "46cc1ea3778b247666c2949669a3333c532fa9c6" - }, - { - "Repository": "github.com/client9/misspell/cmd/misspell", - "Commit": "7888c6b6ce89353cd98e196bce3c3f9e4cdf31f6" - }, - { - "Repository": "github.com/gordonklaus/ineffassign", - "Commit": "7bae11eba15a3285c75e388f77eb6357a2d73ee2" - }, - { - "Repository": "honnef.co/go/tools/cmd/staticcheck", - "Commit": "5a4a2f4a438d01ba03c591f88ef312005a05063b" - }, - { - "Repository": "github.com/kisielk/errcheck", - "Commit": "55d8f507faff4d6eddd0c41a3e713e2567fca4e5" - }, - { - "Repository": "github.com/mgechev/revive", - "Commit": "7773f47324c2bf1c8f7a5500aff2b6c01d3ed73b" - }, - { - "Repository": "sigs.k8s.io/controller-tools/cmd/controller-gen", - "Commit": "2bc3f5eb99cc72cc15775c1f3314cba8c1093627" - } - ], - "RetoolVersion": "1.3.7" -} diff --git a/tools/assets_generate/main.go b/tools/assets_generate/main.go index 285ba0d2d1..b255786e1d 100644 --- a/tools/assets_generate/main.go +++ b/tools/assets_generate/main.go @@ -1,15 +1,17 @@ -// Copyright 2020 Chaos Mesh Authors. +// Copyright 2021 Chaos Mesh Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package main @@ -27,7 +29,7 @@ func main() { buildTag = os.Args[1] } - fs := http.Dir("ui/build") + fs := http.Dir("ui/app/build") err := vfsgen.Generate(fs, vfsgen.Options{ BuildTags: buildTag, PackageName: "uiserver", diff --git a/tools/schedule-migration/main.go b/tools/schedule-migration/main.go new file mode 100644 index 0000000000..664104737d --- /dev/null +++ b/tools/schedule-migration/main.go @@ -0,0 +1,173 @@ +// Copyright 2021 Chaos Mesh Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package main + +import ( + "fmt" + "os" + "strings" + + "gopkg.in/yaml.v2" +) + +type Object struct { + ApiVersion string `yaml:"apiVersion"` + Kind string `yaml:"kind"` + Metadata yaml.MapSlice `yaml:"metadata"` + Spec yaml.MapSlice `yaml:"spec"` +} + +func main() { + if len(os.Args) != 3 { + fmt.Println("migrator ") + os.Exit(1) + } + data, err := os.ReadFile(os.Args[1]) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + var ( + oldObj Object + newObj Object + ) + err = yaml.Unmarshal(data, &oldObj) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + { + var ( + schedule yaml.MapSlice + findSchedule bool + ) + + if isIncompatibleChaos(oldObj) { + fmt.Printf("the define of %s is changed in v2.0, please modify it according to the document, refer to https://chaos-mesh.org/docs/\n", oldObj.Kind) + os.Exit(1) + } + + for _, item := range oldObj.Spec { + if item.Key == "scheduler" { + schedule = item.Value.(yaml.MapSlice) + findSchedule = true + } + } + + if findSchedule { + newObj = toScheduleObject(oldObj, schedule) + } else { + newObj = oldObj + newObj.Spec = transformChaosSpec(oldObj) + } + } + data, err = yaml.Marshal(newObj) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + err = os.WriteFile(os.Args[2], data, 0644) + if err != nil { + fmt.Println(err) + os.Exit(1) + } +} + +func getKeyName(name string) string { + s := strings.ToLower(name) + return strings.ReplaceAll(s, "chaos", "Chaos") +} + +func toNewKind(kind string) string { + if kind == "IoChaos" { + return "IOChaos" + } + return kind +} + +func toScheduleObject(oldObj Object, schedule yaml.MapSlice) Object { + var newObj Object + var cron string + for _, item := range schedule { + if item.Key == "cron" { + cron = item.Value.(string) + } + } + newObj.ApiVersion = oldObj.ApiVersion + newObj.Metadata = oldObj.Metadata + newObj.Kind = "Schedule" + newObj.Spec = append(newObj.Spec, yaml.MapItem{Key: "schedule", Value: cron}) + newObj.Spec = append(newObj.Spec, yaml.MapItem{Key: "type", Value: toNewKind(oldObj.Kind)}) + newObj.Spec = append(newObj.Spec, yaml.MapItem{Key: "historyLimit", Value: 5}) + newObj.Spec = append(newObj.Spec, yaml.MapItem{Key: "concurrencyPolicy", Value: "Forbid"}) + + newSpec := transformChaosSpec(oldObj) + newObj.Spec = append(newObj.Spec, yaml.MapItem{Key: getKeyName(oldObj.Kind), Value: newSpec}) + return newObj +} + +func transformChaosSpec(obj Object) yaml.MapSlice { + var ( + newSpec yaml.MapSlice + containerNames []string + ) + for _, kv := range obj.Spec { + if kv.Key == "scheduler" { + continue + } + + if kv.Key == "containerName" { + containerNames = append(containerNames, kv.Value.(string)) + continue + } + + if obj.Kind == "DNSChaos" { + // 'scope' is obsolete in v2.0, and instead with 'patterns' + // if 'scope' is 'all', means chaos applies to all the host + // so it equal to pattern "*". otherwise, can't transform. + if kv.Key == "scope" && kv.Value == "all" { + patterns := []string{"*"} + kv = yaml.MapItem{Key: "patterns", Value: patterns} + } + } + + newSpec = append(newSpec, kv) + } + + if len(containerNames) != 0 { + newSpec = append(newSpec, yaml.MapItem{Key: "containerNames", Value: containerNames}) + } + + return newSpec +} + +func isIncompatibleChaos(obj Object) bool { + incompatible := false + switch obj.Kind { + case "DNSChaos": + for _, kv := range obj.Spec { + // 'scope' is obsolete in v2.0, and instead with 'patterns' + // if 'scope' is 'all', means chaos applies to all the host + // so it equal to pattern "*". otherwise, can't transform. + if kv.Key == "scope" && kv.Value != "all" { + incompatible = true + } + } + default: + } + + return incompatible +} diff --git a/tools/schedule-migration/migrate.sh b/tools/schedule-migration/migrate.sh new file mode 100755 index 0000000000..abd72af05a --- /dev/null +++ b/tools/schedule-migration/migrate.sh @@ -0,0 +1,133 @@ +#!/usr/bin/env bash +# Copyright 2021 Chaos Mesh Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +set -e + +NAMESPACES=$(kubectl get namespace | sed '1d' | awk '{print $1}') +CRDS="awschaos +dnschaos +gcpchaos +iochaos +jvmchaos +kernelchaos +networkchaos +podchaos +stresschaos +timechaos +" +cnt=0 + +usage() { + cat << EOF +This script is used to migrate to chaos-mesh 2.0. +USAGE: + migrate.sh [FLAGS] +FLAGS: + -h, --help Prints help information + -e, --export Export existing chaos and update them + -i, --import Import updated chaos (do this after chaos-mesh upgrade) + -c, --crd Update CRD (do this after exporting chaos, and before ugrading chaos-mesh) +EOF +} + +update_yaml () { + local yaml=$1 + ./schedule-migration $yaml $yaml +} + +reapply_crd () { + local crd="" + kubectl delete -f https://mirrors.chaos-mesh.org/v1.2.1/crd.yaml + crd="https://mirrors.chaos-mesh.org/latest/crd.yaml" + kubectl create -f ${crd} +} + +handle_namespace () { + local namespace=$1 + for kind in $CRDS + do + echo " searching resources $kind" + resources=$(kubectl get $kind -n $namespace | sed '1d' | awk '{print $1}') + for resource in $resources + do + echo " getting $resource" + kubectl get $kind $resource -n $namespace -o yaml > $cnt.yaml + update_yaml $cnt.yaml + let "cnt+=1" + done + done +} + +export_chaos () { + for ns in $NAMESPACES + do + echo "searching namespace $ns" + handle_namespace $ns + done +} + +import_chaos() { + local yamls=$(find . -regex ".*\.yaml") + for yaml in $yamls + do + kubectl apply -f $yaml + done +} + +UPDATE_CRD=false +EXPORT_CHAOS=false +IMPORT_CHAOS=false + +while [[ $# -gt 0 ]] +do +key="$1" + +case $key in + -e|--export) + EXPORT_CHAOS=true + shift + ;; + -i|--import) + IMPORT_CHAOS=true + shift + ;; + -c|--crd) + UPDATE_CRD=true + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "unknown option: $key" + usage + exit 1 + ;; +esac +done + +if [ ${EXPORT_CHAOS} == "true" ]; then + export_chaos +fi + +if [ ${UPDATE_CRD} == "true" ]; then + reapply_crd +fi + +if [ ${IMPORT_CHAOS} == "true" ]; then + import_chaos +fi diff --git a/tools/schedule-migration/readme.md b/tools/schedule-migration/readme.md new file mode 100644 index 0000000000..23021534eb --- /dev/null +++ b/tools/schedule-migration/readme.md @@ -0,0 +1,19 @@ +## Issues concerning Chaos-mesh 2.0 upgrade +Due to controller refactor and CRD modification, old chaos resource (1.x) won't work with chaos-mesh 2.0, and you have to manually upgrade the CRD since helm won't do it for you. There are several steps for upgrading. + +1. Export old chaos resource (If you don't care for them, you can skip this step.) +2. Delete the old CRDs and apply new ones. +3. Upgrade chaos-mesh to 2.0 +4. Upgrade the old CRDs and reapply them. + +We provide a bash script to do step 1,2 and 4. Check it out. + +Before running the script, you need to compile an `schedule-migrate` binary + +```bash +go build -o schedule-migration main.go +``` + +``` bash +./migrate.sh -h +``` diff --git a/ui/.gitignore b/ui/.gitignore index 818fb8890d..f077945048 100644 --- a/ui/.gitignore +++ b/ui/.gitignore @@ -1,7 +1,7 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies -/node_modules +node_modules /.pnp .pnp.js @@ -9,7 +9,7 @@ /coverage # production -/build +/app/build # misc .DS_Store @@ -21,11 +21,13 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +pnpm-debug.log* package-lock.json # eslint .eslintcache -# ts-interface-builder -*.type-ti.ts +# yarn +.yarn +.yarnrc diff --git a/ui/.husky/pre-commit b/ui/.husky/pre-commit new file mode 100755 index 0000000000..91a7f92db5 --- /dev/null +++ b/ui/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +cd ./ui && npx lint-staged diff --git a/ui/.prettierignore b/ui/.prettierignore index 555fd30ca7..d63b3df835 100644 --- a/ui/.prettierignore +++ b/ui/.prettierignore @@ -1,5 +1 @@ -build/ -tsconfig.json -package.json -package-lock.json -yarn.lock +app/build diff --git a/ui/.prettierrc b/ui/.prettierrc index 31ba22d843..000835bc5b 100644 --- a/ui/.prettierrc +++ b/ui/.prettierrc @@ -1,4 +1,17 @@ { + "plugins": ["@trivago/prettier-plugin-sort-imports"], + "importOrder": [ + "", + "^@ui/(.*)$", + "store", + "^slices/(.*)$", + "^components/(.*)$", + "^lib/(.*)$", + "^images/(.*)$", + "^[./]" + ], + "importOrderSeparation": true, + "importOrderSortSpecifiers": true, "semi": false, "singleQuote": true, "printWidth": 120 diff --git a/ui/README.md b/ui/README.md index 54a3512e52..5ac3a5271b 100644 --- a/ui/README.md +++ b/ui/README.md @@ -3,61 +3,82 @@ Chaos Mesh Logo -# Dashboard +# UI A Web UI for Chaos Mesh. Powered by ⚛️ [Create React App](https://github.com/facebook/create-react-app). - [How to develop](#how-to-develop) - [Main technologies](#main-technologies) - [Bootstrap](#bootstrap) - - [Global env](#global-env) + - [Prepare](#prepare) - [Install deps](#install-deps) - [Start](#start) - - [Structure](#structure) - - [The rules we followed](#the-rules-we-followed) - - [TS or JS](#ts-or-js) - - [Styles](#styles) - - [Be Compact](#be-compact) + - [Packages](#packages) + - [mui-extends](#mui-extends) - [License](#license) ## How to develop -The following content can help you understand how to develop dashboard and its overall structure. +The following content can help you understand the overall structure of UI and how to develop it. ### Main technologies +We use Typescript + React + Redux + Material UI as the main technologies. If you are not familiar with them, please +read their documentation first. + +Also, we use monorepo to manage the whole UI codebase. Here is the general structure: + +```sh +ui +├── app +│ ├── src +│ │ ├── @types +│ │ ├── api +│ │ ├── components +│ │ ├── i18n +│ │ ├── images +│ │ ├── lib +│ │ ├── pages - place all landing pages +│ │ ├── reducers +│ │ ├── slices +├── packages +│ ├── mui-extends +``` + +One is **app**, which describe the whole UI interface, and the other is **packages**, which provide more complete and independent functionalities for app use. + ### Bootstrap -#### Global env +#### Prepare -If you haven't installed the nodejs and golang environment, checkout [https://nodejs.org/en/download/](https://nodejs.org/en/download/) and [https://golang.org/](https://golang.org/). +If you don't have the nodejs and golang environments installed, see [https://nodejs.org/en/download/](https://nodejs.org/en/download/) and [https://golang.org/](https://golang.org/). -And also, we use [Yarn 1](https://classic.yarnpkg.com/en/) as the dependency management. Maybe we will migrate to Yarn 2 in the future, but not now. +And we use [pnpm](https://pnpm.io/) as the dependency management. Please also install it. #### Install deps -If you just cloned a fresh Chaos Mesh repo, into the `ui` folder, run: +Into the `ui` folder, run: ```sh -yarn bootstrap +pnpm i ``` -This command will install all deps the dashboard needed. +This command will install all deps the UI needed. Then, you need to provide an API server as a proxy, it will pass into an env var which named: `REACT_APP_API_URL`. There are three ways to get it: @@ -65,126 +86,60 @@ Then, you need to provide an API server as a proxy, it will pass into an env var If you have Chaos Mesh deployed in a remote cluster, you can use the dashboard service URL as the proxy. - Try to access it with `http://NodePort:2333`. - - **From a local deployed Chaos Mesh Dashboard** When the cluster is local (E.g., [kind](https://kind.sigs.k8s.io/) or [minikube](https://minikube.sigs.k8s.io/)), you can use [Port Forwarding](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/) to access it: ```sh - kubectl port-forward -n chaos-testing svc/chaos-dashboard 2333:2333 + kubectl port-forward -n chaos-mesh svc/chaos-dashboard 2333:2333 ``` - **From local dashboard server** - There have two ways to run chaos-dashboard server in your terminal: - - - `cd .. && go run cmd/chaos-dashboard/main.go` - - `yarn bootstrap && yarn server` + Run chaos-dashboard server in your terminal: - One is real-time, the other needs to be compiled before use. The compiled bundle the extra Swagger API HTML into the binary file. + ```sh + cd .. + go run cmd/chaos-dashboard/main.go + ``` #### Start -We already place a one-step script to start the dashboard: +We already place a one-step script to start the UI: ```sh # cross-env REACT_APP_API_URL=http://localhost:2333 BROWSER=none react-scripts start -yarn start:default +pnpm -F @ui/app start:default ``` -Then open to see the preview effect. +Or if you want to specify the `API_URL`: -> If you want to run the dashboard and the local server concurrently: -> -> ```sh -> yarn start:all -> ``` +```sh +REACT_APP_API_URL=xxx BROWSER=none pnpm -F @ui/app start +``` + +Then open to view it in the browser. + +### Packages + +#### mui-extends -### Structure +This package extends many of mui's components for use in the UI. It will use `tsc` to compile the code, simply run: ```sh -src -├── @types -├── api -├── components -├── components-mui -├── i18n -├── lib -├── pages -├── reducers -├── routes.tsx -├── slices -├── store.ts -└── theme.ts +pnpm -F @ui/mui-extends build ``` -The above tree structure explained as follow: - -- **`@types`** place global types, which use for Typescript. -- **`api`** place all requests. -- **`components`** place all packaged components. -- **`components-mui`** nearly the same as `components`, but inherit from Material UI. -- **`i18n`** place all translations. -- **`lib`** place some independent functions and common utils. -- **`reducers`** (Redux reducers) -- **`routes.tsx`** (Client routes) -- **`slices`** [Redux Tookit slices](https://redux-toolkit.js.org/api/createSlice) -- **`store.ts`** (Redux store) -- **`theme`** place global theme definitions. - -### The rules we followed - -For better collaboration and review, we have developed a few rules to help us develop better. - -- [TS or JS](#ts-or-js) -- [Styles](#styles) -- [Be Compact](#be-compact) - -**_Before you contribute, you must read the following carefully._** - -#### TS or JS - -First, we use [husky](https://github.com/typicode/husky) and [lint-staged](https://github.com/okonet/lint-staged) to make [prettier](https://prettier.io/) format our code automatically before commit. - -~~And also, because some of us use vscode to develop the dashboard, we recommend to use [sort-imports](https://marketplace.visualstudio.com/items?itemName=amatiasq.sort-imports) to format all imports.~~ **(Sort automatically for now)** - -#### Styles - -Currently, we use `@material-ui/styles` to isolate each component styles. - -We hope you can follow this order **(Don't care about their value)** to organize all styles: - -```scss -// Position first -position: relative; -top: 0; -bottom: 0; -left: 0; -right: 0; -// Then display -display: flex; -flex-direction: column; -justify-content: center; -align-items: center; -// Layout -width: 0; -height: 0; -margin: 0; -padding: 0; -// Colors -background: #fff; -color: #000; -// Outside -border: 0; -box-shadow: none; -// Finally, not often used values can be in any order -``` +to build them. + +We provide [storybook](https://storybook.js.org/) for previewing the components, you can run: -#### Be Compact +```sh +pnpm -F @ui/mui-extends build +pnpm -F @ui/mui-extends storybook +``` -- **Don't include unused deps.** -- **Don't let your code be too long-winded, there will be a lot of elegant writing.** +to open it. ## License diff --git a/ui/app/package.json b/ui/app/package.json new file mode 100644 index 0000000000..e6be1a80ee --- /dev/null +++ b/ui/app/package.json @@ -0,0 +1,112 @@ +{ + "name": "@ui/app", + "version": "0.0.0", + "private": true, + "homepage": ".", + "scripts": { + "start": "react-scripts start", + "start:default": "cross-env REACT_APP_API_URL=http://localhost:2333 BROWSER=none react-scripts start", + "build": "react-scripts build", + "analyze": "source-map-explorer 'build/static/js/*.js' --only-mapped", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "dependencies": { + "@emotion/react": "^11.7.0", + "@emotion/styled": "^11.3.0", + "@loadable/component": "^5.14.1", + "@mui/base": "5.0.0-alpha.120", + "@mui/icons-material": "^5.10.16", + "@mui/lab": "5.0.0-alpha.122", + "@mui/material": "^5.10.16", + "@mui/styles": "^5.10.16", + "@mui/x-data-grid": "6.0.0", + "@nivo/core": "^0.80.0", + "@nivo/pie": "^0.80.0", + "@reactour/tour": "^3.3.0", + "@reduxjs/toolkit": "^1.7.1", + "@tanstack/react-query": "^4.28.0", + "@ui/mui-extends": "workspace:*", + "ace-builds": "^1.4.12", + "axios": "^0.24.0", + "clsx": "^1.1.1", + "copy-text-to-clipboard": "^3.0.1", + "cytoscape": "^3.18.1", + "cytoscape-dagre": "^2.3.2", + "d3": "^6.5.0", + "expression-eval": "^5.0.0", + "flat": "^5.0.2", + "formik": "^2.2.6", + "idb": "^7.0.0", + "js-cookie": "^3.0.1", + "js-file-download": "^0.4.12", + "js-yaml": "^4.0.0", + "lodash": "^4.17.21", + "luxon": "^1.28.1", + "re-resizable": "^6.9.9", + "react": "^17.0.1", + "react-ace": "^9.2.1", + "react-dnd": "^15.1.1", + "react-dnd-html5-backend": "^15.1.2", + "react-dom": "^17.0.1", + "react-flow-renderer": "^10.3.0", + "react-helmet": "^6.1.0", + "react-intl": "^5.22.0", + "react-redux": "^7.2.2", + "react-router-dom": "^6.13.0", + "react-scripts": "5.0.1", + "react-window": "^1.8.6", + "redux": "^4.0.5", + "typescript": "~4.5.2", + "uuid": "^8.3.2", + "yup": "^0.29.1" + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "devDependencies": { + "@faker-js/faker": "^7.6.0", + "@tanstack/react-query-devtools": "^4.28.0", + "@testing-library/jest-dom": "^5.15.1", + "@testing-library/react": "^12.1.5", + "@testing-library/user-event": "^13.5.0", + "@types/cytoscape": "^3.14.12", + "@types/d3": "^6.3.0", + "@types/flat": "^5.0.1", + "@types/jest": "^27.0.3", + "@types/js-cookie": "^3.0.1", + "@types/js-yaml": "^4.0.5", + "@types/loadable__component": "^5.13.1", + "@types/lodash": "^4.14.181", + "@types/luxon": "^1.25.1", + "@types/react": "17.0.52", + "@types/react-dom": "17.0.18", + "@types/react-helmet": "^6.1.5", + "@types/react-redux": "^7.1.15", + "@types/react-router-dom": "^5.1.7", + "@types/react-window": "^1.8.2", + "@types/testing-library__jest-dom": "^5.14.5", + "@types/uuid": "^8.3.4", + "@types/yup": "^0.29.11", + "cross-env": "^7.0.3", + "http-proxy-middleware": "^2.0.1", + "msw": "^1.2.1", + "redux-logger": "^3.0.6", + "source-map-explorer": "^2.5.2" + }, + "jest": { + "resetMocks": false + } +} diff --git a/ui/public/favicon.ico b/ui/app/public/favicon.ico similarity index 100% rename from ui/public/favicon.ico rename to ui/app/public/favicon.ico diff --git a/ui/app/public/index.html b/ui/app/public/index.html new file mode 100644 index 0000000000..ffc0032205 --- /dev/null +++ b/ui/app/public/index.html @@ -0,0 +1,27 @@ + + + + + + + + + + Chaos Mesh + + + + + + +
+ + diff --git a/ui/app/src/@types/dagre.d.ts b/ui/app/src/@types/dagre.d.ts new file mode 100644 index 0000000000..e08d70621a --- /dev/null +++ b/ui/app/src/@types/dagre.d.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +declare module 'cytoscape-dagre' { + const ext: cytoscape.Ext + + export default ext +} diff --git a/ui/app/src/@types/global.d.ts b/ui/app/src/@types/global.d.ts new file mode 100644 index 0000000000..f9b7f08cd2 --- /dev/null +++ b/ui/app/src/@types/global.d.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +type uuid = string diff --git a/ui/app/src/@types/mui.d.ts b/ui/app/src/@types/mui.d.ts new file mode 100644 index 0000000000..02f46383d3 --- /dev/null +++ b/ui/app/src/@types/mui.d.ts @@ -0,0 +1,40 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Theme } from '@mui/material/styles' + +// TODO: remove this declaration when @mui/styles isn't used anymore. See: https://mui.com/guides/migration-v4/. +declare module '@mui/styles' { + interface DefaultTheme extends Theme {} +} + +declare module '@mui/material/styles' { + interface Palette { + secondaryContainer: Palette['primary'] + onSecondaryContainer: Palette['primary'] + surfaceVariant: Palette['primary'] + onSurfaceVariant: Palette['primary'] + outline: Palette['primary'] + } + + interface PaletteOptions { + secondaryContainer: PaletteOptions['primary'] + onSecondaryContainer: PaletteOptions['primary'] + surfaceVariant: PaletteOptions['primary'] + onSurfaceVariant: PaletteOptions['primary'] + outline: PaletteOptions['primary'] + } +} diff --git a/ui/app/src/App.tsx b/ui/app/src/App.tsx new file mode 100644 index 0000000000..445ca6f7be --- /dev/null +++ b/ui/app/src/App.tsx @@ -0,0 +1,54 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { QueryClientProvider } from '@tanstack/react-query' +import { ReactQueryDevtools } from '@tanstack/react-query-devtools' +import type { FC } from 'react' +import { DndProvider } from 'react-dnd' +import { HTML5Backend } from 'react-dnd-html5-backend' +import { Provider as StoreProvider } from 'react-redux' +import { RouterProvider } from 'react-router-dom' + +import store from './store' + +import IntlProvider from './IntlProvider' +import ThemeProvider from './ThemeProvider' +import queryClient from './reactQueryClient' +import router from './router' + +interface AppProps { + forTesting?: boolean +} + +const App: FC = ({ forTesting, children }) => { + const rendered = children || + const RealWorldOnlyProviders: FC = ({ children }) => {children} + + return ( + + + + + {!forTesting ? {rendered} : rendered} + + + + + + ) +} + +export default App diff --git a/ui/app/src/IntlProvider.tsx b/ui/app/src/IntlProvider.tsx new file mode 100644 index 0000000000..5506a92b94 --- /dev/null +++ b/ui/app/src/IntlProvider.tsx @@ -0,0 +1,35 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import flat from 'flat' +import messages from 'i18n/messages' +import { useMemo } from 'react' +import { IntlProvider as ReactIntlProvider } from 'react-intl' + +import { useStoreSelector } from 'store' + +const IntlProvider: React.FC = ({ children }) => { + const { lang } = useStoreSelector((state) => state.settings) + const intlMessages = useMemo>(() => flat(messages[lang]), [lang]) + + return ( + + {children} + + ) +} + +export default IntlProvider diff --git a/ui/app/src/ThemeProvider.tsx b/ui/app/src/ThemeProvider.tsx new file mode 100644 index 0000000000..81001bbecd --- /dev/null +++ b/ui/app/src/ThemeProvider.tsx @@ -0,0 +1,34 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { ThemeProvider as MuiThemeProvider, StyledEngineProvider } from '@mui/material/styles' +import { useMemo } from 'react' +import theme, { darkTheme } from 'theme' + +import { useStoreSelector } from 'store' + +const ThemeProvider: React.FC = ({ children }) => { + const { theme: t } = useStoreSelector((state) => state.settings) + const globalTheme = useMemo(() => (t === 'light' ? theme : darkTheme), [t]) + + return ( + + {children} + + ) +} + +export default ThemeProvider diff --git a/ui/app/src/__mocks__/server.js b/ui/app/src/__mocks__/server.js new file mode 100644 index 0000000000..e0fd561d6c --- /dev/null +++ b/ui/app/src/__mocks__/server.js @@ -0,0 +1,4 @@ +import { setupServer } from 'msw/node' +import { getChaosMeshDashboardAPIMSW } from 'openapi/index.msw' + +export const server = setupServer(...getChaosMeshDashboardAPIMSW()) diff --git a/ui/app/src/api/http.ts b/ui/app/src/api/http.ts new file mode 100644 index 0000000000..e38d9e17e5 --- /dev/null +++ b/ui/app/src/api/http.ts @@ -0,0 +1,90 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import axios, { AxiosError, AxiosRequestConfig } from 'axios' + +import store from 'store' + +import { removeToken, setAlert, setAuthOpen } from 'slices/globalStatus' + +import { resetAPIAuthentication } from './interceptors' + +interface ErrorData { + code: number + type: string + message: string + full_text: string +} + +const http = axios.create({ baseURL: 'api' }) + +http.interceptors.response.use(undefined, (error: AxiosError) => { + const data = error.response?.data + + if (data) { + // slice(10): error.api.xxx => xxx + const type = data.type.slice(10) + + switch (type) { + case 'invalid_request': + if (data.message.includes('Unauthorized')) { + store.dispatch( + setAlert({ + type: 'error', + message: 'Please check the validity of the token', + }) + ) + } + break + case 'internal_server_error': + if (data.message.includes('Unauthorized')) { + store.dispatch( + setAlert({ + type: 'error', + message: 'Unauthorized. Please check the validity of the token', + }) + ) + + resetAPIAuthentication() + store.dispatch(removeToken()) + store.dispatch(setAuthOpen(true)) + } + break + // eslint-disable-next-line no-fallthrough + case 'no_cluster_privilege': + case 'no_namespace_privilege': + default: + store.dispatch( + setAlert({ + type: 'error', + message: data.message || 'An unknown error occurred', + }) + ) + + break + } + } + + return Promise.reject(error) +}) + +export const customInstance = (config: AxiosRequestConfig): Promise => { + const promise = http(config).then(({ data }) => data) + + return promise +} + +export default http diff --git a/ui/app/src/api/interceptors.ts b/ui/app/src/api/interceptors.ts new file mode 100644 index 0000000000..960ad24745 --- /dev/null +++ b/ui/app/src/api/interceptors.ts @@ -0,0 +1,76 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import http from './http' + +let tokenInterceptorId: number + +interface GCPToken { + accessToken: string + expiry: string +} + +export const applyAPIAuthentication = (token: string | GCPToken) => { + if (tokenInterceptorId !== undefined) { + http.interceptors.request.eject(tokenInterceptorId) + } + + const headers: { + Authorization?: string + 'X-Authorization-Method'?: string + 'X-Authorization-AccessToken'?: string + 'X-Authorization-Expiry'?: string + } = + typeof token === 'string' + ? { + Authorization: `Bearer ${token}`, + } + : { + 'X-Authorization-Method': 'gcp', + 'X-Authorization-AccessToken': token.accessToken, + 'X-Authorization-Expiry': token.expiry, + } + + tokenInterceptorId = http.interceptors.request.use((config) => { + config.headers = { + ...config.headers, + ...headers, + } + + return config + }) +} + +export const resetAPIAuthentication = () => http.interceptors.request.eject(tokenInterceptorId) + +let nsInterceptorId: number + +export const applyNSParam = (ns: string) => { + if (nsInterceptorId !== undefined) { + http.interceptors.request.eject(nsInterceptorId) + } + + nsInterceptorId = http.interceptors.request.use((config) => { + if (/state|workflows|schedules|experiments|events|archives$/g.test(config.url!)) { + config.params = { + ...config.params, + namespace: ns === 'All' ? null : ns, + } + } + + return config + }) +} diff --git a/ui/app/src/api/queryUtils.ts b/ui/app/src/api/queryUtils.ts new file mode 100644 index 0000000000..1081f51718 --- /dev/null +++ b/ui/app/src/api/queryUtils.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +export enum Stale { + DAY = 86400 * 1000, +} diff --git a/ui/app/src/api/workflows.ts b/ui/app/src/api/workflows.ts new file mode 100644 index 0000000000..eadfcd7a02 --- /dev/null +++ b/ui/app/src/api/workflows.ts @@ -0,0 +1,32 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { RequestForm } from './workflows.type' +import { TemplateCustom } from 'slices/workflows' +import http from './http' + +// TODO: refactor this interface, use the union type from golang struct +export interface APITemplate { + name: string + templateType: string + deadline?: string + children?: APITemplate[] + task?: TemplateCustom +} + +export const renderHTTPTask = (form: RequestForm) => http.post('/workflows/render-task/http', form) +export const parseHTTPTask = (t: APITemplate) => http.post('/workflows/parse-task/http', t) diff --git a/ui/app/src/api/workflows.type.ts b/ui/app/src/api/workflows.type.ts new file mode 100644 index 0000000000..8b00b99e76 --- /dev/null +++ b/ui/app/src/api/workflows.type.ts @@ -0,0 +1,69 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +export interface WorkflowParams { + namespace?: string +} + +export interface Workflow { + is: 'workflow' + uid: uuid + namespace: string + name: string + entry: string + created_at: string + end_time: string + status: 'running' | 'finished' | 'failed' | 'unknown' +} + +interface NodeNameWithTemplate { + name: string + template: string +} +type SerialNode = NodeNameWithTemplate[] +type ParallelNode = NodeNameWithTemplate[] + +interface ConditionalBranch { + name: string + template: string + Expression: string +} + +export interface Node { + name: string + type: 'ChaosNode' | 'SerialNode' | 'ParallelNode' | 'SuspendNode' | 'TaskNode' + state: string + template: string + serial?: SerialNode + parallel?: ParallelNode + conditional_branches?: Array +} + +export interface WorkflowSingle extends Workflow { + topology: { + nodes: Node[] + } + kube_object: any +} + +export interface RequestForm { + name: string + url: string + method: string + body: string + followLocation: boolean + jsonContent: boolean +} diff --git a/ui/app/src/api/zz_generated.frontend.chaos-mesh.ts b/ui/app/src/api/zz_generated.frontend.chaos-mesh.ts new file mode 100644 index 0000000000..5614a5a118 --- /dev/null +++ b/ui/app/src/api/zz_generated.frontend.chaos-mesh.ts @@ -0,0 +1,22 @@ +import { ExperimentKind } from 'components/NewExperiment/types' + +const mapping = new Map([ + ['AWSChaos', 'awsChaos'], + ['AzureChaos', 'azureChaos'], + ['BlockChaos', 'blockChaos'], + ['DNSChaos', 'dnsChaos'], + ['GCPChaos', 'gcpChaos'], + ['HTTPChaos', 'httpChaos'], + ['IOChaos', 'ioChaos'], + ['JVMChaos', 'jvmChaos'], + ['KernelChaos', 'kernelChaos'], + ['NetworkChaos', 'networkChaos'], + ['PhysicalMachineChaos', 'physicalmachineChaos'], + ['PodChaos', 'podChaos'], + ['StressChaos', 'stressChaos'], + ['TimeChaos', 'timeChaos'], +]) + +export function templateTypeToFieldName(templateType: ExperimentKind): string { + return mapping.get(templateType)! +} diff --git a/ui/app/src/components/AutoForm/Info.tsx b/ui/app/src/components/AutoForm/Info.tsx new file mode 100644 index 0000000000..1d5d520df2 --- /dev/null +++ b/ui/app/src/components/AutoForm/Info.tsx @@ -0,0 +1,112 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { MenuItem } from '@mui/material' +import { useFormikContext } from 'formik' +import { getIn } from 'formik' +import { useGetCommonChaosAvailableNamespaces } from 'openapi' + +import { LabelField, SelectField, TextField } from 'components/FormField' +import MoreOptions from 'components/MoreOptions' +import { T } from 'components/T' + +import { Belong } from '.' +import { isInstant } from './validation' +import { Stale } from 'api/queryUtils' + +interface InfoProps { + belong: Belong + kind: string + action?: string +} + +export default function Info({ belong, kind, action }: InfoProps) { + const { errors, touched } = useFormikContext() + + const { data: namespaces } = useGetCommonChaosAvailableNamespaces({ + query: { + enabled: false, + staleTime: Stale.DAY, + }, + }) + + return ( + <> + {(belong === Belong.Experiment || belong === Belong.Schedule) && ( + <> + } + helperText={ + getIn(errors, 'metadata.name') && getIn(touched, 'metadata.name') ? ( + getIn(errors, 'metadata.name') + ) : ( + + ) + } + error={getIn(errors, 'metadata.name') && getIn(touched, 'metadata.name')} + /> + + {namespaces && ( + } + helperText={} + > + {namespaces.map((n) => ( + + {n} + + ))} + + )} + } /> + } /> + + + )} + {belong === Belong.Workflow && ( + <> + } + helperText={ + getIn(errors, 'name') && getIn(touched, 'name') ? getIn(errors, 'name') : + } + error={getIn(errors, 'name') && getIn(touched, 'name')} + /> + {!isInstant(kind, action) && ( + } + helperText={ + getIn(errors, 'deadline') && getIn(touched, 'deadline') ? ( + getIn(errors, 'deadline') + ) : ( + + ) + } + error={getIn(errors, 'deadline') && getIn(touched, 'deadline')} + /> + )} + + )} + + ) +} diff --git a/ui/app/src/components/AutoForm/Schedule.tsx b/ui/app/src/components/AutoForm/Schedule.tsx new file mode 100644 index 0000000000..6cd3f23118 --- /dev/null +++ b/ui/app/src/components/AutoForm/Schedule.tsx @@ -0,0 +1,105 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { InputAdornment, Link, MenuItem } from '@mui/material' +import { useFormikContext } from 'formik' +import { getIn } from 'formik' + +import { SelectField, TextField } from 'components/FormField' +import { T } from 'components/T' + +export default function Schedule() { + const { errors, touched } = useFormikContext() + + return ( + <> + + https://crontab.guru/ + + ), + }} + /> + ) + } + error={getIn(errors, 'spec.schedule') && getIn(touched, 'spec.schedule') ? true : false} + /> + + ) + } + error={getIn(errors, 'historyLimit') && getIn(touched, 'historyLimit')} + /> + + ) + } + error={getIn(errors, 'concurrencyPolicy') && getIn(touched, 'concurrencyPolicy')} + > + + + + + + + + + + + } + helperText={ + getIn(errors, 'startingDeadlineSeconds') && getIn(touched, 'startingDeadlineSeconds') ? ( + getIn(errors, 'startingDeadlineSeconds') + ) : ( + + ) + } + error={getIn(errors, 'startingDeadlineSeconds') && getIn(touched, 'startingDeadlineSeconds')} + /> + + ) +} diff --git a/ui/app/src/components/AutoForm/data.ts b/ui/app/src/components/AutoForm/data.ts new file mode 100644 index 0000000000..1474852d92 --- /dev/null +++ b/ui/app/src/components/AutoForm/data.ts @@ -0,0 +1,56 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import _ from 'lodash' + +export const podPhases = ['Pending', 'Running', 'Succeeded', 'Failed', 'Unknown'] + +export const scopeInitialValues = ({ hasSelector }: { hasSelector: boolean }) => ({ + ...(hasSelector && { + selector: { + namespaces: [], + labelSelectors: [], + annotationSelectors: [], + podPhaseSelectors: [], + pods: [], + physicalMachines: [], + }, + }), + mode: 'all', + value: undefined, +}) + +export interface Schedule { + schedule: string + historyLimit?: number + concurrencyPolicy?: 'Forbid' | 'Allow' + startingDeadlineSeconds?: number +} + +export const scheduleInitialValues: Schedule = { + schedule: '', + historyLimit: 1, + concurrencyPolicy: 'Forbid', + startingDeadlineSeconds: 0, +} + +export const removeScheduleValues = (values: any) => + _.omit(values, ['scheduled', 'schedule', 'historyLimit', 'concurrencyPolicy', 'startingDeadlineSeconds']) + +export const workflowNodeInfoInitialValues = { + name: '', + deadline: '', +} diff --git a/ui/app/src/components/AutoForm/index.tsx b/ui/app/src/components/AutoForm/index.tsx new file mode 100644 index 0000000000..be9d1cd0de --- /dev/null +++ b/ui/app/src/components/AutoForm/index.tsx @@ -0,0 +1,386 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import AddIcon from '@mui/icons-material/Add' +import { Box, Button, Chip, Divider, FormHelperText, MenuItem, Typography } from '@mui/material' +import { eval as expEval, parse } from 'expression-eval' +import { Form, Formik, FormikProps, getIn } from 'formik' +import type { FormikConfig, FormikValues } from 'formik' +import _ from 'lodash' +import { useGetCommonChaosAvailableNamespaces } from 'openapi' +import { Fragment, useEffect, useState } from 'react' + +import Checkbox from '@ui/mui-extends/esm/Checkbox' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreSelector } from 'store' + +import { AutocompleteField, SelectField, Submit, TextField, TextTextField } from 'components/FormField' +import { SpecialTemplateType } from 'components/NewWorkflowNext/utils/convert' +import Scope from 'components/Scope' +import Mode from 'components/Scope/Mode' +import { T } from 'components/T' + +import { concatKindAction } from 'lib/utils' + +import Info from './Info' +import Schedule from './Schedule' +import { removeScheduleValues, scheduleInitialValues, scopeInitialValues, workflowNodeInfoInitialValues } from './data' +import { chooseSchemaByBelong } from './validation' +import { Stale } from 'api/queryUtils' + +export enum Belong { + Experiment = 'Experiment', + Schedule = 'Schedule', + Workflow = 'Workflow', +} + +export interface AutoFormProps { + belong?: Belong + id?: uuid + kind: string // e.g. 'PodChaos' + act?: string // e.g. 'pod-failure' + formikProps: Partial, 'initialValues' | 'onSubmit'>> +} + +export interface AtomFormData { + field: 'text' | 'number' | 'select' | 'label' | 'numbers' | 'text-text' | 'text-label' | 'ref' + label: string + value: string + items?: any[] + children?: AtomFormData[] + multiple?: boolean + helperText?: string + when?: string +} + +const AutoForm: React.FC = ({ belong = Belong.Experiment, id, kind, act: action, formikProps }) => { + const kindAction = concatKindAction(kind, action) + + const { useNewPhysicalMachine } = useStoreSelector((state) => state.settings) + const noScope = + kind === SpecialTemplateType.Suspend || kind === SpecialTemplateType.Serial || kind === SpecialTemplateType.Parallel + + const [initialValues, setInitialValues] = useState({ + id, + kind, + action, + ...(kind === 'NetworkChaos' && { target: scopeInitialValues({ hasSelector: true }) }), + ...(!noScope && + scopeInitialValues({ hasSelector: kind === 'PhysicalMachineChaos' && !useNewPhysicalMachine ? false : true })), + ...(belong === Belong.Workflow && { ...workflowNodeInfoInitialValues, templateType: kind }), + }) + const hasSelector = !!initialValues.selector + const [form, setForm] = useState([]) + const [scheduled, setScheduled] = useState(false) + + const { data: namespaces } = useGetCommonChaosAvailableNamespaces({ + query: { + enabled: false, + staleTime: Stale.DAY, + }, + }) + + useEffect(() => { + function formToRecords(form: AtomFormData[]) { + return form.reduce((acc, d) => { + if (d.field === 'ref') { + acc[d.label] = d.multiple ? [formToRecords(d.children!)] : formToRecords(d.children!) + } else { + acc[d.label] = d.value + } + + return acc + }, {} as FormikValues) + } + + async function loadData() { + if ( + kind === SpecialTemplateType.Suspend || + kind === SpecialTemplateType.Serial || + kind === SpecialTemplateType.Parallel + ) { + setInitialValues((oldValues) => _.merge({}, oldValues, formikProps.initialValues)) + + return + } + + const { data }: { data: AtomFormData[] } = await import(`../../formik/${kind}.ts`) + const form = action + ? data.filter((d) => { + // Since some selectors are not yet supported, ignore target for now. + if (kind === 'NetworkChaos' && d.label === 'target') { + return false + } + + if (kind === 'PhysicalMachineChaos' && useNewPhysicalMachine && d.label === 'address') { + return false + } + + if (d.when) { + const parsed = parse(d.when) + + return expEval(parsed, { action }) + } + + return true + }) + : data + + setInitialValues((oldValues) => _.merge({}, oldValues, formikProps.initialValues || formToRecords(form))) + setForm(form) + } + + if (kind) { + loadData() + } + }, [kind, action, useNewPhysicalMachine, formikProps.initialValues]) + + const renderForm = ( + form: AtomFormData[], + props: FormikProps, + parent?: string, + index?: number + ): any[] => { + const { values, errors, touched, setFieldValue } = props + + // eslint-disable-next-line array-callback-return + return form.map(({ field, label, items, helperText, children, multiple }) => { + const error = getIn(errors, label) + const touch = getIn(touched, label) + const errorAndTouch = error && touch + + let _label = label + if (parent) { + if (index !== undefined) { + _label = `${parent}[${index}].${label}` + } else { + _label = `${parent}.${label}` + } + } + + switch (field) { + case 'text': + return ( + + ) + case 'number': + return ( + + ) + case 'select': + return ( + + {items!.map((option) => ( + + {option.toString()} + + ))} + + ) + case 'label': + return ( + + ) + case 'text-text': + case 'text-label': + return ( + + ) + case 'ref': + const value = getIn(values, _label) + const isMultiple = multiple && _.isArray(value) + + return ( + + + {label} + + {helperText && {helperText}} + + + + {isMultiple + ? value.map((_, index) => ( + + + { + setFieldValue( + _label, + value.filter((_, i) => i !== index) + ) + }} + /> + + {renderForm(children!, props, _label, index)} + + )) + : renderForm(children!, props, _label)} + {isMultiple && ( + + + + )} + + + + ) + } + }) + } + + const switchToSchedule = () => { + if (!scheduled) { + setInitialValues((oldValues) => ({ + ...oldValues, + scheduled: true, + ...scheduleInitialValues, + })) + setTimeout(() => setScheduled(true)) + } else { + setScheduled(false) + setInitialValues((oldValues) => removeScheduleValues(oldValues)) + } + } + + return ( + + {(props) => ( +
+ + + {kindAction} + + {action && ( + + {action} + + )} + {renderForm(form, props)} + {kind === 'NetworkChaos' && ( + <> + + target + + + + } + /> + + + )} + {kind !== SpecialTemplateType.Suspend && + kind !== SpecialTemplateType.Serial && + kind !== SpecialTemplateType.Parallel && ( + <> + + + + + {hasSelector ? ( + + ) : ( + + )} + + + Schedule + + + {scheduled && } + + + )} + Info + + + +
+ )} +
+ ) +} + +export default AutoForm diff --git a/ui/app/src/components/AutoForm/validation.ts b/ui/app/src/components/AutoForm/validation.ts new file mode 100644 index 0000000000..fc82704c5e --- /dev/null +++ b/ui/app/src/components/AutoForm/validation.ts @@ -0,0 +1,54 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { array, object, string } from 'yup' + +import { Belong } from '.' + +const scopeInitialValuesSchema = { + selector: object({ + namespaces: array().min(1), + }), +} + +export function isInstant(kind: string, action?: string) { + if (kind === 'PodChaos' && (action === 'pod-kill' || action === 'container-kill')) { + return true + } + + return false +} + +const workflowNodeInfoSchema = (kind: string, action?: string) => ({ + name: string().trim().required(), + ...(!isInstant(kind, action) && { deadline: string().trim().required() }), +}) + +const workflowSchema = (kind: string, action?: string) => { + return kind !== 'Suspend' + ? object({ + ...(kind !== 'PhysicalMachineChaos' && scopeInitialValuesSchema), + ...workflowNodeInfoSchema(kind, action), + }) + : null +} + +export function chooseSchemaByBelong(belong: Belong, kind: string, action?: string) { + switch (belong) { + case Belong.Workflow: + return workflowSchema(kind, action) + } +} diff --git a/ui/app/src/components/DataTable/index.tsx b/ui/app/src/components/DataTable/index.tsx new file mode 100644 index 0000000000..1372027118 --- /dev/null +++ b/ui/app/src/components/DataTable/index.tsx @@ -0,0 +1,53 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Typography } from '@mui/material' +import type { DataGridProps, GridRenderCellParams } from '@mui/x-data-grid' +import { DataGrid } from '@mui/x-data-grid' + +export default function DataTable({ columns, sx, ...rest }: DataGridProps) { + return ( + ({ + ...d, + flex: d.width ? undefined : 1, + headerAlign: d.headerAlign || 'left', + ...((d.renderCell || d.type === 'actions') && { + renderCell: ({ value }: GridRenderCellParams) => {value}, + }), + }))} + sx={{ + color: 'onSurfaceVariant.main', + '*': { + '&:focus, &:focus-within': { + outline: 'none !important', + }, + }, + '.MuiDataGrid-columnHeaders': { + bgcolor: 'surfaceVariant.main', + }, + '.MuiDataGrid-row:hover': { + cursor: 'pointer', + }, + ...sx, + }} + autoHeight + disableColumnMenu + checkboxSelection={rest.rows.length > 0} + {...rest} + /> + ) +} diff --git a/ui/app/src/components/EventsChart/index.tsx b/ui/app/src/components/EventsChart/index.tsx new file mode 100644 index 0000000000..ef230c1694 --- /dev/null +++ b/ui/app/src/components/EventsChart/index.tsx @@ -0,0 +1,62 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Box, BoxProps } from '@mui/material' +import { CoreEvent } from 'openapi/index.schemas' +import { useEffect, useRef } from 'react' + +import { useStoreSelector } from 'store' + +import NotFound from 'components/NotFound' +import i18n from 'components/T' + +import genEventsChart from 'lib/d3/eventsChart' + +interface EventsChartProps extends BoxProps { + events: CoreEvent[] +} + +const EventsChart: React.FC = ({ events, ...rest }) => { + const { theme } = useStoreSelector((state) => state.settings) + + const chartRef = useRef(null) + + useEffect(() => { + if (events.length) { + const chart = chartRef.current! + + if (typeof chart === 'function') { + chart(events) + + return + } + + chartRef.current = genEventsChart({ + root: chart, + events, + theme, + }) + } + }, [events, theme]) + + return ( + + {events.length === 0 && {i18n('events.notFound')}} + + ) +} + +export default EventsChart diff --git a/ui/app/src/components/EventsTable/index.tsx b/ui/app/src/components/EventsTable/index.tsx new file mode 100644 index 0000000000..a5c8bed465 --- /dev/null +++ b/ui/app/src/components/EventsTable/index.tsx @@ -0,0 +1,242 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import FirstPageIcon from '@mui/icons-material/FirstPage' +import KeyboardArrowLeftIcon from '@mui/icons-material/KeyboardArrowLeft' +import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight' +import LastPageIcon from '@mui/icons-material/LastPage' +import { + Box, + IconButton, + Table, + TableBody, + TableCell, + TableContainer, + TableFooter, + TableHead, + TablePagination, + TableRow, + TableSortLabel, +} from '@mui/material' +import _ from 'lodash' +import { CoreEvent as Event } from 'openapi/index.schemas' +import { useState } from 'react' +import { useIntl } from 'react-intl' + +import Paper from '@ui/mui-extends/esm/Paper' + +import i18n from 'components/T' + +import { comparator, format } from 'lib/luxon' + +function descendingComparator>(a: T, b: T, orderBy: string) { + if (['StartTime', 'EndTime'].includes(orderBy)) { + return comparator(a[orderBy], b[orderBy]) + } + + if (a[orderBy] > b[orderBy]) { + return -1 + } + + if (a[orderBy] < b[orderBy]) { + return 1 + } + + return 0 +} + +type Order = 'asc' | 'desc' + +function getComparator>(order: Order, orderBy: string): (a: T, b: T) => number { + return order === 'desc' + ? (a, b) => descendingComparator(a, b, orderBy) + : (a, b) => -descendingComparator(a, b, orderBy) +} + +function stableSort(data: T[], comparator: (a: T, b: T) => number) { + const indexed: [T, number][] = data.map((el, index) => [el, index]) + + indexed.sort((a, b) => { + const order = comparator(a[0], b[0]) + + if (order !== 0) { + return order + } + + return a[1] - b[1] // compare index + }) + + return indexed.map((el) => el[0]) +} + +type SortedEvent = Omit +type SortedEventWithPods = Event + +const headCells: { id: keyof SortedEvent; label: string }[] = [ + { id: 'object_id', label: 'uuid' }, + { id: 'namespace', label: 'namespace' }, + { id: 'name', label: 'name' }, + { id: 'kind', label: 'kind' }, + { id: 'created_at', label: 'started' }, + { id: 'message', label: 'message' }, +] + +interface EventsTableHeadProps { + order: Order + orderBy: keyof SortedEvent + onSort: (e: React.MouseEvent, k: keyof SortedEvent) => void +} + +const Head: React.FC = ({ order, orderBy, onSort }) => { + const handleSortEvents = (k: keyof SortedEvent) => (e: React.MouseEvent) => onSort(e, k) + + return ( + + + {headCells.map((cell) => ( + + + {cell.label && i18n(`events.event.${cell.label}`)} + + + ))} + + + ) +} + +interface EventsTableRowProps { + event: SortedEventWithPods +} + +const Row: React.FC = ({ event: e }) => ( + + {_.truncate(e.object_id!)} + {e.namespace} + {e.name} + {e.kind} + {format(e.created_at!)} + {e.message} + +) + +interface TablePaginationActionsProps { + count: number + page: number + rowsPerPage: number + onPageChange: (e: React.MouseEvent, newPage: number) => void +} + +const TablePaginationActions: React.FC = ({ count, page, rowsPerPage, onPageChange }) => { + const handleFirstPageButtonClick = (event: React.MouseEvent) => onPageChange(event, 0) + const handleBackButtonClick = (event: React.MouseEvent) => onPageChange(event, page - 1) + const handleNextButtonClick = (event: React.MouseEvent) => onPageChange(event, page + 1) + const handleLastPageButtonClick = (event: React.MouseEvent) => + onPageChange(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1)) + + return ( + + + + + + + + = Math.ceil(count / rowsPerPage) - 1} + aria-label="next page" + > + + + = Math.ceil(count / rowsPerPage) - 1} + aria-label="last page" + > + + + + ) +} + +interface EventsTableProps { + events: Event[] +} + +const EventsTable: React.FC = ({ events: allEvents }) => { + const intl = useIntl() + + const [events] = useState(allEvents) + const [order, setOrder] = useState('desc') + const [orderBy, setOrderBy] = useState('created_at') + const [page, setPage] = useState(0) + const [rowsPerPage, setRowsPerPage] = useState(12) + + const handleSortEvents = (_: React.MouseEvent, k: keyof SortedEvent) => { + const isAsc = orderBy === k && order === 'asc' + + setOrder(isAsc ? 'desc' : 'asc') + setOrderBy(k) + } + + const handlePageChange = (_: React.MouseEvent | null, newPage: number) => setPage(newPage) + + const handleRowsPerPageChange = (event: React.ChangeEvent) => { + setRowsPerPage(parseInt(event.target.value)) + setPage(0) + } + + return ( + }> + + + + + {events && + stableSort(events, getComparator(order, orderBy)) + .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) + .map((e) => )} + + + + + {events && ( + `${from} - ${to} of ${count}`} + labelRowsPerPage={i18n('events.eventsPerPage', intl)} + /> + )} + + +
+
+ ) +} + +export default EventsTable diff --git a/ui/app/src/components/EventsTimeline/index.tsx b/ui/app/src/components/EventsTimeline/index.tsx new file mode 100644 index 0000000000..eced7c18ab --- /dev/null +++ b/ui/app/src/components/EventsTimeline/index.tsx @@ -0,0 +1,74 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import Timeline from '@mui/lab/Timeline' +import TimelineConnector from '@mui/lab/TimelineConnector' +import TimelineContent from '@mui/lab/TimelineContent' +import TimelineDot from '@mui/lab/TimelineDot' +import TimelineItem from '@mui/lab/TimelineItem' +import TimelineOppositeContent from '@mui/lab/TimelineOppositeContent' +import TimelineSeparator from '@mui/lab/TimelineSeparator' +import { Box, Typography } from '@mui/material' +import { CoreEvent } from 'openapi/index.schemas' + +import { useStoreSelector } from 'store' + +import NotFound from 'components/NotFound' +import i18n from 'components/T' + +import { iconByKind } from 'lib/byKind' +import DateTime, { format } from 'lib/luxon' + +interface EventsTimelineProps { + events: CoreEvent[] +} + +const EventsTimeline: React.FC = ({ events }) => { + const { lang } = useStoreSelector((state) => state.settings) + + return events.length > 0 ? ( + + {events.map((e) => ( + + + + + {iconByKind(e.kind as any, 'small')} + + + + + {e.name} + + {e.message} + + + + {DateTime.fromISO(e.created_at!, { + locale: lang, + }).toRelative()} + + + + + ))} + + ) : ( + {i18n('events.notFound')} + ) +} + +export default EventsTimeline diff --git a/ui/app/src/components/FormField/AutocompleteField.tsx b/ui/app/src/components/FormField/AutocompleteField.tsx new file mode 100644 index 0000000000..19f5dd8abb --- /dev/null +++ b/ui/app/src/components/FormField/AutocompleteField.tsx @@ -0,0 +1,62 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { getIn, useFormikContext } from 'formik' + +import MuiExtendsAutocompleteField from '@ui/mui-extends/esm/AutocompleteField' +import type { AutocompleteFieldProps as MuiExtendsAutocompleteFieldProps } from '@ui/mui-extends/esm/AutocompleteField' + +import { T } from 'components/T' + +export interface AutocompleteFieldProps extends MuiExtendsAutocompleteFieldProps { + name: string +} + +const AutocompleteField: React.FC = ({ name, multiple, options, ...props }) => { + const { values, setFieldValue } = useFormikContext() + const value = getIn(values, name) || [] + + const onChange = (_: any, newVal: string | string[] | null, reason: string) => { + if (reason === 'clear') { + setFieldValue(name, multiple ? [] : '') + + return + } + + setFieldValue(name, newVal) + } + + const onDelete = (val: string) => () => + setFieldValue( + name, + value.filter((d: string) => d !== val) + ) + + return ( + } + value={value} + onChange={onChange} + onRenderValueDelete={onDelete} + /> + ) +} + +export default AutocompleteField diff --git a/ui/app/src/components/FormField/LabelField.tsx b/ui/app/src/components/FormField/LabelField.tsx new file mode 100644 index 0000000000..d91e93f065 --- /dev/null +++ b/ui/app/src/components/FormField/LabelField.tsx @@ -0,0 +1,23 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import AutocompleteField, { AutocompleteFieldProps } from './AutocompleteField' + +const LabelField: React.FC> = (props) => { + return +} + +export default LabelField diff --git a/ui/app/src/components/FormField/SelectField.tsx b/ui/app/src/components/FormField/SelectField.tsx new file mode 100644 index 0000000000..2e04e7b78a --- /dev/null +++ b/ui/app/src/components/FormField/SelectField.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Field, getIn, useFormikContext } from 'formik' + +import MuiExtendsSelectField, { SelectFieldProps } from '@ui/mui-extends/esm/SelectField' + +function SelectField(props: SelectFieldProps) { + const { values, setFieldValue } = useFormikContext() + + const onDelete = (val: string) => () => + setFieldValue( + props.name!, + (getIn(values, props.name!) as string[]).filter((d) => d !== val) + ) + + return +} + +export default SelectField diff --git a/ui/app/src/components/FormField/Submit.tsx b/ui/app/src/components/FormField/Submit.tsx new file mode 100644 index 0000000000..43edead621 --- /dev/null +++ b/ui/app/src/components/FormField/Submit.tsx @@ -0,0 +1,37 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Box, Button } from '@mui/material' +import type { ButtonProps } from '@mui/material' + +import { T } from 'components/T' + +export default function Submit({ sx, ...rest }: ButtonProps) { + return ( + + + + ) +} diff --git a/ui/app/src/components/FormField/TextField.test.tsx b/ui/app/src/components/FormField/TextField.test.tsx new file mode 100644 index 0000000000..135f00b9e5 --- /dev/null +++ b/ui/app/src/components/FormField/TextField.test.tsx @@ -0,0 +1,58 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Formik } from 'formik' +import { act, fireEvent, render, screen } from 'test-utils' + +import TextField from './TextField' + +const handleSubmit = jest.fn() + +describe('TextField', () => { + it('should prevent wheel on number field', async () => { + render( + + + + ) + screen.queryByTestId('input')?.focus() + + expect(screen.queryByTestId('input')).toBeTruthy() + + await act(async () => { + fireEvent.wheel(screen.getByTestId('input')) + }) + + expect(screen.getByTestId('input')).not.toHaveFocus() + }) + + it('should prevent wheel on non-number field', async () => { + render( + + + + ) + screen.queryByTestId('input')?.focus() + + expect(screen.queryByTestId('input')).toBeTruthy() + + await act(async () => { + fireEvent.wheel(screen.getByTestId('input')) + }) + + expect(screen.getByTestId('input')).toHaveFocus() + }) +}) diff --git a/ui/app/src/components/FormField/TextField.tsx b/ui/app/src/components/FormField/TextField.tsx new file mode 100644 index 0000000000..091ad42d95 --- /dev/null +++ b/ui/app/src/components/FormField/TextField.tsx @@ -0,0 +1,39 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { FastField, Field, FieldValidator } from 'formik' +import { WheelEvent } from 'react' + +import MuiExtendsTextField, { TextFieldProps } from '@ui/mui-extends/esm/TextField' + +const preventScrollChangingNumberInput = (e: WheelEvent) => { + if (e.target instanceof HTMLInputElement) { + // Prevent the input value change + e.target.blur() + } +} + +const TextField: React.FC = ({ + fast = false, // https://formik.org/docs/api/fastfield + ...rest +}) => { + if (rest.type === 'number') { + rest = { onWheel: preventScrollChangingNumberInput, ...rest } + } + return fast ? : +} + +export default TextField diff --git a/ui/app/src/components/FormField/TextTextField.tsx b/ui/app/src/components/FormField/TextTextField.tsx new file mode 100644 index 0000000000..f4d8ad40da --- /dev/null +++ b/ui/app/src/components/FormField/TextTextField.tsx @@ -0,0 +1,87 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import AddCircleTwoToneIcon from '@mui/icons-material/AddCircleTwoTone' +import RemoveCircleTwoToneIcon from '@mui/icons-material/RemoveCircleTwoTone' +import { Box, Button, FormHelperText, IconButton, Typography } from '@mui/material' +import { getIn, useFormikContext } from 'formik' +import _ from 'lodash' + +import Space from '@ui/mui-extends/esm/Space' + +import LabelField from './LabelField' +import TextField from './TextField' + +interface TextTextFieldProps { + name: string + label: React.ReactNode + helperText?: React.ReactNode + valueLabeled?: boolean +} + +export default function TextTextField({ name, label, helperText, valueLabeled }: TextTextFieldProps) { + const { values, setFieldValue } = useFormikContext() + const fieldValue = getIn(values, name) + const entries = Object.entries(fieldValue) + + const handleAddKV = (n: number) => () => { + setFieldValue(name, { + ...fieldValue, + ['key' + n]: { key: '', value: valueLabeled ? [] : '' }, + }) + } + + const handleRemoveKV = (key: string) => () => { + setFieldValue(name, _.omit(fieldValue, key)) + } + + return ( + <> + + + {label} + + {helperText && {helperText}} + + {entries.length > 0 ? ( + entries.map(([key], i) => ( + + + {valueLabeled ? ( + + ) : ( + + )} + + + + {i === entries.length - 1 && ( + + + + )} + + )) + ) : ( + + + + )} + + ) +} diff --git a/ui/app/src/components/FormField/index.ts b/ui/app/src/components/FormField/index.ts new file mode 100644 index 0000000000..b35483f89a --- /dev/null +++ b/ui/app/src/components/FormField/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +export { default as TextField } from './TextField' +export { default as SelectField } from './SelectField' +export { default as AutocompleteField } from './AutocompleteField' +export { default as LabelField } from './LabelField' +export { default as TextTextField } from './TextTextField' +export { default as Submit } from './Submit' diff --git a/ui/app/src/components/FormikEffect/index.tsx b/ui/app/src/components/FormikEffect/index.tsx new file mode 100644 index 0000000000..b79a595aa4 --- /dev/null +++ b/ui/app/src/components/FormikEffect/index.tsx @@ -0,0 +1,32 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { useFormikContext } from 'formik' +import { useEffect } from 'react' + +interface FormikEffectProps { + didUpdate?: (values: any) => void +} + +export default function FormikEffect({ didUpdate }: FormikEffectProps) { + const { values } = useFormikContext() + + useEffect(() => { + didUpdate && didUpdate(values) + }, [didUpdate, values]) + + return null +} diff --git a/ui/app/src/components/Helmet/index.tsx b/ui/app/src/components/Helmet/index.tsx new file mode 100644 index 0000000000..0832329b16 --- /dev/null +++ b/ui/app/src/components/Helmet/index.tsx @@ -0,0 +1,22 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import Helmet from 'react-helmet' +import type { HelmetProps } from 'react-helmet' + +export default function CustomHelmet(props: HelmetProps) { + return +} diff --git a/ui/app/src/components/MoreOptions/index.tsx b/ui/app/src/components/MoreOptions/index.tsx new file mode 100644 index 0000000000..045e2f7d4b --- /dev/null +++ b/ui/app/src/components/MoreOptions/index.tsx @@ -0,0 +1,58 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown' +import ArrowDropUpIcon from '@mui/icons-material/ArrowDropUp' +import { Box, Button } from '@mui/material' +import { useState } from 'react' + +import Space from '@ui/mui-extends/esm/Space' + +import { T } from 'components/T' + +interface MoreOptionsProps { + isOpen?: boolean + beforeOpen?: () => void + afterClose?: () => void + title?: string | JSX.Element +} + +const MoreOptions: React.FC = ({ isOpen = false, beforeOpen, afterClose, title, children }) => { + const [open, _setOpen] = useState(isOpen) + + const setOpen = () => { + if (open) { + _setOpen(false) + typeof afterClose === 'function' && afterClose() + } else { + typeof beforeOpen === 'function' && beforeOpen() + _setOpen(true) + } + } + + return ( + + + + + {children} + + ) +} + +export default MoreOptions diff --git a/ui/app/src/components/NewExperiment/types.ts b/ui/app/src/components/NewExperiment/types.ts new file mode 100644 index 0000000000..12b492e5b9 --- /dev/null +++ b/ui/app/src/components/NewExperiment/types.ts @@ -0,0 +1,186 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +export interface Metadata { + name: string + namespace: string + labels?: string[] + annotations?: string[] +} + +interface Selector { + namespaces: string[] + labelSelectors?: string[] + annotationSelectors?: string[] + podPhaseSelectors?: string[] + pods?: string[] + physicalMachines?: string[] +} + +export interface Scope { + selector: Selector + mode: string + value?: string +} + +export interface AWS { + action: 'ec2-stop' | 'ec2-restart' | 'detach-volume' + secretName: string + awsRegion: string + ec2Instance: string + volumeID?: string + deviceName?: string +} + +export interface DNS { + action: 'error' | 'random' + patterns: string[] + containerNames?: string[] +} + +export interface GCP { + action: 'node-stop' | 'node-reset' | 'disk-loss' + secretName: string + project: string + zone: string + instance: string + deviceNames?: string[] +} + +export interface IO { + action: 'latency' | 'fault' | 'attrOverride' + delay?: string + errno?: number + attr?: object | string[] + volumePath: string + path: string + percent: number + methods: string[] +} + +export interface Frame { + funcname: string + parameters: string + predicate: string +} + +export interface FailKernelReq { + callchain: Frame[] + failtype: number + headers: string[] + probability: number + times: number +} + +export interface Kernel { + failKernRequest: FailKernelReq +} + +export interface NetworkLoss { + loss: string + correlation: string +} + +export interface NetworkDelay { + latency: string + jitter: string + correlation: string +} + +export interface NetworkDuplicate { + duplicate: string + correlation: string +} + +export interface NetworkCorrupt { + corrupt: string + correlation: string +} + +export interface NetworkBandwidth { + rate: string + limit: number + buffer: number + minburst: number + peakrate: number +} + +export interface Network { + action: 'partition' | 'loss' | 'delay' | 'duplicate' | 'corrupt' | 'bandwidth' + loss?: NetworkLoss + delay?: NetworkDelay + duplicate?: NetworkDuplicate + corrupt?: NetworkCorrupt + bandwidth?: NetworkBandwidth + direction?: 'from' | 'to' | 'both' + target?: Selector +} + +export interface Pod { + action: 'pod-failure' | 'pod-kill' | 'container-kill' + containerNames?: string[] +} + +export interface Stress { + stressors: { + cpu?: { + workers: number + load: number + options: string[] + } + memory?: { + workers: number + size: string + options: string[] + } + } + stressngStressors: string + containerNames: string +} + +export interface Time { + timeOffset: string + clockIds: string[] + containerNames: string[] +} + +export interface ExperimentType { + AWSChaos: AWS + AzureChaos?: unknown + DNSChaos: DNS + GCPChaos: GCP + HTTPChaos?: unknown + IOChaos: IO + JVMChaos?: unknown + KernelChaos: Kernel + NetworkChaos: Network + PodChaos: Pod + StressChaos: Stress + TimeChaos: Time + PhysicalMachineChaos?: unknown + BlockChaos?: unknown +} + +export type ExperimentKind = keyof ExperimentType + +export interface Experiment { + metadata: Metadata + spec: Scope & + ExperimentType[K] & { + duration?: string + } +} diff --git a/ui/app/src/components/NewExperimentNext/ByYAML/index.tsx b/ui/app/src/components/NewExperimentNext/ByYAML/index.tsx new file mode 100644 index 0000000000..2f72729371 --- /dev/null +++ b/ui/app/src/components/NewExperimentNext/ByYAML/index.tsx @@ -0,0 +1,88 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Button, Typography } from '@mui/material' + +import { Ace } from 'ace-builds' +import Paper from '@ui/mui-extends/esm/Paper' +import PublishIcon from '@mui/icons-material/Publish' +import Space from '@ui/mui-extends/esm/Space' +import YAML from 'components/YAML' +import i18n from 'components/T' +import loadable from '@loadable/component' +import { setAlert } from 'slices/globalStatus' +import { useIntl } from 'react-intl' +import { useState } from 'react' +import { useStoreDispatch } from 'store' +import yaml from 'js-yaml' + +const YAMLEditor = loadable(() => import('components/YAMLEditor')) + +interface ByYAMLProps { + callback?: (data: any) => void +} + +const ByYAML: React.FC = ({ callback }) => { + const intl = useIntl() + + const dispatch = useStoreDispatch() + + const [empty, setEmpty] = useState(true) + const [yamlEditor, setYAMLEditor] = useState() + + const onChange = (value: string) => setEmpty(value === '') + + const handleUploadYAMLCallback = (y: any) => yamlEditor?.setValue(y) + + const handleSubmit = () => { + const data = yaml.load(yamlEditor!.getValue()) + + callback && callback(data) + + dispatch( + setAlert({ + type: 'success', + message: i18n('confirm.success.load', intl), + }) + ) + } + + return ( + + + {i18n('newE.byYAMLDesc')} + + + + + + + + + + ) +} + +export default ByYAML diff --git a/ui/app/src/components/NewExperimentNext/LoadFrom/RadioLabel.tsx b/ui/app/src/components/NewExperimentNext/LoadFrom/RadioLabel.tsx new file mode 100644 index 0000000000..314c574f7f --- /dev/null +++ b/ui/app/src/components/NewExperimentNext/LoadFrom/RadioLabel.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Box, Typography } from '@mui/material' +import _ from 'lodash' + +const RadioLabel = (label: string, uuid?: string) => ( + + {label} + {uuid && ( + + + {_.truncate(uuid)} + + + )} + +) + +export default RadioLabel diff --git a/ui/app/src/components/NewExperimentNext/LoadFrom/index.test.tsx b/ui/app/src/components/NewExperimentNext/LoadFrom/index.test.tsx new file mode 100644 index 0000000000..e079b20f59 --- /dev/null +++ b/ui/app/src/components/NewExperimentNext/LoadFrom/index.test.tsx @@ -0,0 +1,47 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { act, render, screen } from 'test-utils' + +import LoadFrom from '.' + +jest.mock('lib/idb', () => { + return { + getDB: jest.fn().mockResolvedValue({ + getAll: jest.fn().mockResolvedValue([]), + }), + } +}) + +describe('', () => { + test('loads and displays experiments and archives', async () => { + await act(async () => { + render() + }) + + expect(screen.getByText('Experiments')).toBeInTheDocument() + expect(screen.queryByText('No experiments found')).not.toBeInTheDocument() + }) + + test('loads and displays schedules', async () => { + await act(async () => { + render() + }) + + expect(screen.getByText('Schedules')).toBeInTheDocument() + expect(screen.queryByText('No schedules found')).not.toBeInTheDocument() + }) +}) diff --git a/ui/app/src/components/NewExperimentNext/LoadFrom/index.tsx b/ui/app/src/components/NewExperimentNext/LoadFrom/index.tsx new file mode 100644 index 0000000000..6cc652ccd4 --- /dev/null +++ b/ui/app/src/components/NewExperimentNext/LoadFrom/index.tsx @@ -0,0 +1,280 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Box, Divider, FormControlLabel, Radio, RadioGroup, Typography } from '@mui/material' +import { + useGetArchives, + useGetArchivesSchedules, + useGetArchivesSchedulesUid, + useGetArchivesUid, + useGetExperiments, + useGetExperimentsUid, + useGetSchedules, + useGetSchedulesUid, +} from 'openapi' +import { TypesArchiveDetail, TypesExperimentDetail, TypesScheduleDetail } from 'openapi/index.schemas' +import { useEffect, useState } from 'react' +import { useIntl } from 'react-intl' + +import Paper from '@ui/mui-extends/esm/Paper' +import SkeletonN from '@ui/mui-extends/esm/SkeletonN' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch } from 'store' + +import { setAlert } from 'slices/globalStatus' + +import i18n from 'components/T' + +import { PreDefinedValue, getDB } from 'lib/idb' + +import RadioLabel from './RadioLabel' + +interface LoadFromProps { + callback?: (data: any) => void + inSchedule?: boolean + inWorkflow?: boolean +} + +const LoadFrom: React.FC = ({ callback, inSchedule, inWorkflow }) => { + const intl = useIntl() + + const dispatch = useStoreDispatch() + + const [scheduleUUID, setScheduleUUID] = useState('') + const [experimentUUID, setExperimentUUID] = useState('') + const [archiveUUID, setArchiveUUID] = useState('') + const [scheduleArchiveUUID, setScheduleArchiveUUID] = useState('') + const [predefined, setPredefined] = useState([]) + const [radio, setRadio] = useState('') + + const { data: experiments, isLoading: loading1 } = useGetExperiments() + const { data: schedules, isLoading: loading2 } = useGetSchedules(undefined, { query: { enabled: inSchedule } }) + const { data: archives, isLoading: loading3 } = (inSchedule ? useGetArchivesSchedules : useGetArchives)() + const loading = loading1 || loading2 || loading3 + function afterLoad(data: TypesScheduleDetail | TypesExperimentDetail | TypesArchiveDetail) { + callback && callback(data.kube_object) + + dispatch( + setAlert({ + type: 'success', + message: i18n('confirm.success.load', intl), + }) + ) + } + useGetSchedulesUid(scheduleUUID, { + query: { + enabled: !!scheduleUUID, + onSuccess(data) { + afterLoad(data) + + setScheduleUUID('') + }, + }, + }) + useGetExperimentsUid(experimentUUID, { + query: { + enabled: !!experimentUUID, + onSuccess(data) { + afterLoad(data) + + setExperimentUUID('') + }, + }, + }) + useGetArchivesSchedulesUid(scheduleArchiveUUID, { + query: { + enabled: !!scheduleArchiveUUID, + onSuccess(data) { + afterLoad(data) + + setScheduleArchiveUUID('') + }, + }, + }) + useGetArchivesUid(archiveUUID, { + query: { + enabled: !!archiveUUID, + onSuccess(data) { + afterLoad(data) + + setArchiveUUID('') + }, + }, + }) + + useEffect(() => { + const fetchPredefined = async () => { + let _predefined = await (await getDB()).getAll('predefined') + + if (!inSchedule) { + _predefined = _predefined.filter((d) => d.kind !== 'Schedule') + } + + setPredefined(_predefined) + } + + fetchPredefined() + }, [inSchedule, inWorkflow]) + + const onRadioChange = (e: any) => { + const [type, uuid] = e.target.value.split('+') + + if (type === 'p') { + const experiment = predefined?.filter((p) => p.name === uuid)[0].yaml + + callback && callback(experiment) + + dispatch( + setAlert({ + type: 'success', + message: i18n('confirm.success.load', intl), + }) + ) + + return + } + + switch (type) { + case 's': + setScheduleUUID(uuid) + + break + case 'e': + setExperimentUUID(uuid) + + break + case 'a': + if (inSchedule) { + setScheduleArchiveUUID(uuid) + } else { + setArchiveUUID(uuid) + } + + break + } + + setRadio(e.target.value) + } + + return ( + + + + {inSchedule && ( + <> + {i18n('schedules.title')} + + {loading ? ( + + ) : schedules && schedules.length > 0 ? ( + + {schedules.map((d) => ( + } + label={RadioLabel(d.name!, d.uid)} + /> + ))} + + ) : ( + + {i18n('schedules.notFound')} + + )} + + + + )} + + {!inSchedule && ( + <> + {i18n('experiments.title')} + + {loading ? ( + + ) : experiments && experiments.length > 0 ? ( + + {experiments.map((d) => ( + } + label={RadioLabel(d.name!, d.uid)} + /> + ))} + + ) : ( + + {i18n('experiments.notFound')} + + )} + + + + )} + + {i18n('archives.title')} + + {loading ? ( + + ) : archives && archives.length > 0 ? ( + + {archives.map((d) => ( + } + label={RadioLabel(d.name!, d.uid)} + /> + ))} + + ) : ( + + {i18n('archives.notFound')} + + )} + + + + {i18n('dashboard.predefined')} + + {loading ? ( + + ) : predefined.length > 0 ? ( + + {predefined.map((d) => ( + } + label={RadioLabel(d.name)} + /> + ))} + + ) : ( + + {i18n('dashboard.noPredefinedFound')} + + )} + + + + ) +} + +export default LoadFrom diff --git a/ui/app/src/components/NewExperimentNext/Step1.tsx b/ui/app/src/components/NewExperimentNext/Step1.tsx new file mode 100644 index 0000000000..0f35465ef6 --- /dev/null +++ b/ui/app/src/components/NewExperimentNext/Step1.tsx @@ -0,0 +1,273 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import CheckIcon from '@mui/icons-material/Check' +import RadioButtonCheckedOutlinedIcon from '@mui/icons-material/RadioButtonCheckedOutlined' +import RadioButtonUncheckedOutlinedIcon from '@mui/icons-material/RadioButtonUncheckedOutlined' +import UndoIcon from '@mui/icons-material/Undo' +import { Box, Card, Divider, Typography } from '@mui/material' +import { makeStyles } from '@mui/styles' +import { Stale } from 'api/queryUtils' +import clsx from 'clsx' +import { useGetCommonConfig } from 'openapi' +import React from 'react' + +import Paper from '@ui/mui-extends/esm/Paper' + +import { useStoreDispatch, useStoreSelector } from 'store' + +import { Env, setEnv, setKindAction, setSpec, setStep1 } from 'slices/experiments' + +import i18n from 'components/T' + +import { iconByKind, transByKind } from 'lib/byKind' + +import _typesData, { Definition, Kind, dataPhysic, schema } from './data/types' +import Kernel from './form/Kernel' +import Stress from './form/Stress' +import TargetGenerated from './form/TargetGenerated' + +const useStyles = makeStyles((theme) => { + const cardActive = { + color: theme.palette.primary.main, + borderColor: theme.palette.primary.main, + } + + return { + card: { + cursor: 'pointer', + marginTop: theme.spacing(3), + marginRight: theme.spacing(3), + '&:hover': cardActive, + }, + cardActive, + submit: { + borderColor: theme.palette.success.main, + }, + submitIcon: { + color: theme.palette.success.main, + }, + asButton: { + cursor: 'pointer', + }, + } +}) + +const submitDirectly = ['pod-failure'] + +interface TypeCardProp { + name: Env + handleSwitchEnv: (env: Env) => () => void + env: Env +} + +const TypeCard: React.FC = ({ name, handleSwitchEnv, env }) => { + const classes = useStyles() + const title = name === 'k8s' ? 'k8s.title' : 'physics.single' + return ( + + + + {iconByKind(name)} + + + {i18n(title)} + + + + ) +} + +const Step1 = () => { + const classes = useStyles() + + const state = useStoreSelector((state) => state) + const { + env, + kindAction: [kind, action], + step1, + } = state.experiments + const dispatch = useStoreDispatch() + + const { data: config } = useGetCommonConfig({ + query: { + enabled: false, + staleTime: Stale.DAY, + }, + }) + + const typesData = env === 'k8s' ? _typesData : dataPhysic + let typesDataEntries = Object.entries(typesData) as [Kind, Definition][] + if (!config?.dns_server_create) { + typesDataEntries = typesDataEntries.filter((d) => d[0] !== 'DNSChaos') + } + + const handleSelectTarget = (key: Kind) => () => { + dispatch(setKindAction([key, ''])) + } + + const handleSelectAction = (newAction: string) => () => { + dispatch(setKindAction([kind, newAction])) + + if (submitDirectly.includes(newAction)) { + handleSubmitStep1({ action: newAction }) + } + } + + const handleSubmitStep1 = (values: Record) => { + const result = action + ? { + ...values, + action, + } + : values + + if (process.env.NODE_ENV === 'development') { + console.debug('Debug handleSubmitStep1:', result) + } + + dispatch(setSpec(result)) + dispatch(setStep1(true)) + } + + const handleUndo = () => dispatch(setStep1(false)) + + const handleSwitchEnv = (env: Env) => () => { + dispatch(setKindAction(['', ''])) + dispatch(setEnv(env)) + } + + return ( + + + + {step1 && ( + + + + )} + {i18n('newE.titleStep1')} + + {step1 && } + + + + + ) +} + +export default Step1 diff --git a/ui/app/src/components/NewExperimentNext/Step2.tsx b/ui/app/src/components/NewExperimentNext/Step2.tsx new file mode 100644 index 0000000000..e29e2c58e9 --- /dev/null +++ b/ui/app/src/components/NewExperimentNext/Step2.tsx @@ -0,0 +1,218 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import CheckIcon from '@mui/icons-material/Check' +import PublishIcon from '@mui/icons-material/Publish' +import UndoIcon from '@mui/icons-material/Undo' +import { Box, Button, Divider, Grid, MenuItem, Typography } from '@mui/material' +import { Form, Formik } from 'formik' +import _ from 'lodash' +import { useGetCommonChaosAvailableNamespaces } from 'openapi' +import { useEffect, useMemo, useState } from 'react' + +import Paper from '@ui/mui-extends/esm/Paper' +import SkeletonN from '@ui/mui-extends/esm/SkeletonN' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch, useStoreSelector } from 'store' + +import { setBasic, setStep2 } from 'slices/experiments' + +import { LabelField, SelectField, TextField } from 'components/FormField' +import MoreOptions from 'components/MoreOptions' +import { Fields as ScheduleSpecificFields, data as scheduleSpecificData } from 'components/Schedule/types' +import Scope from 'components/Scope' +import i18n from 'components/T' + +import basicData, { schema as basicSchema } from './data/basic' +import Scheduler from './form/Scheduler' +import { Stale } from 'api/queryUtils' + +interface Step2Props { + inWorkflow?: boolean + inSchedule?: boolean +} + +const Step2: React.FC = ({ inWorkflow = false, inSchedule = false }) => { + const { step2, env, kindAction, basic } = useStoreSelector((state) => state.experiments) + const [kind] = kindAction + const scopeDisabled = kind === 'AWSChaos' || kind === 'GCPChaos' + const schema = basicSchema({ env, scopeDisabled, scheduled: inSchedule, needDeadline: inWorkflow }) + const dispatch = useStoreDispatch() + const originalInit = useMemo( + () => + inSchedule + ? { + metadata: basicData.metadata, + spec: { + ...basicData.spec, + ...scheduleSpecificData, + }, + } + : basicData, + [inSchedule] + ) + const [init, setInit] = useState(originalInit) + + const { data: namespaces } = useGetCommonChaosAvailableNamespaces({ + query: { + enabled: false, + staleTime: Stale.DAY, + }, + }) + + useEffect(() => { + if (!_.isEmpty(basic)) { + setInit({ + metadata: { + ...originalInit.metadata, + ...basic.metadata, + }, + spec: { + ...originalInit.spec, + ...basic.spec, + selector: { + ...originalInit.spec.selector, + ...basic.spec.selector, + }, + }, + }) + } + }, [originalInit, basic]) + + const handleOnSubmitStep2 = (_values: Record) => { + const values = schema.cast(_values) as Record + + if (process.env.NODE_ENV === 'development') { + console.debug('Debug handleSubmitStep2:', values) + } + + dispatch(setBasic(values)) + dispatch(setStep2(true)) + } + + const handleUndo = () => dispatch(setStep2(false)) + + return ( + + + + {step2 && ( + + + + )} + {i18n(`${inSchedule ? 'newS' : 'newE'}.titleStep2`)} + + {step2 && } + + + + ) +} + +export default Step2 diff --git a/ui/app/src/components/NewExperimentNext/Step3.tsx b/ui/app/src/components/NewExperimentNext/Step3.tsx new file mode 100644 index 0000000000..42ab54f83a --- /dev/null +++ b/ui/app/src/components/NewExperimentNext/Step3.tsx @@ -0,0 +1,111 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import DoneAllIcon from '@mui/icons-material/DoneAll' +import { Box, Typography } from '@mui/material' +import { usePostExperiments } from 'openapi' +import { useIntl } from 'react-intl' +import { useNavigate } from 'react-router-dom' + +import Paper from '@ui/mui-extends/esm/Paper' +import PaperTop from '@ui/mui-extends/esm/PaperTop' + +import { useStoreDispatch, useStoreSelector } from 'store' + +import { resetNewExperiment } from 'slices/experiments' +import { setAlert } from 'slices/globalStatus' + +import { Submit } from 'components/FormField' +import { ExperimentKind } from 'components/NewExperiment/types' +import i18n from 'components/T' + +import { parseSubmit } from 'lib/formikhelpers' + +interface Step3Props { + onSubmit?: (parsedValues: any) => void + inSchedule?: boolean +} + +const Step3: React.FC = ({ onSubmit, inSchedule }) => { + const navigate = useNavigate() + const intl = useIntl() + + const state = useStoreSelector((state) => state) + const { step1, step2, kindAction, env, basic, spec } = state.experiments + const { debugMode, useNewPhysicalMachine } = state.settings + const dispatch = useStoreDispatch() + + const { mutateAsync } = usePostExperiments() + + const submitExperiment = () => { + const parsedValues = parseSubmit( + env, + kindAction[0] as ExperimentKind, + { + ...basic, + spec: { + ...basic.spec, + ...spec, + }, + }, + { inSchedule, useNewPhysicalMachine } + ) + + if (process.env.NODE_ENV === 'development' || debugMode) { + console.debug('Debug parsedValues:', parsedValues) + } + + if (!debugMode) { + if (onSubmit) { + onSubmit(parsedValues) + } else { + mutateAsync({ + data: parsedValues, + }) + .then(() => { + dispatch( + setAlert({ + type: 'success', + message: i18n('confirm.success.create', intl), + }) + ) + + dispatch(resetNewExperiment()) + + navigate('/experiments') + }) + .catch(console.error) + } + } + } + + return ( + <> + {step1 && step2 && ( + + + + + {i18n('newE.complete')} + + + + )} + + ) +} + +export default Step3 diff --git a/ui/app/src/components/NewExperimentNext/data/basic.ts b/ui/app/src/components/NewExperimentNext/data/basic.ts new file mode 100644 index 0000000000..deca32281e --- /dev/null +++ b/ui/app/src/components/NewExperimentNext/data/basic.ts @@ -0,0 +1,81 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import * as Yup from 'yup' + +import { Env } from 'slices/experiments' + +import { schema as scheduleSchema } from 'components/Schedule/types' + +const data = { + metadata: { + name: '', + namespace: '', + labels: [], + annotations: [], + }, + spec: { + selector: { + namespaces: [], + labelSelectors: [], + annotationSelectors: [], + podPhaseSelectors: [], + pods: [], + physicalMachines: [], + }, + mode: 'all', + value: undefined, + address: [], + duration: '', + }, +} + +export const schema = (options: { env: Env; scopeDisabled: boolean; scheduled?: boolean; needDeadline?: boolean }) => { + let result = Yup.object({ + metadata: Yup.object({ + name: Yup.string().trim().required('The name is required'), + }), + }) + + const { env, scopeDisabled, scheduled, needDeadline } = options + let spec = Yup.object() + + if (!scopeDisabled && env === 'k8s') { + spec = spec.shape({ + selector: Yup.object({ + namespaces: Yup.array().min(1, 'The namespace selectors is required'), + }), + }) + } + + if (scheduled) { + spec = spec.shape(scheduleSchema) + } + + if (needDeadline) { + spec = spec.shape({ + duration: Yup.string().trim().required('The deadline is required'), + }) + } + + return result.shape({ + spec, + }) +} + +export type dataType = typeof data + +export default data diff --git a/ui/app/src/components/NewExperimentNext/data/types.ts b/ui/app/src/components/NewExperimentNext/data/types.ts new file mode 100644 index 0000000000..8d14bc1ff6 --- /dev/null +++ b/ui/app/src/components/NewExperimentNext/data/types.ts @@ -0,0 +1,1494 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import * as Yup from 'yup' + +import { ExperimentKind } from 'components/NewExperiment/types' + +export type Kind = Exclude +export type KindPhysic = + | Extract + | 'DiskChaos' + | 'JVMChaos' + | 'ProcessChaos' +type FieldType = 'text' | 'textarea' | 'number' | 'select' | 'label' | 'autocomplete' +interface SpecField { + field: FieldType + items?: any[] + isKV?: boolean + label: string + value: any + helperText?: string + inputProps?: Record + if?: { key: string; equal: string | string[] } +} +export type Spec = Record +interface Category { + name: string + key: string + spec: Spec +} +export interface Definition { + categories?: Category[] + spec?: Spec +} + +const containerNamesHelperText = ({ optional }: { optional: boolean }) => { + const text = + "Type and end with Enter to generate the container names. If it's empty, the first container will be injected." + + return optional ? `Optional. ${text}` : text +} + +const containerNames = { + field: 'label' as FieldType, + label: 'Container names', + value: [], + helperText: containerNamesHelperText({ optional: true }), +} + +const awsCommon: Spec = { + secretName: { + field: 'text', + label: 'Secret name', + value: '', + helperText: 'Optional. The Kubernetes secret which includes AWS credentials', + }, + awsRegion: { + field: 'text', + label: 'Region', + value: '', + helperText: 'The AWS region', + }, + ec2Instance: { + field: 'text', + label: 'EC2 instance', + value: '', + helperText: 'The ID of a EC2 instance', + }, +} + +const blockCommon: Spec = { + containerNames, + volumeName: { + field: 'text', + label: 'Volume name', + value: '', + helperText: 'The name of the volume', + }, +} + +const dnsCommon: Spec = { + patterns: { + field: 'label', + label: 'Patterns', + value: [], + helperText: 'Specify the DNS patterns. For example, type google.com and then press TAB to add it.', + }, + containerNames, +} + +const gcpCommon: Spec = { + secretName: { + field: 'text', + label: 'Secret name', + value: '', + helperText: 'Optional. The Kubernetes secret which includes GCP credentials', + }, + project: { + field: 'text', + label: 'Project', + value: '', + helperText: 'The ID of a GCP project', + }, + zone: { + field: 'text', + label: 'Zone', + value: '', + helperText: 'The zone of a GCP project', + }, + instance: { + field: 'text', + label: 'Instance', + value: '', + helperText: 'The name of a VM instance', + }, +} + +const ioCommon: Spec = { + volumePath: { + field: 'text', + label: 'Volume path', + value: '', + helperText: 'The mount path of injected volume', + }, + path: { + field: 'text', + label: 'Path', + value: '', + helperText: "Optional. The path of files for injecting. If it's empty, the action will inject into all files.", + }, + containerNames, + percent: { + field: 'number', + label: 'Percent', + value: 100, + helperText: 'The percentage of injection errors', + }, + methods: { + field: 'label', + label: 'Methods', + value: [], + helperText: 'Optional. The IO methods for injecting IOChaos actions', + }, +} + +const httpCommonSelect: Spec = { + port: { + field: 'number', + label: 'Port', + value: 80, + helperText: 'The target port of request', + }, + path: { + field: 'text', + label: 'Path', + value: '*', + helperText: 'The target URI path of request, support wildcards(https://www.wikiwand.com/en/Matching_wildcards)', + }, + method: { + field: 'select', + items: ['', 'GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH'], + label: 'Method', + value: '', + helperText: 'Optional. The HTTP method of request', + }, + request_headers: { + field: 'label', + isKV: true, + label: 'Request Headers', + value: [], + helperText: 'Optional. The request headers', + }, +} + +const httpRequestCommon: Spec = { + target: 'Request' as any, + ...httpCommonSelect, +} + +const httpResponseCommon: Spec = { + target: 'Response' as any, + ...httpCommonSelect, + code: { + field: 'number', + label: 'Status Code', + value: '', + helperText: 'Optional. The target status code of response', + }, + response_headers: { + field: 'label', + isKV: true, + label: 'Response Headers', + value: [], + helperText: 'Optional. The response headers', + }, +} + +const httpDelayCommon: Spec = { + delay: { + field: 'text', + label: 'Delay', + value: '', + helperText: 'The delay of request/response', + }, +} + +const httpReplaceCommon: Spec = { + 'replace.headers': { + field: 'label', + isKV: true, + label: 'Replace Headers', + value: [], + helperText: 'Optional. The headers to be replaced', + }, + 'replace.body': { + field: 'textarea', + label: 'Replace Body', + value: '', + helperText: 'Optional. The body(in base64 encoding) to be replaced', + }, +} + +const httpPatchCommon: Spec = { + 'patch.headers': { + field: 'label', + isKV: true, + label: 'Patch Headers', + value: [], + helperText: 'Optional. The headers to be patched', + }, + 'patch.body.type': { + field: 'select', + items: ['', 'JSON'], + label: 'Patch Body Type', + value: '', + helperText: 'Optional. The patch type of body', + }, + 'patch.body.value': { + field: 'textarea', + label: 'Patch Body Value', + value: '', + helperText: 'The value to be patched into body', + }, +} + +const jvmClassAndMethod: Spec = { + class: { + field: 'text', + label: 'Class', + value: '', + helperText: 'Class that is injected with faults', + }, + method: { + field: 'text', + label: 'Method', + value: '', + helperText: 'Method that is injected with faults', + }, +} + +const jvmPort: Spec = { + port: { + field: 'number', + label: 'Port', + value: 9277, + helperText: 'The service port of the loaded agent, through which the rules are configured', + }, +} + +const networkCommon: Spec = { + direction: { + field: 'select', + items: ['from', 'to', 'both'], + label: 'Direction', + value: 'to', + helperText: 'Specify the network direction', + }, + externalTargets: { + field: 'label', + label: 'External targets', + value: [], + helperText: 'Type and end with Enter to generate the network targets outside k8s', + }, + target: undefined as any, +} + +const data: Record = { + // AWS + AWSChaos: { + categories: [ + { + name: 'Stop EC2', + key: 'ec2-stop', + spec: { + action: 'ec2-stop' as any, + ...awsCommon, + }, + }, + { + name: 'Restart EC2', + key: 'ec2-restart', + spec: { + action: 'ec2-restart' as any, + ...awsCommon, + }, + }, + { + name: 'Detach Volume', + key: 'detach-volume', + spec: { + action: 'detach-volume' as any, + ...awsCommon, + deviceName: { + field: 'text', + label: 'Device name', + value: '', + helperText: 'The device name for the volume', + }, + volumeID: { + field: 'text', + label: 'EBS volume', + value: '', + helperText: 'The ID of a EBS volume', + }, + }, + }, + ], + }, + BlockChaos: { + categories: [ + { + name: 'Delay', + key: 'delay', + spec: { + action: 'delay' as any, + latency: { + field: 'text', + label: 'Latency', + value: '', + helperText: 'The latency of delay', + }, + jitter: { + field: 'text', + label: 'Jitter', + value: '', + helperText: 'The jitter of delay', + }, + correlation: { + field: 'text', + label: 'Correlation', + value: '', + helperText: 'The correlation of delay', + }, + ...blockCommon, + }, + }, + ], + }, + // DNS Fault + DNSChaos: { + categories: [ + { + name: 'Error', + key: 'error', + spec: { + action: 'error' as any, + ...dnsCommon, + }, + }, + { + name: 'Random', + key: 'random', + spec: { + action: 'random' as any, + ...dnsCommon, + }, + }, + ], + }, + // GCP + GCPChaos: { + categories: [ + { + name: 'Stop node', + key: 'node-stop', + spec: { + action: 'node-stop' as any, + ...gcpCommon, + }, + }, + { + name: 'Reset node', + key: 'node-reset', + spec: { + action: 'node-reset' as any, + ...gcpCommon, + }, + }, + { + name: 'Loss disk', + key: 'disk-loss', + spec: { + action: 'disk-loss' as any, + ...gcpCommon, + deviceNames: { + field: 'label', + label: 'Device names', + value: [], + helperText: 'Type and end with Enter to generate the device names', + }, + }, + }, + ], + }, + // IO Injection + IOChaos: { + categories: [ + { + name: 'Latency', + key: 'latency', + spec: { + action: 'latency' as any, + delay: { + field: 'text', + label: 'Delay', + value: '', + helperText: + "The value of delay of I/O operations. If it's empty, the operator will generate a value for it randomly.", + inputProps: { min: 0 }, + }, + ...ioCommon, + }, + }, + { + name: 'Fault', + key: 'fault', + spec: { + action: 'fault' as any, + errno: { + field: 'number', + label: 'Errno', + value: 0, + helperText: 'The error code returned by I/O operators. By default, it returns a random error code', + }, + ...ioCommon, + }, + }, + { + name: 'AttrOverride', + key: 'attrOverride', + spec: { + action: 'attrOverride' as any, + attr: { + field: 'label', + isKV: true, + label: 'Attr', + value: [], + }, + ...ioCommon, + }, + }, + ], + }, + // HTTP Injection + HTTPChaos: { + categories: [ + { + name: 'Request Abort', + key: 'request-abort', + spec: { + abort: true as any, + ...httpRequestCommon, + }, + }, + { + name: 'Request Delay', + key: 'request-delay', + spec: { + ...httpRequestCommon, + ...httpDelayCommon, + }, + }, + { + name: 'Request Replace', + key: 'request-replace', + spec: { + ...httpRequestCommon, + ...httpReplaceCommon, + 'replace.path': { + field: 'text', + label: 'Replace Path', + value: '', + helperText: 'Optional. The path to be replaced', + }, + 'replace.method': { + field: 'select', + items: ['', 'GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH'], + label: 'Replace Method', + value: '', + helperText: 'Optional. The HTTP method to be replaced', + }, + 'replace.queries': { + field: 'label', + isKV: true, + label: 'Replace Queries', + value: [], + helperText: 'Optional. The queries to be replaced', + }, + }, + }, + { + name: 'Request Patch', + key: 'request-patch', + spec: { + ...httpRequestCommon, + ...httpPatchCommon, + 'patch.queries': { + field: 'label', + isKV: true, + label: 'Patch Queries', + value: [], + helperText: 'Optional. The queries to be patched', + }, + }, + }, + { + name: 'Response Abort', + key: 'response-abort', + spec: { + abort: true as any, + ...httpResponseCommon, + }, + }, + { + name: 'Response Delay', + key: 'response-delay', + spec: { + ...httpResponseCommon, + ...httpDelayCommon, + }, + }, + { + name: 'Response Replace', + key: 'response-replace', + spec: { + ...httpResponseCommon, + ...httpReplaceCommon, + 'replace.code': { + field: 'number', + label: 'Replace Status Code', + value: '', + helperText: 'Optional. The status code to be replaced', + }, + }, + }, + { + name: 'Response Patch', + key: 'response-patch', + spec: { + ...httpResponseCommon, + ...httpPatchCommon, + }, + }, + ], + }, + // Kernel Fault + KernelChaos: { + spec: { + failKernRequest: { + callchain: [], + failtype: 0, + headers: [], + probability: 0, + times: 0, + }, + } as any, + }, + // Network Attack + NetworkChaos: { + categories: [ + { + name: 'Partition', + key: 'partition', + spec: { + action: 'partition' as any, + ...networkCommon, + }, + }, + { + name: 'Loss', + key: 'loss', + spec: { + action: 'loss' as any, + loss: { + field: 'text', + label: 'Loss', + value: '', + helperText: 'The percentage of packet loss', + }, + correlation: { + field: 'text', + label: 'Correlation', + value: '', + helperText: 'The correlation of loss', + }, + ...networkCommon, + }, + }, + { + name: 'Delay', + key: 'delay', + spec: { + action: 'delay' as any, + latency: { + field: 'text', + label: 'Latency', + value: '', + helperText: 'The latency of delay', + }, + jitter: { + field: 'text', + label: 'Jitter', + value: '', + helperText: 'The jitter of delay', + }, + correlation: { + field: 'text', + label: 'Correlation', + value: '', + helperText: 'The correlation of delay', + }, + ...networkCommon, + }, + }, + { + name: 'Duplicate', + key: 'duplicate', + spec: { + action: 'duplicate' as any, + duplicate: { + field: 'text', + label: 'Duplicate', + value: '', + helperText: 'The percentage of packet duplication', + }, + correlation: { + field: 'text', + label: 'Correlation', + value: '', + helperText: 'The correlation of duplicate', + }, + ...networkCommon, + }, + }, + { + name: 'Corrupt', + key: 'corrupt', + spec: { + action: 'corrupt' as any, + corrupt: { + field: 'text', + label: 'Corrupt', + value: '', + helperText: 'The percentage of packet corruption', + }, + correlation: { + field: 'text', + label: 'Correlation', + value: '', + helperText: 'The correlation of corrupt', + }, + ...networkCommon, + }, + }, + { + name: 'Bandwidth', + key: 'bandwidth', + spec: { + action: 'bandwidth' as any, + rate: { + field: 'text', + label: 'Rate', + value: '', + helperText: 'The rate allows bps, kbps, mbps, gbps, tbps unit. For example, bps means bytes per second', + }, + limit: { + field: 'number', + label: 'Limit', + value: 0, + helperText: 'The number of bytes that can be queued waiting for tokens to become available', + }, + buffer: { + field: 'number', + label: 'Buffer', + value: 0, + helperText: 'The maximum amount of bytes that tokens can be available instantaneously', + }, + minburst: { + field: 'number', + label: 'Min burst', + value: 0, + helperText: 'The size of the peakrate bucket', + }, + peakrate: { + field: 'number', + label: 'Peak rate', + value: 0, + helperText: 'The maximum depletion rate of the bucket', + }, + ...networkCommon, + }, + }, + ], + }, + // Pod Fault + PodChaos: { + categories: [ + { + name: 'Pod Failure', + key: 'pod-failure', + spec: { + action: 'pod-failure' as any, + }, + }, + { + name: 'Pod Kill', + key: 'pod-kill', + spec: { + action: 'pod-kill' as any, + gracePeriod: { + field: 'number', + label: 'Grace period', + value: 0, + helperText: 'Optional. Grace period represents the duration in seconds before the pod should be deleted', + }, + }, + }, + { + name: 'Container Kill', + key: 'container-kill', + spec: { + action: 'container-kill' as any, + containerNames: { + ...containerNames, + helperText: containerNamesHelperText({ optional: false }), + }, + }, + }, + ], + }, + // Stress Test + StressChaos: { + spec: { + stressors: { + cpu: { + workers: 0, + load: 0, + options: [], + }, + memory: { + workers: 0, + size: '', + options: [], + }, + }, + stressngStressors: '', + containerNames: [], + } as any, + }, + // Clock Skew + TimeChaos: { + spec: { + timeOffset: { + field: 'text', + label: 'Offset', + value: '', + helperText: 'Fill the time offset', + }, + clockIds: { + field: 'label', + label: 'Clock ids', + value: [], + helperText: + "Optional. Type and end with Enter to generate the clock ids. If it's empty, it will be set to ['CLOCK_REALTIME']", + }, + containerNames, + }, + }, + JVMChaos: { + categories: [ + { + name: 'Exception', + key: 'exception', + spec: { + action: 'exception' as any, + exception: { + field: 'text', + label: 'Exception', + value: '', + helperText: 'Specify the exception to be thrown', + }, + ...jvmClassAndMethod, + ...jvmPort, + }, + }, + { + name: 'GC', + key: 'gc', + spec: { + action: 'gc' as any, + ...jvmPort, + }, + }, + { + name: 'Latency', + key: 'latency', + spec: { + action: 'latency' as any, + latency: { + field: 'number', + label: 'Latency', + value: '', + helperText: 'Specify the time of latency, unit is millisecond', + }, + ...jvmClassAndMethod, + ...jvmPort, + }, + }, + { + name: 'Return', + key: 'return', + spec: { + action: 'return' as any, + value: { + field: 'text', + label: 'Value', + value: '', + helperText: 'Specify the return value', + }, + ...jvmClassAndMethod, + ...jvmPort, + }, + }, + { + name: 'Stress', + key: 'stress', + spec: { + action: 'stress' as any, + cpuCount: { + field: 'number', + label: 'CPU Count', + value: '', + helperText: 'Specify the CPU count', + }, + memType: { + field: 'select', + items: ['stack', 'heap'], + label: 'Mem Type', + value: '', + helperText: 'Specify the mem type', + }, + ...jvmPort, + }, + }, + { + name: 'Rule', + key: 'ruleData', + spec: { + ruleData: { + field: 'textarea', + label: 'Rule', + value: '', + helperText: 'byteman rule configuration', + }, + ...jvmPort, + }, + }, + ], + }, +} + +const networkPhysicCommon: Spec = { + correlation: { + field: 'text', + label: 'Correlation', + value: '', + helperText: 'The correlation of corrupt', + }, + device: { + field: 'text', + label: 'Device', + value: '', + helperText: 'Affected device, e.g., eth0', + }, + hostname: { + field: 'text', + label: 'Hostname', + value: '', + helperText: 'Specify the target hostname', + }, + 'ip-address': { + field: 'text', + label: 'IP Address', + value: '', + helperText: 'Specify the target IP address', + }, + 'ip-protocol': { + field: 'select', + items: ['tcp', 'udp', 'icmp', 'all'], + label: 'IP Protocol', + value: 'all', + helperText: 'Specify the IP protocol', + }, + sourceport: { + field: 'text', + label: 'Source Port', + value: '', + helperText: 'The source port of target ip address or hostname, split by ,', + if: { + key: 'ip-protocol', + equal: ['tcp', 'udp'], + }, + }, + 'egress-port': { + field: 'text', + label: 'Egress Port', + value: '', + helperText: 'The egress port of target ip address or hostname, split by ,', + }, + percent: { + field: 'text', + label: 'Percent', + value: '1', + helperText: 'Percentage of network packet duplication', + }, +} + +const diskPhysicCommon: Spec = { + size: { + field: 'text', + label: 'Size', + value: '', + helperText: + 'The supported formats of the size are: c(=1), w(=2), kB(=1000), K(=1024), MB(=1000*1000), M(=1024*1024), GB and so on.', + }, + path: { + field: 'text', + label: 'Path', + value: '', + helperText: 'Specify the file path of the data to be read/written', + }, +} + +const jvmPhysicPidAndPort: Spec = { + pid: { + field: 'number', + label: 'Pid', + value: '', + helperText: 'ID of the Java process being injected into the fault', + }, + ...jvmPort, +} + +export const dataPhysic: Record = { + DiskChaos: { + categories: [ + { + name: 'Read Payload', + key: 'disk-read-payload', + spec: { + action: 'disk-read-payload' as any, + ...diskPhysicCommon, + 'payload-process-num': { + field: 'number', + label: 'Payload process num', + value: 1, + }, + }, + }, + { + name: 'Write Payload', + key: 'disk-write-payload', + spec: { + action: 'disk-write-payload' as any, + ...diskPhysicCommon, + 'payload-process-num': { + field: 'number', + label: 'Payload process num', + value: 1, + }, + }, + }, + { + name: 'Fill', + key: 'disk-fill', + spec: { + action: 'disk-fill' as any, + ...diskPhysicCommon, + 'fill-by-fallocate': { + field: 'select', + items: [ + { + label: 'true', + value: true, + }, + { + label: 'false', + value: false, + }, + ], + label: 'Fill by fallocate', + value: true, + helperText: 'Whether to use fallocate to quickly request disk space', + }, + }, + }, + ], + }, + JVMChaos: { + categories: [ + { + name: 'Exception', + key: 'jvm-exception', + spec: { + action: 'jvm-exception' as any, + exception: { + field: 'text', + label: 'Exception', + value: '', + helperText: 'Specify the exception to be thrown', + }, + ...jvmClassAndMethod, + ...jvmPhysicPidAndPort, + }, + }, + { + name: 'GC', + key: 'jvm-gc', + spec: { + action: 'jvm-gc' as any, + ...jvmPhysicPidAndPort, + }, + }, + { + name: 'Latency', + key: 'jvm-latency', + spec: { + action: 'jvm-latency' as any, + latency: { + field: 'number', + label: 'Latency', + value: '', + helperText: 'Specify the time of latency, unit is millisecond', + }, + ...jvmClassAndMethod, + ...jvmPhysicPidAndPort, + }, + }, + { + name: 'Return', + key: 'jvm-return', + spec: { + action: 'jvm-return' as any, + value: { + field: 'text', + label: 'Value', + value: '', + helperText: 'Specify the return value', + }, + ...jvmClassAndMethod, + ...jvmPhysicPidAndPort, + }, + }, + { + name: 'Stress', + key: 'jvm-stress', + spec: { + action: 'jvm-stress' as any, + 'cpu-count': { + field: 'number', + label: 'CPU Count', + value: '', + helperText: 'Specify the CPU count', + }, + 'mem-type': { + field: 'select', + items: ['stack', 'heap'], + label: 'Mem Type', + value: '', + helperText: 'Specify the mem type', + }, + ...jvmPhysicPidAndPort, + }, + }, + { + name: 'Rule', + key: 'jvm-rule-data', + spec: { + 'rule-data': { + field: 'textarea', + label: 'Rule', + value: '', + helperText: 'byteman rule configuration', + }, + ...jvmPhysicPidAndPort, + }, + }, + ], + }, + NetworkChaos: { + categories: [ + { + name: 'Corrupt', + key: 'network-corrupt', + spec: { + action: 'network-corrupt' as any, + ...networkPhysicCommon, + }, + }, + { + name: 'Duplicate', + key: 'network-duplicate', + spec: { + action: 'network-duplicate' as any, + ...networkPhysicCommon, + }, + }, + { + name: 'Loss', + key: 'network-loss', + spec: { + action: 'network-loss' as any, + ...networkPhysicCommon, + }, + }, + { + name: 'Delay', + key: 'network-delay', + spec: { + action: 'network-delay' as any, + latency: { + field: 'text', + label: 'Latency', + value: '', + helperText: 'The latency of delay', + }, + jitter: { + field: 'text', + label: 'Jitter', + value: '', + helperText: 'The jitter of delay', + }, + ...networkPhysicCommon, + percent: undefined as any, + }, + }, + { + name: 'Partition', + key: 'network-partition', + spec: { + action: 'network-partition' as any, + direction: networkCommon['direction'], + ...networkPhysicCommon, + 'accept-tcp-flags': { + field: 'text', + label: 'Accept TCP Flags', + value: '', + if: { + key: 'ip-protocol', + equal: 'tcp', + }, + }, + correlation: undefined as any, + sourceport: undefined as any, + 'egress-port': undefined as any, + percent: undefined as any, + }, + }, + { + name: 'Bandwidth', + key: 'network-bandwidth', + spec: { + action: 'network-bandwidth' as any, + rate: { + field: 'text', + label: 'Rate', + value: '', + helperText: 'The rate allows bps, kbps, mbps, gbps, tbps unit. For example, bps means bytes per second', + }, + limit: { + field: 'number', + label: 'Limit', + value: 0, + helperText: 'The number of bytes that can be queued waiting for tokens to become available', + }, + buffer: { + field: 'number', + label: 'Buffer', + value: 0, + helperText: 'The maximum amount of bytes that tokens can be available instantaneously', + }, + minburst: { + field: 'number', + label: 'Min burst', + value: 0, + helperText: 'The size of the peakrate bucket', + }, + peakrate: { + field: 'number', + label: 'Peak rate', + value: 0, + helperText: 'The maximum depletion rate of the bucket', + }, + direction: networkCommon['direction'], + + device: { + field: 'text', + label: 'Device', + value: '', + helperText: 'Affected device, e.g., eth0', + }, + hostname: { + field: 'text', + label: 'Hostname', + value: '', + helperText: 'Specify the hostname', + }, + 'ip-address': { + field: 'text', + label: 'IP Address', + value: '', + helperText: 'Specify the IP address', + }, + }, + }, + { + name: 'DNS', + key: 'network-dns', + spec: { + action: 'network-dns' as any, + 'dns-domain-name': { + field: 'text', + label: 'Hostname', + value: '', + helperText: 'Affected domains', + }, + 'dns-ip': { + field: 'text', + label: 'IP', + value: '', + helperText: 'Indicates that the affected domain is mapped to this address', + }, + 'dns-server': { + field: 'text', + label: 'Server', + value: '', + helperText: 'DNS server address', + }, + }, + }, + ], + }, + ProcessChaos: { + spec: { + action: 'process' as any, + process: { + field: 'text', + label: 'Process', + value: '', + helperText: 'The name or ID of the process to be killed', + }, + signal: { + field: 'number', + label: 'Signal', + value: 9, + helperText: 'The process signal value', + }, + recoverCmd: { + field: 'text', + label: 'Recover Command', + value: '', + helperText: 'The command to be run when recovering experiment', + }, + }, + }, + StressChaos: { + categories: [ + { + name: 'CPU', + key: 'stress-cpu', + spec: { + action: 'stress-cpu' as any, + workers: { + field: 'number', + label: 'Workers', + value: 0, + helperText: 'Workers', + }, + load: { + field: 'number', + label: 'Load', + value: 0, + helperText: 'Load', + }, + }, + }, + { + name: 'Memory', + key: 'stress-mem', + spec: { + action: 'stress-mem' as any, + size: { + field: 'text', + label: 'Size', + value: '', + helperText: 'The supported formats of the size are: B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.', + }, + }, + }, + ], + }, + TimeChaos: { + spec: { + action: 'clock' as any, + 'time-offset': { + field: 'text', + label: 'Offset', + value: '', + helperText: 'Fill the time offset', + }, + pid: { + field: 'number', + label: 'Pid', + value: '', + helperText: 'ID of the process that will be injected into the fault', + }, + }, + }, +} + +const AWSChaosCommonSchema = Yup.object({ + awsRegion: Yup.string().required('The region is required'), + ec2Instance: Yup.string().required('The ID of the EC2 instance is required'), +}) + +const patternsSchema = Yup.array().of(Yup.string()).required('The patterns is required') + +const GCPChaosCommonSchema = Yup.object({ + project: Yup.string().required('The project is required'), + zone: Yup.string().required('The zone is required'), + instance: Yup.string().required('The instance is required'), +}) + +const networkTargetSchema = Yup.object({ + namespaces: Yup.array().min(1, 'The namespace selectors is required'), +}) + +const httpDelayCommonSchema = { + delay: Yup.string().required('The delay is required'), +} + +const httpPathCommonSchema = { + path: Yup.string().required('The path is required'), +} + +export const schema: Partial>> = { + AWSChaos: { + 'ec2-stop': AWSChaosCommonSchema, + 'ec2-restart': AWSChaosCommonSchema, + 'detach-volume': AWSChaosCommonSchema.shape({ + deviceName: Yup.string().required('The device name is required'), + volumeID: Yup.string().required('The ID of the EBS volume is required'), + }), + }, + DNSChaos: { + error: Yup.object({ + patterns: patternsSchema, + }), + random: Yup.object({ + patterns: patternsSchema, + }), + }, + GCPChaos: { + 'node-stop': GCPChaosCommonSchema, + 'node-reset': GCPChaosCommonSchema, + 'disk-loss': GCPChaosCommonSchema.shape({ + deviceNames: Yup.array().of(Yup.string()).required('At least one device name is required'), + }), + }, + IOChaos: { + latency: Yup.object({ + delay: Yup.string().required('The delay is required'), + }), + fault: Yup.object({ + errno: Yup.number().min(0).required('The errno is required'), + }), + attrOverride: Yup.object({ + attr: Yup.array().of(Yup.string()).required('The attr is required'), + }), + }, + HTTPChaos: { + 'request-abort': Yup.object({ + ...httpPathCommonSchema, + }), + 'request-delay': Yup.object({ + ...httpDelayCommonSchema, + ...httpPathCommonSchema, + }), + 'request-replace': Yup.object({ + ...httpPathCommonSchema, + }), + 'request-patch': Yup.object({ + ...httpPathCommonSchema, + }), + 'response-abort': Yup.object({ + ...httpPathCommonSchema, + }), + 'response-delay': Yup.object({ + ...httpDelayCommonSchema, + ...httpPathCommonSchema, + }), + 'response-replace': Yup.object({ + ...httpPathCommonSchema, + }), + 'response-patch': Yup.object({ + ...httpPathCommonSchema, + }), + }, + NetworkChaos: { + partition: Yup.object({ + target: networkTargetSchema, + }), + loss: Yup.object({ + loss: Yup.object({ + loss: Yup.string().required('The loss is required'), + }), + target: networkTargetSchema, + }), + delay: Yup.object({ + delay: Yup.object({ + latency: Yup.string().required('The latency is required'), + }), + target: networkTargetSchema, + }), + duplicate: Yup.object({ + duplicate: Yup.object({ + duplicate: Yup.string().required('The duplicate is required'), + }), + target: networkTargetSchema, + }), + corrupt: Yup.object({ + corrupt: Yup.object({ + corrupt: Yup.string().required('The corrupt is required'), + }), + target: networkTargetSchema, + }), + bandwidth: Yup.object({ + bandwidth: Yup.object({ + rate: Yup.string().required('The rate of bandwidth is required'), + }), + target: networkTargetSchema, + }), + }, + PodChaos: { + 'pod-kill': Yup.object({ + gracePeriod: Yup.number().min(0, 'Grace period must be non-negative integer'), + }), + 'container-kill': Yup.object({ + containerNames: Yup.array().of(Yup.string()).required('At least one container name is required'), + }), + }, + TimeChaos: { + default: Yup.object({ + timeOffset: Yup.string().required('The time offset is required'), + }), + }, +} + +export type dataType = typeof data + +export default data diff --git a/ui/app/src/components/NewExperimentNext/form/Kernel.tsx b/ui/app/src/components/NewExperimentNext/form/Kernel.tsx new file mode 100644 index 0000000000..10f2e73472 --- /dev/null +++ b/ui/app/src/components/NewExperimentNext/form/Kernel.tsx @@ -0,0 +1,138 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import AddCircleIcon from '@mui/icons-material/AddCircle' +import RemoveCircleIcon from '@mui/icons-material/RemoveCircle' +import { Box, IconButton, InputAdornment, MenuItem, Typography } from '@mui/material' +import { Form, Formik } from 'formik' +import { useEffect, useState } from 'react' + +import Paper from '@ui/mui-extends/esm/Paper' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreSelector } from 'store' + +import { LabelField, SelectField, Submit, TextField } from 'components/FormField' + +import typesData from '../data/types' + +interface KernelProps { + onSubmit: (values: Record) => void +} + +const Kernel: React.FC = ({ onSubmit }) => { + const { spec } = useStoreSelector((state) => state.experiments) + + const initialValues = typesData.KernelChaos.spec! + + const [init, setInit] = useState(initialValues) + + useEffect(() => { + setInit({ + failKernRequest: { + ...initialValues.failKernRequest, + ...spec.failKernRequest, + }, + }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [spec]) + + return ( + + {({ values, setFieldValue }) => { + const callchain = (values.failKernRequest as any).callchain + + const addFrame = () => + setFieldValue( + 'failKernRequest.callchain', + callchain.concat([ + { + funcname: '', + parameters: '', + predicate: '', + }, + ]) + ) + + const removeFrame = (index: number) => () => { + setFieldValue( + 'failKernRequest.callchain', + callchain.filter((_: any, i: number) => index !== i) + ) + } + + return ( +
+ + + Callchain + + + + + {callchain.length > 0 && ( + + {callchain.map((_: any, i: number) => ( + + + Frame {i + 1} + + + + + + + + + ))} + + )} + + + + {[0, 1, 2].map((option) => ( + + {option} + + ))} + + + %} + /> + + + + + + ) + }} +
+ ) +} + +export default Kernel diff --git a/ui/app/src/components/NewExperimentNext/form/Scheduler.tsx b/ui/app/src/components/NewExperimentNext/form/Scheduler.tsx new file mode 100644 index 0000000000..36c85c8057 --- /dev/null +++ b/ui/app/src/components/NewExperimentNext/form/Scheduler.tsx @@ -0,0 +1,129 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Box, FormControlLabel, Link, Switch, Typography } from '@mui/material' +import { FormikErrors, FormikTouched, getIn, useFormikContext } from 'formik' +import { useEffect, useState } from 'react' +import { FormattedMessage } from 'react-intl' + +import { useStoreSelector } from 'store' + +import { TextField } from 'components/FormField' +import { ExperimentKind } from 'components/NewExperiment/types' +import i18n from 'components/T' + +import { validateDuration, validateSchedule } from 'lib/formikhelpers' + +function isInstant(kind: ExperimentKind | '', action: string) { + if (kind === 'PodChaos' && (action === 'pod-kill' || action === 'container-kill')) { + return true + } + + return false +} + +interface SchedulerProps { + errors: FormikErrors> + touched: FormikTouched> + inSchedule?: boolean +} + +const Scheduler: React.FC = ({ errors, touched, inSchedule = false }) => { + const { fromExternal, kindAction, basic } = useStoreSelector((state) => state.experiments) + const { values, setFieldValue } = useFormikContext() + const [kind, action] = kindAction + const instant = isInstant(kind, action) + + const [continuous, setContinuous] = useState(false) + + useEffect(() => { + if (!inSchedule && fromExternal && basic.spec.duration === '') { + setContinuous(true) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [fromExternal]) + + const handleChecked = (e: React.ChangeEvent) => { + const checked = e.target.checked + + setContinuous(checked) + + if (checked && getIn(values, 'spec.duration') !== '') { + setFieldValue('spec.duration', '') + } + } + + return ( + <> + + {i18n('newE.steps.run')} + {!inSchedule && ( + + } + label={i18n('newE.run.continuous')} + disabled={instant} + /> + )} + + + {inSchedule && ( + + https://crontab.guru/ + + ), + }} + /> + ) + } + error={getIn(errors, 'spec.schedule') && getIn(touched, 'spec.schedule') ? true : false} + /> + )} + + {!continuous && ( + + )} + + ) +} + +export default Scheduler diff --git a/ui/app/src/components/NewExperimentNext/form/Stress.tsx b/ui/app/src/components/NewExperimentNext/form/Stress.tsx new file mode 100644 index 0000000000..19c6e198a7 --- /dev/null +++ b/ui/app/src/components/NewExperimentNext/form/Stress.tsx @@ -0,0 +1,138 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Typography } from '@mui/material' +import { Form, Formik, getIn } from 'formik' +import { useEffect, useState } from 'react' + +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreSelector } from 'store' + +import { LabelField, Submit, TextField } from 'components/FormField' +import MoreOptions from 'components/MoreOptions' + +import typesData from '../data/types' + +const validate = (values: any) => { + let errors = {} + + const { cpu, memory } = values.stressors + + if (cpu.workers <= 0 && memory.workers <= 0) { + const message = 'The CPU or Memory workers must have at least one greater than 0' + + errors = { + stressors: { + cpu: { + workers: message, + }, + memory: { + workers: message, + }, + }, + } + } + + return errors +} + +interface StressProps { + onSubmit: (values: Record) => void +} + +const Stress: React.FC = ({ onSubmit }) => { + const { spec } = useStoreSelector((state) => state.experiments) + + const initialValues = typesData.StressChaos.spec! + + const [init, setInit] = useState(initialValues) + + useEffect(() => { + setInit({ + ...initialValues, + ...spec, + }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [spec]) + + return ( + + {({ errors }) => ( +
+ + CPU + + + + + Memory + + + + + + + + + + + + + )} +
+ ) +} + +export default Stress diff --git a/ui/app/src/components/NewExperimentNext/form/TargetGenerated.tsx b/ui/app/src/components/NewExperimentNext/form/TargetGenerated.tsx new file mode 100644 index 0000000000..af9a8f30d7 --- /dev/null +++ b/ui/app/src/components/NewExperimentNext/form/TargetGenerated.tsx @@ -0,0 +1,244 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { MenuItem } from '@mui/material' +import { Stale } from 'api/queryUtils' +import { Form, Formik, FormikErrors, FormikTouched, getIn, setIn } from 'formik' +import { useGetCommonChaosAvailableNamespaces } from 'openapi' +import { useEffect, useState } from 'react' +import { ObjectSchema } from 'yup' + +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreSelector } from 'store' + +import { Env } from 'slices/experiments' + +import { AutocompleteField, LabelField, SelectField, Submit, TextField } from 'components/FormField' +import MoreOptions from 'components/MoreOptions' +import Scope from 'components/Scope' +import i18n from 'components/T' + +import basicData from '../data/basic' +import { Kind, Spec } from '../data/types' + +interface TargetGeneratedProps { + env: Env + kind?: Kind | '' + data: Spec + validationSchema?: ObjectSchema + onSubmit: (values: Record) => void +} + +const TargetGenerated: React.FC = ({ env, kind, data, validationSchema, onSubmit }) => { + const { spec } = useStoreSelector((state) => state.experiments) + + const { data: namespaces } = useGetCommonChaosAvailableNamespaces({ + query: { + enabled: false, + staleTime: Stale.DAY, + }, + }) + + let initialValues = Object.entries(data).reduce((acc, [k, v]) => { + if (v instanceof Object && v.field) { + acc = setIn(acc, k, v.value) + } else { + acc[k] = v + } + + return acc + }, {} as Record) + + if (env === 'k8s' && kind === 'NetworkChaos') { + const action = initialValues.action + delete initialValues.action + const direction = initialValues.direction + delete initialValues.direction + const externalTargets = initialValues.externalTargets + delete initialValues.externalTargets + + initialValues = { + action, + [action]: action !== 'partition' ? initialValues : undefined, + direction, + externalTargets, + } + } + + const [init, setInit] = useState(initialValues) + + useEffect(() => { + setInit({ + ...initialValues, + ...spec, + }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [spec]) + + const parseDataToFormFields = ( + errors: FormikErrors>, + touched: FormikTouched> + ) => { + const rendered = Object.entries(data) + .filter(([_, v]) => v && v instanceof Object && v.field) + .map(([k, v]) => { + if (env === 'k8s' && kind === 'NetworkChaos' && k !== 'direction' && k !== 'externalTargets') { + k = `${data.action}.${k}` + } + + if (env === 'k8s' && kind === 'BlockChaos' && k !== 'volumeName' && k !== 'iops' && k !== 'containerNames') { + k = `${data.action}.${k}` + } + + switch (v.field) { + case 'text': + return ( + + ) + case 'textarea': + return ( + + ) + case 'number': + return ( + + ) + case 'select': + return ( + + {v.items?.map((option: string | { label: string; value: any }) => + option instanceof Object ? ( + + {option.label} + + ) : ( + + {option} + + ) + )} + + ) + case 'label': + return ( + + ) + case 'autocomplete': + return ( + + ) + default: + return null + } + }) + .filter((d) => d) + + return <>{rendered.map((d) => d)} + } + + return ( + + {({ values, setFieldValue, errors, touched }) => { + const beforeTargetOpen = () => { + if (!getIn(values, 'target')) { + setFieldValue('target', { + selector: basicData.spec.selector, + mode: basicData.spec.mode, + value: basicData.spec.value, + }) + } + } + + const afterTargetClose = () => { + if (getIn(values, 'target')) { + setFieldValue('target', undefined) + } + } + + return ( +
+ {parseDataToFormFields(errors, touched)} + {env === 'k8s' && kind === 'NetworkChaos' && ( + + {values.target && ( + + )} + + )} + + + ) + }} +
+ ) +} + +export default TargetGenerated diff --git a/ui/app/src/components/NewExperimentNext/index.tsx b/ui/app/src/components/NewExperimentNext/index.tsx new file mode 100644 index 0000000000..81b6883a86 --- /dev/null +++ b/ui/app/src/components/NewExperimentNext/index.tsx @@ -0,0 +1,110 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { forwardRef, useImperativeHandle, useState } from 'react' +import { setEnv, setExternalExperiment } from 'slices/experiments' + +import { Box } from '@mui/material' +import ByYAML from './ByYAML' +import LoadFrom from './LoadFrom' +import Space from '@ui/mui-extends/esm/Space' +import Step1 from './Step1' +import Step2 from './Step2' +import Step3 from './Step3' +import Tab from '@mui/material/Tab' +import TabContext from '@mui/lab/TabContext' +import TabList from '@mui/lab/TabList' +import TabPanel from '@mui/lab/TabPanel' +import i18n from 'components/T' +import { parseYAML } from 'lib/formikhelpers' +import { useStoreDispatch } from 'store' + +type PanelType = 'initial' | 'existing' | 'yaml' + +export interface NewExperimentHandles { + setPanel: React.Dispatch> +} + +interface NewExperimentProps { + onSubmit?: (parsedValues: any) => void + loadFrom?: boolean + inWorkflow?: boolean + inSchedule?: boolean +} + +const NewExperiment: React.ForwardRefRenderFunction = ( + { onSubmit, loadFrom = true, inWorkflow, inSchedule }, + ref +) => { + const dispatch = useStoreDispatch() + + const [panel, setPanel] = useState('initial') + + useImperativeHandle(ref, () => ({ + setPanel, + })) + + const onChange = (_: any, newValue: PanelType) => { + setPanel(newValue) + } + + const fillExperiment = (original: any) => { + const { kind, basic, spec } = parseYAML(original) + const env = kind === 'PhysicalMachineChaos' ? 'physic' : 'k8s' + const action = spec.action ?? '' + + dispatch(setEnv(env)) + dispatch( + setExternalExperiment({ + kindAction: [kind, action], + spec, + basic, + }) + ) + + setPanel('initial') + } + + return ( + + {loadFrom && ( + + + + + + + + )} + + + + + + + + + {loadFrom && } + + + + + + ) +} + +export default forwardRef(NewExperiment) diff --git a/ui/app/src/components/NewWorkflow/Add.tsx b/ui/app/src/components/NewWorkflow/Add.tsx new file mode 100644 index 0000000000..81d9f454da --- /dev/null +++ b/ui/app/src/components/NewWorkflow/Add.tsx @@ -0,0 +1,385 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Box, Button, MenuItem, StepLabel, Typography } from '@mui/material' +import NewExperimentNext, { NewExperimentHandles } from 'components/NewExperimentNext' +import { SelectField, TextField } from 'components/FormField' +import { Template, TemplateType, setTemplate, updateTemplate } from 'slices/workflows' +import { resetNewExperiment, setExternalExperiment } from 'slices/experiments' +import { useEffect, useRef, useState } from 'react' +import { useStoreDispatch, useStoreSelector } from 'store' + +import AddCircleIcon from '@mui/icons-material/AddCircle' +import CloseIcon from '@mui/icons-material/Close' +import { Formik } from 'formik' +import HTTPTask from './HTTPTask' +import SerialOrParallel from './SerailOrParallel' +import Space from '@ui/mui-extends/esm/Space' +import Suspend from './Suspend' +import Task from './Task' +import i18n from 'components/T' +import { makeStyles } from '@mui/styles' +import { parseYAML } from 'lib/formikhelpers' +import { setAlert } from 'slices/globalStatus' +import { useIntl } from 'react-intl' + +const useStyles = makeStyles({ + field: { + width: 180, + }, +}) + +export enum RenderableTemplateType { + HTTP = 'http', +} + +export type AllTemplateType = RenderableTemplateType | TemplateType + +const types = Object.values({ ...TemplateType, ...RenderableTemplateType }) + +interface AddProps { + childIndex?: number + parentTemplates?: Template[] + setParentTemplates?: React.Dispatch> + setParentExpand?: React.Dispatch> + externalTemplate?: Template + update?: number + updateCallback?: () => void +} + +const Add: React.FC = ({ + childIndex, + parentTemplates, + setParentTemplates, + setParentExpand, + externalTemplate, + update, + updateCallback, +}) => { + const classes = useStyles() + const intl = useIntl() + + const dispatch = useStoreDispatch() + const { templates: storeTemplates } = useStoreSelector((state) => state.workflows) + + const [initialValues, setInitialValues] = useState({ + type: TemplateType.Single as AllTemplateType, + num: 2, + name: '', + deadline: '', + container: { + name: '', + image: '', + command: [] as string[], + }, + conditionalBranches: [ + { + target: '', + expression: '', + }, + { + target: '', + expression: '', + }, + ], + }) + const [num, setNum] = useState(-1) + const [templates, setTemplates] = useState([]) + const formRef = useRef() + const newERef = useRef(null) + const [typeOfTemplate, setTypeOfTemplate] = useState(TemplateType.Single) + + // use methods instead of this state + const [isRenderedHTTPTask, setIsRenderedHTTPTask] = useState(false) + + const fillExperiment = (t: Template) => { + const e = t.experiment + + const { kind, basic, spec } = parseYAML(e) + + dispatch( + setExternalExperiment({ + kindAction: [kind, spec.action ?? ''], + spec, + basic, + }) + ) + } + + useEffect(() => { + // TODO: use API provided by server + if (externalTemplate) { + if ( + externalTemplate.type === 'custom' && + externalTemplate.custom && + externalTemplate.custom.container.name.endsWith('-rendered-http-request') + ) { + setIsRenderedHTTPTask(true) + } + } else { + setIsRenderedHTTPTask(false) + } + }, [externalTemplate]) + + useEffect(() => { + if (externalTemplate) { + const { type, name, deadline, children, custom } = externalTemplate + + switch (type) { + case 'single': + fillExperiment(externalTemplate) + + break + case 'serial': + case 'parallel': + case 'custom': + const templates = children! + + setTemplates(templates) + setNum(templates.length) + + // TODO: if rendered http set type to http + + break + } + + setInitialValues({ + ...initialValues, + type, + num: children ? children.length : 2, + name, + deadline: deadline || '', + ...custom, + }) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [externalTemplate]) + + const resetNoSingle = () => { + setNum(-1) + setTemplates([]) + } + + const onValidate = ({ type, num: newNum }: { type: string; num: number }) => { + setIsRenderedHTTPTask(type === 'http') + setTypeOfTemplate(type as AllTemplateType) + + const prevType = formRef.current.values.type + + if (prevType !== 'single' && type === 'single') { + resetNoSingle() + + return + } + + if (type === 'serial' || type === 'parallel' || type === 'custom') { + if (typeof newNum !== 'number' || newNum < 0) { + if (isRenderedHTTPTask) { + resetNoSingle() + return + } + + formRef.current.setFieldValue('num', 2) + + return + } + + // Protect exist templates + if (newNum < templates.length) { + return + } + + setNum(newNum) + + return + } + + if (type === 'http') { + resetNoSingle() + return + } + + if (type === 'suspend') { + if (prevType === 'serial' || prevType === 'parallel' || prevType === 'custom') { + resetNoSingle() + } + } + } + + const submit = (template: Template) => { + if (storeTemplates.some((t) => t.name === template.name)) { + dispatch( + setAlert({ + type: 'warning', + message: i18n('newW.messages.redundant', intl), + }) + ) + + return + } + + if (childIndex !== undefined) { + if (parentTemplates![childIndex!]) { + const tmp = JSON.parse(JSON.stringify(parentTemplates!)) + tmp[childIndex!] = template + + setParentTemplates!(tmp) + } else { + setParentTemplates!([...parentTemplates!, template]) + } + + setParentExpand!(-1) + } else { + dispatch(update !== undefined ? updateTemplate({ ...template, index: update }) : setTemplate(template)) + typeof updateCallback === 'function' && updateCallback() + } + } + + const onSubmit = (experiment: any) => { + const type = formRef.current.values.type + + const name = experiment.metadata.name + const template = { + type, + name, + experiment, + } + + submit(template) + + dispatch(resetNewExperiment()) + } + + const submitNoSingleNode = () => { + const { type, name, deadline, container, conditionalBranches } = formRef.current.values + const template: Template = { + type, + name: name.trim(), + deadline, + children: templates, + } + if (type === 'custom') { + template.custom = { + container, + conditionalBranches, + } + } + + submit(template) + + resetNoSingle() + } + + return ( + <> + + {({ values, setFieldValue, errors, touched }) => { + return ( + <> + }> + + + {types.map((d) => ( + + {i18n(`newW.node.${d}`)} + + ))} + + {num > 0 && ( + + )} + {update !== undefined && ( + + )} + + + + {(values.type === 'serial' || values.type === 'parallel') && ( + + )} + {values.type === 'custom' && !isRenderedHTTPTask && ( + <> + + + )} + {isRenderedHTTPTask && ( + + + + )} + + ) + }} + + + {num < 0 && ( + + {typeOfTemplate === 'suspend' && ( + + + + )} + + {typeOfTemplate === 'single' && ( + + + + )} + + )} + + ) +} + +export default Add diff --git a/ui/app/src/components/NewWorkflow/HTTPTask.tsx b/ui/app/src/components/NewWorkflow/HTTPTask.tsx new file mode 100644 index 0000000000..9f8c0c2cb7 --- /dev/null +++ b/ui/app/src/components/NewWorkflow/HTTPTask.tsx @@ -0,0 +1,195 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Form, Formik } from 'formik' +import { FormControlLabel, Switch } from '@mui/material' +import { MenuItem, Typography } from '@mui/material' +import { SelectField, Submit, TextField } from 'components/FormField' +import { Template, TemplateType } from 'slices/workflows' +import { parseHTTPTask, renderHTTPTask } from 'api/workflows' +import { useEffect, useRef, useState } from 'react' + +import Paper from '@ui/mui-extends/esm/Paper' +import PaperTop from '@ui/mui-extends/esm/PaperTop' +import { RequestForm } from 'api/workflows.type' +import Space from '@ui/mui-extends/esm/Space' +import i18n from 'components/T' +import { makeStyles } from '@mui/styles' +import { useIntl } from 'react-intl' +import { validateName } from 'lib/formikhelpers' + +const useStyles = makeStyles({ + field: { + width: 180, + }, +}) + +const HTTPMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTION'] + +interface HTTPTaskProps extends CommonTemplateProps { + childrenCount: number + submitTemplate: (template: Template) => void +} + +interface CommonTemplateProps { + name?: string + deadline?: string + type: TemplateType + templates: Template[] + externalTemplate?: Template +} + +const HTTPTask: React.FC = (props) => { + const intl = useIntl() + const classes = useStyles() + + const { submitTemplate } = props + const onSubmit = (form: RequestForm) => { + renderHTTPTask(form) + .then((response) => { + const { name, task } = response.data! + const { container } = task + const result: Template = { + name, + children: [], + type: TemplateType.Custom, + custom: { + container, + conditionalBranches: [], + }, + } + submitTemplate(result) + }) + .catch(console.error) + } + const formRef = useRef() + const [initialValues, setInitialValues] = useState({ + name: props.name || '', + url: '', + method: '', + body: '', + followLocation: false, + jsonContent: false, + }) + + useEffect(() => { + if (props.externalTemplate) { + // TODO: use unified name + const backendType = props.externalTemplate.type === 'custom' ? 'Task' : props.externalTemplate.type + parseHTTPTask({ + name: props.externalTemplate.name, + templateType: backendType, + task: { + container: props.externalTemplate.custom!.container, + conditionalBranches: props.externalTemplate.custom!.conditionalBranches, + }, + }) + .then((response) => { + if (response.data) { + const parsedForm = response.data as RequestForm + setInitialValues({ + ...parsedForm, + followLocation: parsedForm.followLocation || false, + jsonContent: parsedForm.jsonContent || false, + }) + } + }) + .catch(console.error) + } + return () => {} + }, [props.externalTemplate]) + + return ( + + + + + {({ values, errors, touched, handleChange }) => { + return ( +
+ + + + + + {HTTPMethods.map((method) => ( + + {method} + + ))} + + {(values.method === 'POST' || values.method === 'PUT') && ( + + )} + + } + /> + + } + /> + + +
+ ) + }} +
+
+
+ ) +} + +export default HTTPTask diff --git a/ui/app/src/components/NewWorkflow/SerailOrParallel.tsx b/ui/app/src/components/NewWorkflow/SerailOrParallel.tsx new file mode 100644 index 0000000000..d5392347d3 --- /dev/null +++ b/ui/app/src/components/NewWorkflow/SerailOrParallel.tsx @@ -0,0 +1,189 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Box, IconButton, Typography } from '@mui/material' +import { Form, Formik } from 'formik' +import { Submit, TextField } from 'components/FormField' +import { Template, TemplateType } from 'slices/workflows' +import { useRef, useState } from 'react' +import { validateDeadline, validateName } from 'lib/formikhelpers' + +import Add from './Add' +import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown' +import ArrowRightIcon from '@mui/icons-material/ArrowRight' +import Paper from '@ui/mui-extends/esm/Paper' +import PaperTop from '@ui/mui-extends/esm/PaperTop' +import React from 'react' +import Space from '@ui/mui-extends/esm/Space' +import i18n from 'components/T' +import { resetNewExperiment } from 'slices/experiments' +import { setAlert } from 'slices/globalStatus' +import { useIntl } from 'react-intl' +import { useStoreDispatch } from 'store' + +interface SerialOrParallelProps extends FormProps { + childrenCount: number + submitTemplate: (template: Template) => void + templates: Template[] +} +interface FormProps { + name?: string + deadline?: string + type: TemplateType +} +/** + * SerialOrParallel component is the editor of workflow template with type Serial or Parallel + * @param props SerialOrParallelProps + * @returns + */ +const SerialOrParallel: React.FC = (props) => { + const intl = useIntl() + const dispatch = useStoreDispatch() + + const formRef = useRef() + + // expand is an int index, stands for the detail page of (expand)-th child task is expanded + // so it's obvious that there is only one expanded detail page at a time + // when expand is -1, means no detail page is expanded + const [expand, setExpand] = useState(-1) + + const [templates, setTemplates] = useState(props.templates || []) + + const submitSerialOrParallel = () => { + const { name, deadline } = formRef.current.values + const template: Template = { + type: props.type, + name: name.trim(), + deadline, + children: templates, + } + props.submitTemplate(template) + } + + const onValidate = (values: FormProps) => { + const errors: any = {} + return errors + } + + const switchExpand = (index: number) => () => { + if (index > templates.length) { + dispatch( + setAlert({ + type: 'warning', + // Please fill in the current branch first + message: i18n('newW.messages.m1', intl), + }) + ) + + return + } + + setExpand( + expand === index + ? (function () { + dispatch(resetNewExperiment()) + + return -1 + })() + : index + ) + } + + return ( + + {({ values, setFieldValue, errors, touched }) => { + return ( + +
+ + + + + + + + +
+ + {Array(props.childrenCount) + .fill(0) + .map((_, index) => ( + + + + + {expand === index ? : } + + + {templates.length > index + ? templates[index].name + : `${i18n('newW.node.child', intl)} ${index + 1}`} + + + + {expand === index && ( + + + + )} + + ))} +
+ ) + }} +
+ ) +} +export default SerialOrParallel diff --git a/ui/app/src/components/NewWorkflow/Suspend.tsx b/ui/app/src/components/NewWorkflow/Suspend.tsx new file mode 100644 index 0000000000..5be1f2734f --- /dev/null +++ b/ui/app/src/components/NewWorkflow/Suspend.tsx @@ -0,0 +1,85 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Form, Formik } from 'formik' +import { Submit, TextField } from 'components/FormField' +import { Template, TemplateType } from 'slices/workflows' +import { validateDeadline, validateName } from 'lib/formikhelpers' + +import Paper from '@ui/mui-extends/esm/Paper' +import PaperTop from '@ui/mui-extends/esm/PaperTop' +import Space from '@ui/mui-extends/esm/Space' +import i18n from 'components/T' +import { schemaBasic } from './types' +import { useIntl } from 'react-intl' + +export interface SuspendValues { + name: string + deadline: string +} + +interface SuspendProps { + initialValues?: SuspendValues + submit: (template: Template) => void +} + +const Suspend: React.FC = ({ initialValues, submit }) => { + const intl = useIntl() + + const onSubmit = ({ name, deadline }: SuspendValues) => { + const values = schemaBasic.cast({ name, deadline }) + + submit({ + type: TemplateType.Suspend, + ...values!, + }) + } + + return ( + + + + + {({ errors, touched }) => ( +
+ + + + + + + )} +
+
+
+ ) +} + +export default Suspend diff --git a/ui/app/src/components/NewWorkflow/Task.tsx b/ui/app/src/components/NewWorkflow/Task.tsx new file mode 100644 index 0000000000..d0be978645 --- /dev/null +++ b/ui/app/src/components/NewWorkflow/Task.tsx @@ -0,0 +1,329 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Autocomplete, Box, IconButton, TextField as MUITextField, Typography } from '@mui/material' +import { Branch, Template, TemplateType } from 'slices/workflows' +import { Form, Formik } from 'formik' +import { LabelField, Submit, TextField } from 'components/FormField' +import { useRef, useState } from 'react' +import { useStoreDispatch, useStoreSelector } from 'store' +import { validateImage, validateName } from 'lib/formikhelpers' + +import Add from './Add' +import AddCircleIcon from '@mui/icons-material/AddCircle' +import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown' +import ArrowRightIcon from '@mui/icons-material/ArrowRight' +import Paper from '@ui/mui-extends/esm/Paper' +import PaperTop from '@ui/mui-extends/esm/PaperTop' +import RemoveCircleIcon from '@mui/icons-material/RemoveCircle' +import Space from '@ui/mui-extends/esm/Space' +import i18n from 'components/T' +import { resetNewExperiment } from 'slices/experiments' +import { setAlert } from 'slices/globalStatus' +import { useIntl } from 'react-intl' + +interface TaskProps extends FormProps { + childrenCount: number + submitTemplate: (template: Template) => void + templates: Template[] +} + +interface FormProps { + name?: string + deadline?: string + type: TemplateType + container: Container + conditionalBranches: Branch[] +} +interface Container { + name: string + image: string + command: string[] +} + +const Task: React.FC = (props) => { + const intl = useIntl() + const dispatch = useStoreDispatch() + const formRef = useRef() + + const { templates: storeTemplates } = useStoreSelector((state) => state.workflows) + const [templates, setTemplates] = useState(props.templates) + const templateNames = [...new Set([...storeTemplates, ...templates].map((t) => t.name))] + + const submitTask = () => { + const { name, deadline, container, conditionalBranches } = formRef.current.values + const template: Template = { + type: props.type, + name: name.trim(), + deadline, + children: templates, + custom: { + container, + conditionalBranches, + }, + } + props.submitTemplate(template) + } + + // expand is an int index, stands for the detail page of (expand)-th child task is expanded + // so it's obvious that there is only one expanded detail page at a time + // when expand is -1, means no detail page is expanded + const [expand, setExpand] = useState(-1) + const switchExpand = (index: number) => () => { + if (index > templates.length) { + dispatch( + setAlert({ + type: 'warning', + // Please fill in the current branch first + message: i18n('newW.messages.m1', intl), + }) + ) + + return + } + + setExpand( + expand === index + ? (function () { + dispatch(resetNewExperiment()) + + return -1 + })() + : index + ) + } + return ( + <> + + {({ values, setFieldValue, errors, touched }) => { + const { conditionalBranches } = values + + const addBranch = (branch: Branch) => () => { + if (branch.target === '') { + dispatch( + setAlert({ + type: 'warning', + message: i18n('newW.messages.m2', intl), + }) + ) + + return + } + + setFieldValue( + 'conditionalBranches', + conditionalBranches.concat([ + { + target: '', + expression: '', + }, + ]) + ) + // setChildrenCount(childrenCount + 1) + } + + const removeBranch = (index: number) => () => { + setFieldValue( + 'conditionalBranches', + conditionalBranches.filter((_: any, i: number) => index !== i) + ) + // setChildrenCount(childrenCount - 1) + setTemplates(templates.filter((_: any, i: number) => index !== i)) + } + + const conditionalBranchTargetSelected = + (index: number) => (_: any, newVal: string | null, reason: string) => { + const name = `conditionalBranches[${index}].target` + + if (reason === 'clear') { + setFieldValue(name, '') + + return + } + + setFieldValue(name, newVal) + + if (templateNames.includes(newVal!)) { + const template = [...storeTemplates, ...templates].find((t) => t.name === newVal)! + + const tmp = JSON.parse(JSON.stringify(templates)) + tmp[index] = template + + setTemplates(tmp) + // setNum(tmp.length) + } + } + + return ( + props.type === 'custom' && ( + +
+ + + + + {i18n('newW.node.container.title')} + + + + {i18n('newW.node.conditionalBranches.title')} + {conditionalBranches.length > 0 && + conditionalBranches.map((d, i) => ( + + + if + + + + then + + ( + + )} + PaperComponent={(props) => } + /> + {i !== conditionalBranches.length - 1 && ( + + + + )} + {i === conditionalBranches.length - 1 && ( + + + + )} + + ))} + + + +
+ + {Array(props.childrenCount) + .fill(0) + .map((_, index) => ( + + + + + {expand === index ? : } + + + {templates.length > index + ? templates[index].name + : `${i18n('newW.node.child', intl)} ${index + 1}`} + + + + {expand === index && ( + + + + )} + + ))} +
+ ) + ) + }} +
+ + ) +} + +export default Task diff --git a/ui/app/src/components/NewWorkflow/index.tsx b/ui/app/src/components/NewWorkflow/index.tsx new file mode 100644 index 0000000000..ccedfcc82e --- /dev/null +++ b/ui/app/src/components/NewWorkflow/index.tsx @@ -0,0 +1,319 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import loadable from '@loadable/component' +import CheckIcon from '@mui/icons-material/Check' +import PublishIcon from '@mui/icons-material/Publish' +import RemoveIcon from '@mui/icons-material/Remove' +import UndoIcon from '@mui/icons-material/Undo' +import { + Box, + Button, + Chip, + Grid, + IconButton, + ListItemIcon, + MenuItem, + Step, + StepLabel, + Stepper, + Typography, +} from '@mui/material' +import { makeStyles } from '@mui/styles' +import { Ace } from 'ace-builds' +import { Stale } from 'api/queryUtils' +import { Form, Formik } from 'formik' +import yaml from 'js-yaml' +import _ from 'lodash' +import { useGetCommonChaosAvailableNamespaces, usePostWorkflows } from 'openapi' +import { useEffect, useState } from 'react' +import { useIntl } from 'react-intl' +import { useNavigate } from 'react-router-dom' + +import Menu from '@ui/mui-extends/esm/Menu' +import Paper from '@ui/mui-extends/esm/Paper' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch, useStoreSelector } from 'store' + +import { resetNewExperiment } from 'slices/experiments' +import { setAlert, setConfirm } from 'slices/globalStatus' +import { Template, deleteTemplate, resetWorkflow } from 'slices/workflows' + +import { SelectField, TextField } from 'components/FormField' +import i18n from 'components/T' + +import { validateDeadline, validateName } from 'lib/formikhelpers' +import { constructWorkflow } from 'lib/formikhelpers' + +import Add from './Add' + +const YAMLEditor = loadable(() => import('components/YAMLEditor')) + +const useStyles = makeStyles((theme) => ({ + leftSticky: { + position: 'sticky', + top: 0, + height: `calc(100vh - 56px - ${theme.spacing(9)})`, + }, + field: { + width: 180, + marginTop: 0, + [theme.breakpoints.up('sm')]: { + marginBottom: 0, + }, + '& .MuiInputBase-input': { + padding: 8, + }, + '& .MuiInputLabel-root, fieldset': { + fontSize: theme.typography.body2.fontSize, + lineHeight: 0.875, + }, + }, +})) + +type IStep = Template + +export type WorkflowBasic = { + name: string + namespace: string + deadline: string +} + +const NewWorkflow = () => { + const classes = useStyles() + const intl = useIntl() + const navigate = useNavigate() + + const state = useStoreSelector((state) => state) + const { templates } = state.workflows + const dispatch = useStoreDispatch() + + const [steps, setSteps] = useState([]) + const [restoreIndex, setRestoreIndex] = useState(-1) + const [workflowBasic, setWorkflowBasic] = useState({ + name: '', + namespace: '', + deadline: '', + }) + const [yamlEditor, setYAMLEditor] = useState() + + const { data: namespaces } = useGetCommonChaosAvailableNamespaces({ + query: { + enabled: false, + staleTime: Stale.DAY, + }, + }) + const { mutateAsync } = usePostWorkflows() + + useEffect(() => { + return () => { + dispatch(resetNewExperiment()) + } + }, [dispatch]) + + useEffect(() => { + setSteps(_.isEmpty(templates) ? [] : templates) + }, [templates]) + + const resetRestore = () => { + setRestoreIndex(-1) + } + + const restoreExperiment = (index: number) => () => { + if (restoreIndex !== -1) { + resetRestore() + } else { + setRestoreIndex(index) + } + } + + const removeExperiment = (index: number) => { + dispatch(deleteTemplate(index)) + dispatch( + setAlert({ + type: 'success', + message: i18n('confirm.success.delete', intl) as string, + }) + ) + resetRestore() + } + + const handleSelect = (name: string, index: number, action: string) => () => { + switch (action) { + case 'delete': + dispatch( + setConfirm({ + index, + title: `${i18n('common.delete', intl)} ${name}`, + description: i18n('newW.node.deleteDesc', intl) as string, + handle: handleAction(action, index), + }) + ) + break + } + } + + const handleAction = (action: string, index: number) => () => { + switch (action) { + case 'delete': + removeExperiment(index) + break + } + } + + const updateTemplateCallback = () => { + setRestoreIndex(-1) + dispatch(resetNewExperiment()) + } + + const onValidate = setWorkflowBasic + + const submitWorkflow = () => { + const workflow = yamlEditor?.getValue()! + + if (process.env.NODE_ENV === 'development') { + console.debug('Debug workflow:', workflow) + } + + mutateAsync({ + data: yaml.load(workflow) as any, + }) + .then(() => { + dispatch(resetWorkflow()) + + navigate('/workflows') + }) + .catch(console.error) + } + + return ( + + + + {i18n('common.process')} + + {steps.length > 0 && + steps.map((step, index) => ( + + {restoreIndex !== index ? ( + }> + + + + + + {step.name} + + + + + + + + + + + + {i18n('common.delete')} + + + + + + + ) : ( + + )} + + ))} + {restoreIndex < 0 && ( + + + + )} + + + + + + {({ errors, touched }) => ( +
+ + {i18n('newW.titleBasic')} + + + {namespaces!.map((n) => ( + + {n} + + ))} + + + {i18n('common.preview')} + + + + + + + +
+ )} +
+
+
+ ) +} + +export default NewWorkflow diff --git a/ui/app/src/components/NewWorkflow/types.ts b/ui/app/src/components/NewWorkflow/types.ts new file mode 100644 index 0000000000..8dba83ae58 --- /dev/null +++ b/ui/app/src/components/NewWorkflow/types.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import * as Yup from 'yup' + +export const schemaBasic = Yup.object({ + name: Yup.string().trim().required('The task name is required'), + deadline: Yup.string().trim().required('The deadline is required'), +}) + +export const schema = schemaBasic.shape({ + container: Yup.object({ + name: Yup.string().trim().required('The container name is required'), + image: Yup.string().trim().required('The image is required'), + command: Yup.array().of(Yup.string()), + }), + conditionalBranches: Yup.array() + .of( + Yup.object({ + target: Yup.string().trim().required('The target is required'), + expression: Yup.string().trim().required('The expression is required'), + }) + ) + .min(1) + .required('The conditional branches should be defined'), +}) diff --git a/ui/app/src/components/NewWorkflowNext/AdjustableEdge.tsx b/ui/app/src/components/NewWorkflowNext/AdjustableEdge.tsx new file mode 100644 index 0000000000..3aa3c6f039 --- /dev/null +++ b/ui/app/src/components/NewWorkflowNext/AdjustableEdge.tsx @@ -0,0 +1,65 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { getBezierPath, getEdgeCenter } from 'react-flow-renderer' +import type { EdgeProps } from 'react-flow-renderer' + +import FlowTooltip from './FlowTooltip' + +const foreignObjectSize = 24 + +export default function SuspendEdge({ + id, + sourceX, + sourceY, + targetX, + targetY, + sourcePosition, + targetPosition, + markerEnd, + data, +}: EdgeProps) { + const edgePath = getBezierPath({ + sourceX, + sourceY, + sourcePosition, + targetX, + targetY, + targetPosition, + }) + const [edgeCenterX, edgeCenterY] = getEdgeCenter({ + sourceX, + sourceY, + targetX, + targetY, + }) + + return ( + <> + + + +
+ + + + ) +} diff --git a/ui/app/src/components/NewWorkflowNext/BareNode.test.tsx b/ui/app/src/components/NewWorkflowNext/BareNode.test.tsx new file mode 100644 index 0000000000..535372fb4b --- /dev/null +++ b/ui/app/src/components/NewWorkflowNext/BareNode.test.tsx @@ -0,0 +1,27 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { render } from 'test-utils' + +import BareNode from './BareNode' + +describe('', () => { + it('renders correctly', () => { + const { container } = render() + + expect(container).toMatchSnapshot() + }) +}) diff --git a/ui/app/src/components/NewWorkflowNext/BareNode.tsx b/ui/app/src/components/NewWorkflowNext/BareNode.tsx new file mode 100644 index 0000000000..a4c2c90a87 --- /dev/null +++ b/ui/app/src/components/NewWorkflowNext/BareNode.tsx @@ -0,0 +1,41 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Box, Button } from '@mui/material' +import type { ButtonProps } from '@mui/material' +import { forwardRef } from 'react' + +import { iconByKind } from 'lib/byKind' + +export type BareNodeProps = ButtonProps & { + kind: string +} + +export default forwardRef(({ kind, sx, children, name, ...rest }, ref) => ( + + )} + + + + `1px solid ${theme.palette.divider}` }}> + + Elements + + {recentUse.length > 0 && ( + + Recently Used + + Recently used experiments + + + )} + + Functional Nodes + + Drag or click items below into the board to create a functional node. + + + + + + Chaos Nodes + + Drag or click items below into the board to create a Chaos node. + + + + + Kubernetes + Hosts + + + + + + + + + + + + Pipeline Board + + + + + + + + {workflow && } +
+ + ) +} diff --git a/ui/app/src/components/NewWorkflowNext/utils/convert.test.ts b/ui/app/src/components/NewWorkflowNext/utils/convert.test.ts new file mode 100644 index 0000000000..2421a0245c --- /dev/null +++ b/ui/app/src/components/NewWorkflowNext/utils/convert.test.ts @@ -0,0 +1,233 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import type { Node } from 'react-flow-renderer' +import { v4 as uuidv4 } from 'uuid' + +import { + ExperimentKind, + Template, + connectNodes, + nodeExperimentToTemplate, + templateToNodeExperiment, + templateTypeToFieldName, + workflowToFlow, +} from './convert' + +const nodeExperimentPodChaosSample = { + kind: 'PodChaos', + name: 'p1', + templateType: 'PodChaos', + deadline: '1m', + action: 'pod-failure', + selector: { + namespaces: ['default'], + }, + mode: 'all', +} + +const templatePodChaosSample: any = { + name: 'p1', + templateType: ExperimentKind.PodChaos, + deadline: '1m', + podChaos: { + action: 'pod-failure', + selector: { + namespaces: ['default'], + }, + mode: 'all', + }, +} + +const nodeExperimentScheduleSample = { + kind: 'PodChaos', + name: 's1', + templateType: 'PodChaos', + deadline: '1m', + scheduled: true, + schedule: '@every 2h', + historyLimit: 2, + concurrencyPolicy: 'Forbid', + action: 'pod-failure', + selector: { + namespaces: ['default'], + }, + mode: 'all', +} + +const templateScheduleSample: Template = { + name: 's1', + templateType: 'Schedule', + deadline: '1m', + schedule: { + schedule: '@every 2h', + historyLimit: 2, + concurrencyPolicy: 'Forbid', + type: 'PodChaos', + podChaos: { + action: 'pod-failure', + selector: { + namespaces: ['default'], + }, + mode: 'all', + }, + }, +} + +const workflowSample1 = ` +apiVersion: chaos-mesh.org/v1alpha1 +kind: Workflow +metadata: + name: try-workflow-parallel +spec: + entry: the-entry + templates: + - name: the-entry + templateType: Parallel + deadline: 240s + children: + - workflow-stress-chaos + - workflow-network-chaos + - workflow-pod-chaos-schedule + - name: workflow-network-chaos + templateType: NetworkChaos + deadline: 20s + networkChaos: + direction: to + action: delay + mode: all + selector: + labelSelectors: + 'app': 'hello-kubernetes' + delay: + latency: '90ms' + correlation: '25' + jitter: '90ms' + - name: workflow-pod-chaos-schedule + templateType: Schedule + deadline: 40s + schedule: + schedule: '@every 2s' + type: 'PodChaos' + podChaos: + action: pod-kill + mode: one + selector: + labelSelectors: + 'app': 'hello-kubernetes' + - name: workflow-stress-chaos + templateType: StressChaos + deadline: 20s + stressChaos: + mode: one + selector: + labelSelectors: + 'app': 'hello-kubernetes' + stressors: + cpu: + workers: 1 + load: 20 + options: ['--cpu 1', '--timeout 600'] +` + +describe('components/NewWorkflowNext/utils/convert', () => { + describe('templateTypeToFieldName', () => { + it('should return the correct field names', () => { + expect(templateTypeToFieldName(ExperimentKind.AWSChaos)).toBe('awsChaos') + expect(templateTypeToFieldName(ExperimentKind.HTTPChaos)).toBe('httpChaos') + expect(templateTypeToFieldName(ExperimentKind.PhysicalMachineChaos)).toBe('physicalmachineChaos') + }) + }) + + describe('nodeExperimentToTemplate', () => { + it('should return the correct PodChaos template', () => { + expect(nodeExperimentToTemplate(nodeExperimentPodChaosSample)).toEqual(templatePodChaosSample) + }) + + it('should return the correct Schedule template', () => { + expect(nodeExperimentToTemplate(nodeExperimentScheduleSample)).toEqual(templateScheduleSample) + }) + + it('should return the correct Suspend template', () => { + const data = { + name: 's2', + templateType: 'Suspend', + deadline: '1m', + } + + expect(nodeExperimentToTemplate(data)).toEqual({ + name: 's2', + templateType: 'Suspend', + deadline: '1m', + }) + }) + }) + + describe('templateToNodeExperiment', () => { + it('should return the correct PodChaos NodeExperiment', () => { + const { id, ...rest } = templateToNodeExperiment(templatePodChaosSample) + + expect(rest).toEqual(nodeExperimentPodChaosSample) + }) + + it('should return the correct Schedule NodeExperiment', () => { + const { id, ...rest } = templateToNodeExperiment(templateScheduleSample, true) + + expect(rest).toEqual({ + ...nodeExperimentScheduleSample, + startingDeadlineSeconds: 0, + }) + }) + }) + + describe('connectNodes', () => { + const nodes: Node[] = [ + { + id: uuidv4(), + position: { x: 0, y: 0 }, + data: {}, + }, + { + id: uuidv4(), + position: { x: 0, y: 0 }, + data: {}, + }, + { + id: uuidv4(), + position: { x: 0, y: 0 }, + data: {}, + }, + ] + it('should return the correct connections', () => { + const result = connectNodes(nodes) + + expect(result.length).toBe(2) + expect(result[0].source).toBe(nodes[0].id) + expect(result[0].target).toBe(nodes[1].id) + expect(result[1].source).toBe(nodes[1].id) + expect(result[1].target).toBe(nodes[2].id) + }) + }) + + describe('workflowToFlow', () => { + it('test workflow sample 1', () => { + const { nodes, edges } = workflowToFlow(workflowSample1) + + expect(nodes.length).toBe(4) + expect(edges.length).toBe(0) + }) + }) +}) diff --git a/ui/app/src/components/NewWorkflowNext/utils/convert.ts b/ui/app/src/components/NewWorkflowNext/utils/convert.ts new file mode 100644 index 0000000000..db99577145 --- /dev/null +++ b/ui/app/src/components/NewWorkflowNext/utils/convert.ts @@ -0,0 +1,468 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import yaml from 'js-yaml' +import _ from 'lodash' +import { Edge, Node, XYPosition, getIncomers } from 'react-flow-renderer' +import { v4 as uuidv4 } from 'uuid' + +import type { NodeExperiment } from 'slices/workflows' + +import { Schedule, scheduleInitialValues } from 'components/AutoForm/data' + +import { arrToObjBySep, isDeepEmpty, objToArrBySep } from 'lib/utils' + +export enum ExperimentKind { + AWSChaos = 'AWSChaos', + AzureChaos = 'AzureChaos', + BlockChaos = 'BlockChaos', + DNSChaos = 'DNSChaos', + GCPChaos = 'GCPChaos', + HTTPChaos = 'HTTPChaos', + IOChaos = 'IOChaos', + JVMChaos = 'JVMChaos', + KernelChaos = 'KernelChaos', + NetworkChaos = 'NetworkChaos', + PodChaos = 'PodChaos', + StressChaos = 'StressChaos', + TimeChaos = 'TimeChaos', + PhysicalMachineChaos = 'PhysicalMachineChaos', +} + +const mapping = new Map([ + [ExperimentKind.AWSChaos, 'awsChaos'], + [ExperimentKind.AzureChaos, 'azureChaos'], + [ExperimentKind.BlockChaos, 'blockChaos'], + [ExperimentKind.DNSChaos, 'dnsChaos'], + [ExperimentKind.GCPChaos, 'gcpChaos'], + [ExperimentKind.HTTPChaos, 'httpChaos'], + [ExperimentKind.IOChaos, 'ioChaos'], + [ExperimentKind.JVMChaos, 'jvmChaos'], + [ExperimentKind.KernelChaos, 'kernelChaos'], + [ExperimentKind.NetworkChaos, 'networkChaos'], + [ExperimentKind.PodChaos, 'podChaos'], + [ExperimentKind.StressChaos, 'stressChaos'], + [ExperimentKind.TimeChaos, 'timeChaos'], + [ExperimentKind.PhysicalMachineChaos, 'physicalmachineChaos'], +]) + +export function templateTypeToFieldName(templateType: ExperimentKind) { + return mapping.get(templateType) +} + +export enum SpecialTemplateType { + Serial = 'Serial', + Parallel = 'Parallel', + Suspend = 'Suspend', +} + +export interface Template { + id?: uuid + level?: number + name: string + templateType: SpecialTemplateType | ExperimentKind | 'Schedule' + deadline?: string + schedule?: { type: string; [key: string]: any } & Schedule + children?: string[] +} + +export function nodeExperimentToTemplate(node: NodeExperiment): Template { + const { id, kind, name, templateType, deadline, scheduled, ...rest } = JSON.parse(JSON.stringify(node)) + + if (scheduled) { + const { schedule, historyLimit, concurrencyPolicy, startingDeadlineSeconds, ...restrest } = rest + + return { + name, + templateType: 'Schedule', + deadline, + schedule: { + schedule, + historyLimit, + concurrencyPolicy, + startingDeadlineSeconds, + type: templateType, + [templateTypeToFieldName(templateType)!]: restrest, + }, + } + } + + const fieldName = templateTypeToFieldName(templateType) + + return { + name, + templateType, + deadline, + ...(fieldName && { [fieldName]: rest }), + } +} + +export function flowToWorkflow(nodes: Node[], edges: Edge[], storeTemplates: Record) { + const origin = nodes + .filter((n) => !n.parentNode) + .map((n) => ({ ...n, incomers: getIncomers(n, nodes, edges) })) + .find((n) => n.incomers.length === 0)! + const nodeMap = _.keyBy(nodes, 'id') + const sourceMap = _.keyBy(edges, 'source') + + function genTemplates(origin: Node, level: number): Template[] { + const originalTemplate = storeTemplates[origin.data.name] + let currentTemplate: Template + let restTemplates: Template[] = [] + + if ( + originalTemplate.templateType === SpecialTemplateType.Serial || + originalTemplate.templateType === SpecialTemplateType.Parallel + ) { + const children = nodes + .filter((n) => n.parentNode === origin.id) + .map((n) => ({ id: n.id, ...storeTemplates[n.data.name] })) + + currentTemplate = { + level, + name: originalTemplate.name, + templateType: originalTemplate.templateType, + children: children.map((n) => n.name), + } + + restTemplates = children.flatMap((n) => genTemplates(nodeMap[n.id], level + 1)) + } else { + currentTemplate = { level, ...nodeExperimentToTemplate(originalTemplate) } + } + + const edge = sourceMap[origin.id] + let nextNode + if (edge) { + nextNode = nodeMap[edge.target] + } + + return [ + currentTemplate, + ...restTemplates, + ...(nextNode && !nextNode.parentNode ? genTemplates(nextNode, level) : []), + ] + } + + let templates = _.uniqBy(genTemplates(origin, 0), 'name') + const templatesWithLevel0 = templates.filter((t) => t.level === 0) + const hasEntry = + templatesWithLevel0.length === 1 && + (templatesWithLevel0[0].templateType === SpecialTemplateType.Serial || + templatesWithLevel0[0].templateType === SpecialTemplateType.Parallel) + templates = [ + ...(!hasEntry + ? [ + { + name: 'entry', + templateType: SpecialTemplateType.Serial, + children: templatesWithLevel0.map((t) => t.name), + }, + ] + : []), + ...templates.map((t) => _.omit(t, 'level')), + ] + + return yaml.dump( + { + apiVersion: 'chaos-mesh.org/v1alpha1', + kind: 'Workflow', + metadata: {}, + spec: { + entry: hasEntry ? templatesWithLevel0[0].name : 'entry', + templates, + }, + }, + { + replacer: (key, value) => { + if (isDeepEmpty(value)) { + return undefined + } + + // field === 'text-text'/'text-label' + if (_.has(value, 'key0')) { + if (_.isString(value['key0'].value)) { + return _.values(value).reduce((acc, { key, value: val }) => { + acc[key] = val + + return acc + }, {}) + } else { + return _.values(value).map(({ key, value: val }) => _.zip(_.times(val.length, _.constant(key)), val)) + } + } + + // Parse labels, annotations, labelSelectors, and annotationSelectors to object. + if (['labels', 'annotations', 'labelSelectors', 'annotationSelectors'].includes(key)) { + return arrToObjBySep(value, ': ') + } + + return value + }, + } + ) +} + +export function templateToNodeExperiment(t: Template, scheduled?: boolean): NodeExperiment { + let result + + if (scheduled) { + const { type, schedule, historyLimit, concurrencyPolicy, startingDeadlineSeconds, ...rest } = t['schedule']! + const fieldName = templateTypeToFieldName(type as ExperimentKind)! + const chaos = rest[fieldName] + + result = { + kind: type, + name: t.name, + templateType: type, + deadline: t.deadline, + scheduled: true, + ..._.defaults( + { + schedule, + historyLimit, + concurrencyPolicy, + startingDeadlineSeconds, + }, + scheduleInitialValues + ), + ...chaos, + } + } else { + const fieldName = templateTypeToFieldName(t.templateType as ExperimentKind) + + result = { + kind: t.templateType, + name: t.name, + templateType: t.templateType, + deadline: t.deadline, + ...(fieldName && (t as any)[fieldName]), + } + } + + // Parse labelSelectors, and annotationSelectors to array. + if (_.has(result, 'selector.labelSelectors')) { + _.update(result, 'selector.labelSelectors', (obj) => objToArrBySep(obj, ': ')) + } + if (_.has(result, 'selector.annotationSelectors')) { + _.update(result, 'selector.annotationSelectors', (obj) => objToArrBySep(obj, ': ')) + } + + return result +} + +export function connectNodes(nodes: Node[]) { + const edges: Edge[] = [] + + for (let i = 1; i < nodes.length; i++) { + const prev = nodes[i - 1] + const cur = nodes[i] + + const id = uuidv4() + + edges.push({ + id, + type: 'adjustableEdge', + source: prev.id, + target: cur.id, + data: { + id, + }, + }) + } + + return edges +} + +type ParentNode = { + id: uuid + type: SpecialTemplateType.Serial | SpecialTemplateType.Parallel +} +export enum View { + NodeWidth = 200, + NodeHeight = 30, + PaddingX = 30, + PaddingY = 15, + GroupNodeTypographyHeight = 32, +} + +export function workflowToFlow(workflow: string) { + const { entry, templates }: { entry: string; templates: Template[] } = (yaml.load(workflow) as any).spec + const templatesMap = _.keyBy(templates, 'name') + // Convert templates to store. + // + // The `name` is used here as the unique id, + // because the name of a template inside a Workflow is unique. + const store = _.transform>(templatesMap, (acc, t, k) => { + if (t.templateType === 'Schedule') { + acc[k] = templateToNodeExperiment(t, true) + } else { + acc[k] = templateToNodeExperiment(t) + } + }) + const nodes: Record = {} + const edges: Edge[] = [] + + function recurInsertNodesAndEdges( + entry: Template, + relativePos: XYPosition, + level: number, + index: number, + parentNode?: ParentNode + ): { id: uuid; width: number; height: number } { + function addNode(id: uuid, parentNode?: ParentNode): Node { + return { + id, + type: 'flowNode', + position: { + x: + parentNode?.type === SpecialTemplateType.Serial + ? relativePos.x + View.PaddingX * (index + 1) + : View.PaddingX, + y: + View.GroupNodeTypographyHeight + + (parentNode?.type === SpecialTemplateType.Parallel + ? relativePos.y + View.PaddingY * (index + 1) + : View.PaddingY), + }, + data: { + name: entry.name, + kind: entry.templateType, + children: _.truncate(entry.name, { length: 20 }), + }, + ...(parentNode && { + parentNode: parentNode.id, + extent: 'parent', + }), + } + } + + const id = uuidv4() + let width = 0 + let height = 0 + + if (entry.templateType === SpecialTemplateType.Serial || entry.templateType === SpecialTemplateType.Parallel) { + const childrenNum = entry.children!.length + + nodes[id] = { + id, + type: 'groupNode', + position: { + x: + parentNode?.type === SpecialTemplateType.Serial + ? relativePos.x + View.PaddingX * (index + 1) + : parentNode?.type === SpecialTemplateType.Parallel + ? View.PaddingX + : relativePos.x, + y: + View.GroupNodeTypographyHeight + + (parentNode?.type === SpecialTemplateType.Parallel + ? relativePos.y + View.PaddingY * (index + 1) + : parentNode?.type === SpecialTemplateType.Serial + ? View.PaddingY + : relativePos.y - View.GroupNodeTypographyHeight), + }, + data: { + name: entry.name, + type: entry.templateType, + childrenNum, + }, + ...(parentNode && { + parentNode: parentNode.id, + extent: 'parent', + connectable: parentNode.type === SpecialTemplateType.Serial, + }), + zIndex: -1, // Make edges visible on the top of the group node. + } + + const children = entry.children!.map((child) => templatesMap[child]) + + let prevWidth = 0 + let prevHeight = 0 + const uuids = children.map((child, i) => { + const { + id: uuid, + width: w, + height: h, + } = recurInsertNodesAndEdges( + child, + { + x: prevWidth, + y: prevHeight, + }, + level + 1, + i, + { + id, + type: entry.templateType as any, + } + ) + + if (entry.templateType === SpecialTemplateType.Serial) { + width += w + height = Math.max(height, h) + + prevWidth += w + } + + if (entry.templateType === SpecialTemplateType.Parallel) { + width = Math.max(width, w) + height += h + + prevHeight += h + } + + if (nodes[uuid].type === 'groupNode') { + prevHeight += View.GroupNodeTypographyHeight + } + + return uuid + }) + + // If Serial, connect all child nodes. + if (entry.templateType === SpecialTemplateType.Serial) { + edges.push(...connectNodes(uuids.map((uuid) => nodes[uuid]))) + } + + // Calculate the padding of the group node. + width += entry.templateType === SpecialTemplateType.Serial ? View.PaddingX * (childrenNum + 1) : View.PaddingX * 2 + height += + entry.templateType === SpecialTemplateType.Parallel ? View.PaddingY * (childrenNum + 1) : View.PaddingY * 2 + + // Calculate the height of all headers. + const specialUUIDs = _.sumBy(uuids, (uuid) => (nodes[uuid].type === 'groupNode' ? 1 : 0)) + if (specialUUIDs > 0) { + height += + entry.templateType === SpecialTemplateType.Serial + ? View.GroupNodeTypographyHeight + : View.GroupNodeTypographyHeight * specialUUIDs + } + + nodes[id].data.width = width + nodes[id].data.height = height + } else { + nodes[id] = addNode(id, parentNode) + + width = View.NodeWidth + height = View.NodeHeight + } + + return { id, width, height } + } + + recurInsertNodesAndEdges(templatesMap[entry], { x: 100, y: 100 }, 0, 0) + + return { store, nodes: _.values(nodes), edges } +} diff --git a/ui/app/src/components/NotFound/index.tsx b/ui/app/src/components/NotFound/index.tsx new file mode 100644 index 0000000000..ab9d200c1d --- /dev/null +++ b/ui/app/src/components/NotFound/index.tsx @@ -0,0 +1,46 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Box, useTheme } from '@mui/material' +import type { BoxProps } from '@mui/material' + +import EmptyStreetDark from 'images/assets/undraw_empty_street-dark.svg' +import undrawNotFound from 'images/assets/undraw_not_found.svg' + +interface NotFoundProps extends BoxProps { + illustrated?: boolean +} + +const NotFound: React.FC = ({ illustrated = false, children, ...rest }) => { + const theme = useTheme() + + return ( + + {illustrated && ( + + Not found + + )} + {children} + + ) +} + +export default NotFound diff --git a/ui/app/src/components/ObjectConfiguration/Node.tsx b/ui/app/src/components/ObjectConfiguration/Node.tsx new file mode 100644 index 0000000000..5388a0fc1f --- /dev/null +++ b/ui/app/src/components/ObjectConfiguration/Node.tsx @@ -0,0 +1,164 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Box, Table, TableBody, TableRow, Typography } from '@mui/material' + +import { Branch } from 'slices/workflows' +import ObjectConfiguration from '.' +import { TableCell } from './common' +import i18n from 'components/T' + +interface NodeConfigurationProps { + template: any +} + +const Suspend = ({ template: t }: NodeConfigurationProps) => ( + + + + {i18n('common.name')} + + + {t.name} + + + + + {i18n('newE.target.kind')} + + + {t.templateType} + + + + + {i18n('newW.node.deadline')} + + + {t.deadline} + + + + +
+) + +const Custom = ({ template: t }: NodeConfigurationProps) => { + const { container } = t.task + + return ( + <> + + {i18n('newE.steps.basic')} + + + + + {i18n('common.name')} + + + {t.name} + + + + +
+ + {i18n('newW.node.container.title')} + + + + {i18n('common.name')} + + + {container.name} + + + + + {i18n('newW.node.container.image')} + + + {container.image} + + + + {container.command && ( + + {i18n('newW.node.container.command')} + + {container.command.map((d: string, i: number) => ( + + - {d} + + ))} + + + )} +
+ + {i18n('newW.node.conditionalBranches.title')} + + {t.conditionalBranches && + t.conditionalBranches.map((d: Branch, i: number) => ( + + + {i18n('newW.node.conditionalBranches.branch')} {i + 1} + + + + {i18n('newW.node.conditionalBranches.target')} + + + {d.target} + + + + + {i18n('newW.node.conditionalBranches.expression')} + + + {d.expression} + + + +
+
+ ))} + + ) +} + +const NodeConfiguration: React.FC = ({ template: t }) => { + const rendered = () => { + switch (t.templateType) { + case 'Suspend': + return + case 'Task': + return + default: + return ( + + + + ) + } + } + + return rendered() +} + +export default NodeConfiguration diff --git a/ui/app/src/components/ObjectConfiguration/common.tsx b/ui/app/src/components/ObjectConfiguration/common.tsx new file mode 100644 index 0000000000..888a2ad397 --- /dev/null +++ b/ui/app/src/components/ObjectConfiguration/common.tsx @@ -0,0 +1,336 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { + ListItemProps, + ListProps, + List as MUIList, + ListItem as MUIListItem, + TableCell as MUITableCell, + Table, + TableBody, + TableCellProps, + TableRow, + Typography, +} from '@mui/material' + +import { ExperimentKind } from 'components/NewExperiment/types' +import i18n from 'components/T' +import { objToArrBySep } from 'lib/utils' + +export const TableCell = (props: TableCellProps) => ( + +) +export const List = (props: ListProps) => +export const ListItem = (props: ListItemProps) => + +export const Selector = ({ data }: any) => ( + + + {data.namespaces && ( + + {i18n('k8s.namespaceSelectors')} + + + {data.namespaces.join('; ')} + + + + )} + {data.labelSelectors && ( + + {i18n('k8s.labelSelectors')} + + + {objToArrBySep(data.labelSelectors, ': ').join('; ')} + + + + )} + {data.annotationSelectors && ( + + {i18n('k8s.annotationSelectors')} + + + {objToArrBySep(data.annotationSelectors, ': ').join('; ')} + + + + )} + +
+) + +const Pod = ({ data: { containerName } }: any) => ( + <> + {containerName && ( + + Container name + + + {containerName} + + + + )} + +) + +const Network = ({ data }: any) => ( + <> + {data.direction && ( + + Direction + + + {data.direction} + + + + )} + +) + +const IO = ({ data }: any) => ( + <> + {data.delay && ( + + Delay + + + {data.delay} + + + + )} + {data.errno && ( + + Errno + + + {data.errno} + + + + )} + {data.attr && ( + + Attr + + + {objToArrBySep(data.attr, ': ').map((d) => ( + + + {d} + + + ))} + + + + )} + {data.volumePath && ( + + Volume path + + + {data.volumePath} + + + + )} + {data.path && ( + + Path + + + {data.path} + + + + )} + {data.containerName && ( + + Container name + + + {data.containerName} + + + + )} + {data.percent && ( + + Percent + + + {data.percent} + + + + )} + {data.methods && ( + + Methods + + + {objToArrBySep(data.methods, ': ').map((d) => ( + + + {d} + + + ))} + + + + )} + +) + +export const Stress = ({ data: { stressors, stressngStressors, containerName } }: any) => ( + <> + {stressors.cpu && stressors.cpu.workers > 0 && ( + + CPU + + + workers: {stressors.cpu.workers} + + + size: {stressors.cpu.size} + + + + )} + {stressors.memory && stressors.memory.workers > 0 && ( + + Memory + + + workers: {stressors.memory.workers} + + + size: {stressors.memory.size} + + + + )} + {stressngStressors && ( + + Options of stress-ng + + + {objToArrBySep(stressngStressors, ': ').map((d) => ( + + + {d} + + + ))} + + + + )} + {containerName && ( + + Container name + + + {containerName} + + + + )} + +) + +const Time = ({ data }: any) => ( + <> + {data.timeOffset && ( + + Time offset + + + {data.timeOffset} + + + + )} + {data.clockIds && ( + + Clock ids + + + {objToArrBySep(data.clockIds, ': ').map((d) => ( + + + {d} + + + ))} + + + + )} + {data.containerNames && ( + + Container names + + + {objToArrBySep(data.containerNames, ': ').map((d) => ( + + + {d} + + + ))} + + + + )} + +) + +export const Experiment = ({ kind, data }: { kind: ExperimentKind; data: any }) => ( + + + + {i18n('newE.target.kind')} + + + {kind} + + + + {['PodChaos', 'NetworkChaos', 'IOChaos'].includes(kind) && ( + + {i18n('newE.target.action')} + + + {data.action} + + + + )} + {kind === 'PodChaos' && } + {kind === 'NetworkChaos' && } + {kind === 'IOChaos' && } + {kind === 'StressChaos' && } + {kind === 'TimeChaos' && +
+) diff --git a/ui/app/src/components/ObjectConfiguration/index.tsx b/ui/app/src/components/ObjectConfiguration/index.tsx new file mode 100644 index 0000000000..fc20fb9573 --- /dev/null +++ b/ui/app/src/components/ObjectConfiguration/index.tsx @@ -0,0 +1,216 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Grid, Table, TableBody, TableRow, Typography } from '@mui/material' +import { templateTypeToFieldName } from 'api/zz_generated.frontend.chaos-mesh' +import { TypesArchiveDetail, TypesExperimentDetail } from 'openapi/index.schemas' + +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreSelector } from 'store' + +import StatusLabel from 'components/StatusLabel' +import i18n from 'components/T' + +import { format } from 'lib/luxon' + +import { Experiment, Selector, TableCell } from './common' + +type Config = TypesExperimentDetail | TypesArchiveDetail + +interface ObjectConfigurationProps { + config: Config + inNode?: boolean + inSchedule?: boolean + inArchive?: boolean + vertical?: boolean +} + +const ObjectConfiguration: React.FC = ({ + config, + inNode, + inSchedule, + inArchive, + vertical, +}) => { + const { lang } = useStoreSelector((state) => state.settings) + + const spec: any = inNode ? config : config!.kube_object!.spec + const experiment = + inSchedule || inNode ? spec[templateTypeToFieldName(inSchedule ? spec.type : (config as any).templateType)] : spec + + return ( + <> + {!inNode && ( + + {config.name} + + {!inArchive && } + + )} + + + {!inNode && ( + + + {i18n('newE.steps.basic')} + + + + + + {i18n('k8s.namespace')} + + + {config.namespace} + + + + + + {i18n('common.uuid')} + + + {config.uid} + + + + + + {i18n('table.created')} + + + {format(config.created_at!, lang)} + + + + +
+
+ )} + + + + {i18n('newE.steps.scope')} + + + {(inNode + ? (config as any).templateType !== 'PhysicalMachineChaos' + : inSchedule + ? spec.type !== 'PhysicalMachineChaos' + : (config.kind as any) !== 'PhysicalMachineChaos') && } + + {(inNode + ? (config as any).templateType === 'PhysicalMachineChaos' + : inSchedule + ? spec.type === 'PhysicalMachineChaos' + : (config.kind as any) === 'PhysicalMachineChaos') && ( + + + {i18n('physic.address')} + + + {inNode + ? (config as any).physicalmachineChaos.address + : inSchedule + ? spec.physicalmachineChaos.address + : spec.address} + + + +
+ )} +
+ + + + {i18n('experiments.single')} + + + + + + + + {i18n('newE.steps.run')} + + + + + {!inSchedule && ( + + {i18n(inNode ? 'newW.node.deadline' : 'common.duration')} + + + {inNode ? (config as any).deadline : spec.duration ? spec.duration : i18n('newE.run.continuous')} + + + + )} + {inSchedule && ( + <> + + {i18n('schedules.single')} + + + {spec.schedule} + + + + {spec.historyLimit && ( + + {i18n('newS.basic.historyLimit')} + + + {spec.historyLimit} + + + + )} + {spec.concurrencyPolicy && ( + + {i18n('newS.basic.concurrencyPolicy')} + + + {spec.concurrencyPolicy} + + + + )} + {spec.startingDeadlineSeconds && ( + + {i18n('newS.basic.startingDeadlineSeconds')} + + + {spec.startingDeadlineSeconds} + + + + )} + + )} + +
+
+
+ + ) +} + +export default ObjectConfiguration diff --git a/ui/app/src/components/ObjectListItem/index.tsx b/ui/app/src/components/ObjectListItem/index.tsx new file mode 100644 index 0000000000..9116a4ae9b --- /dev/null +++ b/ui/app/src/components/ObjectListItem/index.tsx @@ -0,0 +1,174 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import ArchiveOutlinedIcon from '@mui/icons-material/ArchiveOutlined' +import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined' +import PauseCircleOutlineIcon from '@mui/icons-material/PauseCircleOutline' +import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline' +import { Box, IconButton, Typography } from '@mui/material' +import _ from 'lodash' +import { TypesArchive, TypesExperiment, TypesSchedule } from 'openapi/index.schemas' +import { useIntl } from 'react-intl' +import { useNavigate } from 'react-router-dom' + +import Paper from '@ui/mui-extends/esm/Paper' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreSelector } from 'store' + +import StatusLabel from 'components/StatusLabel' +import i18n from 'components/T' + +import DateTime, { format } from 'lib/luxon' + +interface ObjectListItemProps { + type?: 'schedule' | 'experiment' | 'archive' + archive?: 'workflow' | 'schedule' | 'experiment' + data: TypesSchedule | TypesExperiment | TypesArchive + onSelect: (info: { uuid: uuid; title: string; description: string; action: string }) => void +} + +const ObjectListItem: React.FC = ({ data, type = 'experiment', archive, onSelect }) => { + const navigate = useNavigate() + const intl = useIntl() + + const { lang } = useStoreSelector((state) => state.settings) + + const handleAction = (action: string) => (event: React.MouseEvent) => { + event.stopPropagation() + + switch (action) { + case 'archive': + onSelect({ + title: `${i18n('archives.single', intl)} ${data.name}`, + description: i18n(`${type}s.deleteDesc`, intl), + action, + uuid: data.uid!, + }) + + return + case 'pause': + onSelect({ + title: `${i18n('common.pause', intl)} ${data.name}`, + description: i18n('experiments.pauseDesc', intl), + action, + uuid: data.uid!, + }) + + return + case 'start': + onSelect({ + title: `${i18n('common.start', intl)} ${data.name}`, + description: i18n('experiments.startDesc', intl), + action, + uuid: data.uid!, + }) + + return + case 'delete': + onSelect({ + title: `${i18n('common.delete', intl)} ${data.name}`, + description: i18n('archives.deleteDesc', intl), + action, + uuid: data.uid!, + }) + + return + default: + return + } + } + + const handleJumpTo = () => { + let path + switch (type) { + case 'schedule': + case 'experiment': + path = `/${type}s/${data.uid}` + break + case 'archive': + path = `/archives/${data.uid}?kind=${archive!}` + break + } + + navigate(path) + } + + const Actions = () => ( + + + {i18n('table.created')}{' '} + {DateTime.fromISO(data.created_at!, { + locale: lang, + }).toRelative()} + + {(type === 'schedule' || type === 'experiment') && + ((data as any).status === 'paused' ? ( + + + + ) : (data as any).status !== 'finished' ? ( + + + + ) : null)} + {type !== 'archive' && ( + + + + )} + {type === 'archive' && ( + + + + )} + + ) + + return ( + + + + {type !== 'archive' && } + + {_.truncate(data.name!)} + + + {_.truncate(data.uid!)} + + + + + + + ) +} + +export default ObjectListItem diff --git a/ui/app/src/components/RBACGenerator/index.tsx b/ui/app/src/components/RBACGenerator/index.tsx new file mode 100644 index 0000000000..31bc241b72 --- /dev/null +++ b/ui/app/src/components/RBACGenerator/index.tsx @@ -0,0 +1,180 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Box, Button, Checkbox, FormControl, FormControlLabel, MenuItem, Typography } from '@mui/material' +import { makeStyles } from '@mui/styles' +import copy from 'copy-text-to-clipboard' +import { Field, Form, Formik } from 'formik' +import _ from 'lodash' +import { useGetCommonChaosAvailableNamespaces, useGetCommonRbacConfig } from 'openapi' +import { useRef, useState } from 'react' +import { useIntl } from 'react-intl' + +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch } from 'store' + +import { setAlert } from 'slices/globalStatus' + +import { SelectField } from 'components/FormField' +import i18n from 'components/T' +import { Stale } from 'api/queryUtils' + +const useStyles = makeStyles((theme) => ({ + pre: { + padding: theme.spacing(3), + background: theme.palette.background.default, + borderRadius: 4, + whiteSpace: 'pre-wrap', + }, + copy: { + position: 'absolute', + top: theme.spacing(6), + right: theme.spacing(3), + }, +})) + +const initialValues = { namespace: 'default', role: 'viewer', clustered: false } + +const RBACGenerator = () => { + const classes = useStyles() + + const intl = useIntl() + + const dispatch = useStoreDispatch() + + const [params, setParams] = useState(initialValues) + const [rbac, setRBAC] = useState('') + const [getSecret, setGetSecret] = useState('') + const [generateToken, setGenerateToken] = useState('') + const containerRef = useRef(null) + + const { data: namespaces } = useGetCommonChaosAvailableNamespaces({ + query: { + enabled: false, + staleTime: Stale.DAY, + }, + }) + useGetCommonRbacConfig(params, { + query: { + onSuccess(data) { + const entries = Object.entries(data) + const [name, yaml] = entries[0] + + setRBAC(yaml) + setGetSecret(`kubectl describe${name.includes('cluster') ? '' : ` -n ${params.namespace}`} secrets ${name}`) + setGenerateToken(`kubectl create token ${name}`) + }, + }, + }) + + const onValidate = ({ namespace, role, clustered }: typeof params) => { + setParams({ + namespace: clustered ? '' : namespace, + role, + clustered, + }) + } + + const copyRBAC = () => { + copy(rbac, { target: containerRef.current! }) + + dispatch( + setAlert({ + type: 'success', + message: i18n('common.copied', intl), + }) + ) + } + + return ( +
+ + + {i18n('settings.addToken.generatorHelper')} + + {}} validate={onValidate} validateOnBlur={false}> + {({ values: { clustered } }) => ( +
+ + + } + label={{i18n('settings.addToken.clustered')}} + /> + + + {namespaces!.map((n) => ( + + {n} + + ))} + + + {['manager', 'viewer'].map((role) => ( + + {_.upperFirst(role)} + + ))} + + +
+ )} +
+ + {i18n('settings.addToken.generatorHelper2')} + + +
+            {rbac}
+          
+ + + +
+ + {i18n('settings.addToken.generatorHelper3')} + +
kubectl apply -f rbac.yaml
+ + + {i18n('settings.addToken.generatorHelperGetTokenHeader')} + + + + {i18n('settings.addToken.generatorHelperGetTokenCase1')} + +
{generateToken}
+ + {i18n('settings.addToken.generatorHelperGetTokenCase2')} + +
{getSecret}
+
+
+
+ ) +} + +export default RBACGenerator diff --git a/ui/app/src/components/Schedule/types.tsx b/ui/app/src/components/Schedule/types.tsx new file mode 100644 index 0000000000..b32a125f3b --- /dev/null +++ b/ui/app/src/components/Schedule/types.tsx @@ -0,0 +1,99 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { InputAdornment, MenuItem } from '@mui/material' +import { FormikProps, FormikValues, getIn } from 'formik' +import { number, string } from 'yup' + +import { SelectField, TextField } from 'components/FormField' +import { T } from 'components/T' + +export interface ScheduleSpecific { + schedule: string + historyLimit?: number + concurrencyPolicy?: 'Forbid' | 'Allow' + startingDeadlineSeconds?: number +} + +export const data: ScheduleSpecific = { + schedule: '', + historyLimit: 1, + concurrencyPolicy: 'Forbid', + startingDeadlineSeconds: undefined, +} + +export const Fields = ({ errors, touched }: Pick, 'errors' | 'touched'>) => ( + <> + } + helperText={ + getIn(errors, 'spec.historyLimit') && getIn(touched, 'spec.historyLimit') ? ( + getIn(errors, 'spec.historyLimit') + ) : ( + + ) + } + error={getIn(errors, 'spec.historyLimit') && getIn(touched, 'spec.historyLimit')} + /> + } + helperText={ + getIn(errors, 'spec.concurrencyPolicy') && getIn(touched, 'spec.concurrencyPolicy') ? ( + getIn(errors, 'spec.concurrencyPolicy') + ) : ( + + ) + } + error={getIn(errors, 'spec.concurrencyPolicy') && getIn(touched, 'spec.concurrencyPolicy')} + > + + + + + + + + } + endAdornment={ + + + + } + helperText={ + getIn(errors, 'spec.startingDeadlineSeconds') && getIn(touched, 'spec.startingDeadlineSeconds') ? ( + getIn(errors, 'spec.startingDeadlineSeconds') + ) : ( + + ) + } + error={getIn(errors, 'spec.startingDeadlineSeconds') && getIn(touched, 'spec.startingDeadlineSeconds')} + /> + +) + +export const schema = { + historyLimit: number().min(1, 'The historyLimit is at least 1'), + concurrencyPolicy: string().required('The concurrencyPolicy is required'), + startingDeadlineSeconds: number().min(0, 'The startingDeadlineSeconds is at least 0').nullable(true), +} diff --git a/ui/app/src/components/Scope/DeprecatedAddress.tsx b/ui/app/src/components/Scope/DeprecatedAddress.tsx new file mode 100644 index 0000000000..3d77490cd1 --- /dev/null +++ b/ui/app/src/components/Scope/DeprecatedAddress.tsx @@ -0,0 +1,39 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { getIn, useFormikContext } from 'formik' + +import { LabelField } from 'components/FormField' +import i18n from 'components/T' + +const DeprecatedAddress = () => { + const { errors, touched } = useFormikContext() + + return ( + + ) +} + +export default DeprecatedAddress diff --git a/ui/app/src/components/Scope/Mode.tsx b/ui/app/src/components/Scope/Mode.tsx new file mode 100644 index 0000000000..962a21dc25 --- /dev/null +++ b/ui/app/src/components/Scope/Mode.tsx @@ -0,0 +1,68 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { InputAdornment, MenuItem } from '@mui/material' +import { getIn, useFormikContext } from 'formik' + +import { SelectField, TextField } from 'components/FormField' +import { T } from 'components/T' + +const modes = [ + { name: 'Random One', value: 'one' }, + { name: 'Fixed Number', value: 'fixed' }, + { name: 'Fixed Percent', value: 'fixed-percent' }, + { name: 'Random Max Percent', value: 'random-max-percent' }, +] +const modesWithAdornment = ['fixed-percent', 'random-max-percent'] + +interface ModeProps { + modeScope: string + scope: string +} + +const Mode: React.FC = ({ modeScope, scope }) => { + const { values } = useFormikContext() + + return ( + <> + } + helperText={} + > + All + {modes.map((option) => ( + + {option.name} + + ))} + + + {!['all', 'one'].includes(getIn(values, modeScope).mode) && ( + } + helperText={} + endAdornment={ + modesWithAdornment.includes(getIn(values, scope).mode) && % + } + /> + )} + + ) +} + +export default Mode diff --git a/ui/app/src/components/Scope/TargetsTable/PhysicalMachinesTable.tsx b/ui/app/src/components/Scope/TargetsTable/PhysicalMachinesTable.tsx new file mode 100644 index 0000000000..94f565cbb7 --- /dev/null +++ b/ui/app/src/components/Scope/TargetsTable/PhysicalMachinesTable.tsx @@ -0,0 +1,67 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Checkbox, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@mui/material' +import { TypesPhysicalMachine } from 'openapi/index.schemas' + +import PaperContainer from '@ui/mui-extends/esm/PaperContainer' + +import { T } from 'components/T' + +import { TargetsTableActions } from '.' + +interface PhysicalMachinesTableProps extends TargetsTableActions { + data: TypesPhysicalMachine[] +} + +export default function PhysicalMachinesTable({ data, handleSelect, isSelected }: PhysicalMachinesTableProps) { + return ( + + + + + + + + + + + + + + + + + + {data.map((d) => { + const key = `${d.namespace}:${d.name}` + + return ( + + + + + {d.name} + {d.namespace} + {d.address} + + ) + })} + +
+
+ ) +} diff --git a/ui/app/src/components/Scope/TargetsTable/PodsTable.tsx b/ui/app/src/components/Scope/TargetsTable/PodsTable.tsx new file mode 100644 index 0000000000..79652662f1 --- /dev/null +++ b/ui/app/src/components/Scope/TargetsTable/PodsTable.tsx @@ -0,0 +1,71 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Checkbox, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@mui/material' +import { TypesPod } from 'openapi/index.schemas' + +import PaperContainer from '@ui/mui-extends/esm/PaperContainer' + +import { T } from 'components/T' + +import { TargetsTableActions } from '.' + +interface PodsTableProps extends TargetsTableActions { + data: TypesPod[] +} + +export default function PosTable({ data, handleSelect, isSelected }: PodsTableProps) { + return ( + + + + + + + + + + + + + + + + + + + + + {data.map((d) => { + const key = `${d.namespace}:${d.name}` + + return ( + + + + + {d.name} + {d.namespace} + {d.ip} + {d.state} + + ) + })} + +
+
+ ) +} diff --git a/ui/app/src/components/Scope/TargetsTable/index.tsx b/ui/app/src/components/Scope/TargetsTable/index.tsx new file mode 100644 index 0000000000..7510e1599a --- /dev/null +++ b/ui/app/src/components/Scope/TargetsTable/index.tsx @@ -0,0 +1,88 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { getIn, useFormikContext } from 'formik' +import { useMemo } from 'react' + +import { useStoreDispatch } from 'store' + +import { Env } from 'slices/experiments' +import { setAlert } from 'slices/globalStatus' + +import PhysicalMachinesTable from './PhysicalMachinesTable' +import PodsTable from './PodsTable' + +interface TargetsTableProps { + env: Env + scope?: string + data: any[] +} + +export interface TargetsTableActions { + handleSelect: (name: string) => () => void + isSelected: (name: string) => boolean +} + +const TargetsTable = ({ env, scope = 'scope', data }: TargetsTableProps) => { + const originalTargets = useMemo(() => data.map((d) => `${d.namespace}:${d.name}`), [data]) + const targetsCount = originalTargets.length + + const { values, setFieldValue } = useFormikContext() + const formikTargets: string[] = getIn(values, `${scope}.pods`) + + const selected = formikTargets.length > 0 ? formikTargets : originalTargets + const isSelected = (name: string) => selected.indexOf(name) !== -1 + const setSelected = (newVal: string[]) => setFieldValue(`${scope}.pods`, newVal) + + const dispatch = useStoreDispatch() + + const handleSelect = (name: string) => () => { + const selectedIndex = selected.indexOf(name) + let newSelected: string[] = [] + + if (selectedIndex === -1) { + newSelected = [...selected, name] + } else if (selectedIndex === 0) { + newSelected = selected.slice(1) + } else if (selectedIndex === selected.length - 1) { + newSelected = selected.slice(0, -1) + } else if (selectedIndex > 0) { + newSelected = [...selected.slice(0, selectedIndex), ...selected.slice(selectedIndex + 1)] + } + + if (newSelected.length === 0) { + dispatch( + setAlert({ + type: 'warning', + message: 'Please select at least one pod.', + }) + ) + + return + } + + setSelected(newSelected.length === targetsCount ? [] : newSelected) + } + + return ( + <> + {env === 'k8s' && } + {env === 'physic' && } + + ) +} + +export default TargetsTable diff --git a/ui/app/src/components/Scope/index.tsx b/ui/app/src/components/Scope/index.tsx new file mode 100644 index 0000000000..2d31140a48 --- /dev/null +++ b/ui/app/src/components/Scope/index.tsx @@ -0,0 +1,223 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { MenuItem, Typography } from '@mui/material' +import { getIn, useFormikContext } from 'formik' +import { useGetCommonAnnotations, useGetCommonLabels, usePostCommonPhysicalmachines, usePostCommonPods } from 'openapi' +import { useEffect, useMemo } from 'react' + +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreSelector } from 'store' + +import { Env } from 'slices/experiments' + +import { podPhases } from 'components/AutoForm/data' +import { AutocompleteField, SelectField } from 'components/FormField' +import MoreOptions from 'components/MoreOptions' +import { T } from 'components/T' + +import { arrToObjBySep, objToArrBySep } from 'lib/utils' + +import DeprecatedAddress from './DeprecatedAddress' +import Mode from './Mode' +import TargetsTable from './TargetsTable' + +interface ScopeProps { + env: Env + namespaces: string[] + scope?: string + modeScope?: string + previewTitle?: string | JSX.Element +} + +const Scope = ({ env, namespaces, scope = 'selector', modeScope = '', previewTitle }: ScopeProps) => { + const { values, setFieldValue, errors, touched } = useFormikContext() + const { + namespaces: currentNamespaces, + labelSelectors: currentLabels, + annotationSelectors: currentAnnotations, + } = getIn(values, scope) + + const { settings } = useStoreSelector((state) => state) + const { enableKubeSystemNS } = settings + + const { data: labels } = useGetCommonLabels( + { + podNamespaceList: currentNamespaces.join(','), + }, + { + query: { + enabled: currentNamespaces.length > 0, + initialData: {}, + }, + } + ) + const { data: annotations } = useGetCommonAnnotations( + { + podNamespaceList: currentNamespaces.join(','), + }, + { + query: { + enabled: currentNamespaces.length > 0, + initialData: {}, + }, + } + ) + const kvSeparator = ': ' + const labelKVs = useMemo(() => objToArrBySep(labels!, kvSeparator), [labels]) + const annotationKVs = useMemo(() => objToArrBySep(annotations!, kvSeparator), [annotations]) + + const { data: pods, mutate: postPods } = usePostCommonPods() + const { data: physicalMachines, mutate: postPhysicalMachines } = usePostCommonPhysicalmachines() + + const targets = env === 'k8s' ? pods : physicalMachines + + useEffect(() => { + // Set namespaces automatically when `targetNamespace` is set because there is only one namespace. + if (namespaces.length === 1) { + setFieldValue(`${scope}.namespace`, namespaces) + + // Set namespace in metadata automatically too. + if (scope === 'spec.selector') { + setFieldValue('namespace', namespaces[0]) + } + } + }, [namespaces, scope, setFieldValue]) + + useEffect(() => { + if (currentNamespaces.length > 0) { + // Get different targets according to the env. + if (env === 'k8s') { + postPods({ + data: { + namespaces: currentNamespaces, + labelSelectors: arrToObjBySep(currentLabels, kvSeparator), + annotationSelectors: arrToObjBySep(currentAnnotations, kvSeparator), + }, + }) + } else { + postPhysicalMachines({ + data: { + namespaces: currentNamespaces, + labelSelectors: arrToObjBySep(currentLabels, kvSeparator), + annotationSelectors: arrToObjBySep(currentAnnotations, kvSeparator), + }, + }) + } + } + }, [currentNamespaces, currentLabels, currentAnnotations, env, postPods, postPhysicalMachines]) + + return ( + + } + helperText={ + getIn(touched, `${scope}.namespaces`) && getIn(errors, `${scope}.namespaces`) ? ( + getIn(errors, `${scope}.namespaces`) + ) : ( + + ) + } + options={enableKubeSystemNS ? namespaces : namespaces.filter((d) => d !== 'kube-system')} + error={getIn(errors, `${scope}.namespaces`) && getIn(touched, `${scope}.namespaces`) ? true : false} + /> + + } + helperText={} + options={labelKVs} + /> + + + } + helperText={} + options={annotationKVs} + /> + + + multiple + name={`${scope}.podPhaseSelectors`} + label={} + helperText={} + fullWidth + > + {podPhases.map((option) => ( + + {option} + + ))} + + + + + +
+ + {previewTitle || } + + + + +
+ + {targets ? ( + + ) : ( + + + + )} +
+ ) +} + +interface ConditionalScopeProps extends ScopeProps { + kind: string +} + +const ConditionalScope = ({ kind, ...rest }: ConditionalScopeProps) => { + const disabled = kind === 'AWSChaos' || kind === 'GCPChaos' + + const { useNewPhysicalMachine } = useStoreSelector((state) => state.settings) + + if (disabled) { + return ( + {`${kind} does not need to define the scope.`} + ) + } + + if (rest.env === 'physic' && !useNewPhysicalMachine) { + return + } + + return +} + +export default ConditionalScope diff --git a/ui/app/src/components/Search/index.tsx b/ui/app/src/components/Search/index.tsx new file mode 100644 index 0000000000..97baaddb62 --- /dev/null +++ b/ui/app/src/components/Search/index.tsx @@ -0,0 +1,244 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import FingerprintIcon from '@mui/icons-material/Fingerprint' +import HelpOutlineIcon from '@mui/icons-material/HelpOutline' +import ScheduleIcon from '@mui/icons-material/Schedule' +import SearchIcon from '@mui/icons-material/Search' +import { + Autocomplete, + Box, + ChipProps, + CircularProgress, + InputAdornment, + Chip as MUIChip, + TextField, + Typography, +} from '@mui/material' +import { makeStyles } from '@mui/styles' +import _ from 'lodash' +import { + getArchives, + getArchivesSchedules, + getArchivesWorkflows, + getExperiments, + getSchedules, + getWorkflows, +} from 'openapi' +import { CoreWorkflowMeta, TypesArchive, TypesExperiment, TypesSchedule } from 'openapi/index.schemas' +import { useMemo, useState } from 'react' +import { useIntl } from 'react-intl' +import { useNavigate } from 'react-router-dom' + +import Paper from '@ui/mui-extends/esm/Paper' +import Tooltip from '@ui/mui-extends/esm/Tooltip' + +import i18n from 'components/T' + +import { format } from 'lib/luxon' +import search from 'lib/search' + +const Chip = (props: ChipProps) => + +const useStyles = makeStyles((theme) => ({ + tooltip: { + marginBottom: 0, + paddingLeft: theme.spacing(3), + '& > li': { + marginTop: theme.spacing(1.5), + }, + }, + chipContainer: { + display: 'flex', + flexWrap: 'wrap', + '& > *': { + margin: theme.spacing(0.75), + marginLeft: 0, + }, + }, +})) + +type OptionCategory = CoreWorkflowMeta | TypesSchedule | TypesExperiment | TypesArchive +type Option = OptionCategory & { is?: string } + +const Search: React.FC = () => { + const classes = useStyles() + const navigate = useNavigate() + const intl = useIntl() + + const [open, setOpen] = useState(false) + const [options, setOptions] = useState([]) + const [noResult, setNoResult] = useState(true) + const loading = open && options.length === 0 + + const debounceExecSearch = useMemo( + () => + _.debounce(async (s: string) => { + setNoResult(false) + setOpen(true) + + const [workflows, schedules, experiments, archives, archivedWorkflows, archivedSchedules] = [ + (await getWorkflows()).map((d) => ({ + ...d, + is: 'workflow' as 'workflow', + kind: 'Workflow', + })), + (await getSchedules()).map((d) => ({ ...d, is: 'schedule' })), + (await getExperiments()).map((d) => ({ ...d, is: 'experiment' })), + (await getArchives()).map((d) => ({ ...d, is: 'archive' })), + (await getArchivesWorkflows()).map((d) => ({ ...d, is: 'archive' })), + (await getArchivesSchedules()).map((d) => ({ ...d, is: 'archive' })), + ] + + const result = search( + { workflows, schedules, experiments, archives: [...archives, ...archivedWorkflows, ...archivedSchedules] }, + s + ) + const newOptions = [...result.workflows, ...result.schedules, ...result.experiments, ...result.archives] + + setOptions(newOptions) + if (newOptions.length === 0) { + setNoResult(true) + } + }, 500), + [] + ) + + const groupBy = (option: Option) => i18n(`${option.is}s.title`, intl) + const getOptionLabel = (option: Option) => option.name! + const isOptionEqualToValue = (option: Option, value: Option) => option.uid === value.uid + const filterOptions = (options: Option[]) => options + + const determineKind = (option: Option) => (option.is === 'workflow' ? 'Workflow' : (option as any).kind) + const determineLink = (uuid: uuid, type: Option['is'], kind: string) => { + let link = `/${type}s/${uuid}` + + switch (type) { + case 'archive': + switch (kind) { + case 'Workflow': + case 'Schedule': + link = `${link}?kind=${kind.toLowerCase()}` + break + default: + link = `${link}?kind=experiment` + break + } + break + } + + return link + } + + const renderOption = (props: any, option: Option) => { + const type = option.is + + const uuid = option.uid! + const name = option.name + const kind = determineKind(option) + const time = option.created_at! + + const onClick = () => { + navigate(determineLink(uuid, type, kind)) + setOpen(false) + } + + return ( +
  • + + + {name} + +
    + } label={_.truncate(uuid)} title={uuid} /> + + } label={format(time)} /> +
    +
    +
  • + ) + } + + const onChange = (_: any, value: Option, reason: string) => { + if (reason === 'selectOption') { + navigate(determineLink(value.uid!, value.is, determineKind(value!))) + } + } + + const onInputChange = (_: any, newVal: string, reason: string) => { + if (newVal && reason !== 'reset') { + debounceExecSearch(newVal) + } + } + + return ( + setOpen(false)} + loading={loading} + loadingText={noResult ? i18n('search.result.noResult') : i18n('search.result.acquiring')} + options={options} + groupBy={groupBy} + getOptionLabel={getOptionLabel} + isOptionEqualToValue={isOptionEqualToValue} + filterOptions={filterOptions} + renderOption={renderOption} + onChange={onChange} + onInputChange={onInputChange} + renderInput={(params) => ( + + + + ), + endAdornment: ( + <> + {loading && !noResult ? : null} + + + {i18n('search.tip.title')} +
      +
    • {i18n('search.tip.namespace')}
    • +
    • {i18n('search.tip.kind')}
    • +
    + + } + > + +
    +
    + + ), + }} + /> + )} + PaperComponent={(props) => } + disableClearable + /> + ) +} + +export default Search diff --git a/ui/app/src/components/StatusLabel/index.tsx b/ui/app/src/components/StatusLabel/index.tsx new file mode 100644 index 0000000000..9d91062262 --- /dev/null +++ b/ui/app/src/components/StatusLabel/index.tsx @@ -0,0 +1,82 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { CircularProgress, Typography, styled, useTheme } from '@mui/material' + +import Space from '@ui/mui-extends/esm/Space' + +import { T } from 'components/T' + +const Circle = styled('div')((props) => ({ + width: 8, + height: 8, + backgroundColor: props.color, + borderRadius: '50%', +})) + +interface StatusLabelProps { + status: string +} + +const StatusLabel: React.FC = ({ status }) => { + const theme = useTheme() + + const label = + + let color + switch (status) { + case 'injecting': + case 'running': + case 'deleting': + color = theme.palette.primary.main + + break + case 'paused': + case 'unknown': + color = theme.palette.grey[500] + + break + case 'finished': + color = theme.palette.success.main + + break + case 'failed': + color = theme.palette.error.main + + break + } + + let icon + switch (status) { + case 'injecting': + case 'running': + case 'deleting': + icon = + + break + } + + return ( + + {icon || } + + {label} + + + ) +} + +export default StatusLabel diff --git a/ui/app/src/components/T/index.test.tsx b/ui/app/src/components/T/index.test.tsx new file mode 100644 index 0000000000..686405d969 --- /dev/null +++ b/ui/app/src/components/T/index.test.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2022 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { render, screen } from 'test-utils' + +import i18n, { T } from '.' + +describe('i18n() and ', () => { + test('displays `k8s.title` with i18n()', async () => { + render(
    {i18n('k8s.title')}
    ) + + expect(screen.getByText('Kubernetes')).toBeInTheDocument() + }) + + test('displays `k8s.title` with ', async () => { + render() + + expect(screen.getByText('Kubernetes')).toBeInTheDocument() + }) +}) diff --git a/ui/app/src/components/T/index.tsx b/ui/app/src/components/T/index.tsx new file mode 100644 index 0000000000..24da1cb108 --- /dev/null +++ b/ui/app/src/components/T/index.tsx @@ -0,0 +1,40 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* + * This component was created to provide localized translations. + * + * It has three ways to use: + * + * 1. **DEPRECATED** `i18n(string)` will return a `FormattedMessage` component with the given string as id. + * 2. `i18n(string, intl)` will use intl object to return a translated string. + * 3. `T` is an alias of `FormattedMessage`. Mostly you will often use `T` instead of `i18n`. + * + */ +import { FormattedMessage } from 'react-intl' +import type { IntlShape } from 'react-intl' + +// https://github.com/microsoft/TypeScript/issues/24929 +function i18n(id: string): Exclude // DEPRECATED, but preserve for backward compatibility. +function i18n(id: string, intl: IntlShape): string +function i18n(id: string, intl?: IntlShape) { + return intl ? intl.formatMessage({ id }) : +} + +// Re-export an alias for FormattedMessage. +export const T = FormattedMessage +export default i18n diff --git a/ui/app/src/components/Token/index.tsx b/ui/app/src/components/Token/index.tsx new file mode 100644 index 0000000000..592490f58b --- /dev/null +++ b/ui/app/src/components/Token/index.tsx @@ -0,0 +1,132 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { applyAPIAuthentication, resetAPIAuthentication } from 'api/interceptors' +import { Form, Formik, FormikHelpers } from 'formik' +import { getExperimentsState } from 'openapi' +import { useIntl } from 'react-intl' + +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch, useStoreSelector } from 'store' + +import { setAlert, setTokenName, setTokens } from 'slices/globalStatus' + +import { Submit, TextField } from 'components/FormField' +import i18n from 'components/T' + +import { validateName } from 'lib/formikhelpers' + +function validateToken(value: string) { + let error + + if (value === '') { + error = i18n('settings.addToken.tokenValidation') as unknown as string + } + + return error +} + +export interface TokenFormValues { + name: string + token: string +} + +interface TokenProps { + onSubmitCallback?: (values: TokenFormValues) => void +} + +const Token: React.FC = ({ onSubmitCallback }) => { + const intl = useIntl() + + const { tokens } = useStoreSelector((state) => state.globalStatus) + const dispatch = useStoreDispatch() + + const saveToken = (values: TokenFormValues) => { + dispatch(setTokens([...tokens, values])) + dispatch(setTokenName(values.name)) + } + + const submitToken = (values: TokenFormValues, { setFieldError, resetForm }: FormikHelpers) => { + if (tokens.some((token) => token.name === values.name)) { + dispatch( + setAlert({ + type: 'warning', + message: i18n('settings.addToken.duplicateDesc', intl), + }) + ) + + return + } + + applyAPIAuthentication(values.token) + + function restSteps() { + saveToken(values) + + typeof onSubmitCallback === 'function' && onSubmitCallback(values) + + resetForm() + } + + // Test the validity of the token in advance + getExperimentsState() + .then(restSteps) + .catch((error) => { + const data = error.response?.data + + if (data && data.code === 'error.api.invalid_request' && data.message.includes('Unauthorized')) { + setFieldError('token', 'Please check the validity of the token') + + resetAPIAuthentication() + + return + } + + restSteps() + }) + } + + return ( + + {({ errors, touched }) => ( +
    + + + + + + + )} +
    + ) +} + +export default Token diff --git a/ui/app/src/components/TopContainer/Auth.tsx b/ui/app/src/components/TopContainer/Auth.tsx new file mode 100644 index 0000000000..c049c2eafc --- /dev/null +++ b/ui/app/src/components/TopContainer/Auth.tsx @@ -0,0 +1,101 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import GoogleIcon from '@mui/icons-material/Google' +import { Box, Button, Divider, IconButton, Link, Typography } from '@mui/material' +import { Stale } from 'api/queryUtils' +import { useGetCommonConfig } from 'openapi' +import { useState } from 'react' +import { useNavigate } from 'react-router-dom' + +import ConfirmDialog from '@ui/mui-extends/esm/ConfirmDialog' +import Space from '@ui/mui-extends/esm/Space' + +import RBACGenerator from 'components/RBACGenerator' +import i18n from 'components/T' +import Token from 'components/Token' + +interface AuthProps { + open: boolean +} + +const Auth: React.FC = ({ open }) => { + const navigate = useNavigate() + + const { data: config } = useGetCommonConfig({ + query: { + enabled: false, + staleTime: Stale.DAY, + }, + }) + + const [tokenGenOpen, setTokenGenOpen] = useState(false) + + const handleSubmitCallback = () => navigate(0) + const handleAuthGCP = () => (window.location.href = '/api/auth/gcp/redirect') + + return ( + + + + {i18n('settings.addToken.prompt2')} + setTokenGenOpen(true)}> + {i18n('settings.addToken.prompt3')} + + + + + {config?.gcp_security_mode && ( + <> + + {i18n('settings.addToken.or')} + + + + + + + + )} + + + + + + + + + ) +} + +export default Auth diff --git a/ui/app/src/components/TopContainer/Namespace.tsx b/ui/app/src/components/TopContainer/Namespace.tsx new file mode 100644 index 0000000000..42fd33fa72 --- /dev/null +++ b/ui/app/src/components/TopContainer/Namespace.tsx @@ -0,0 +1,68 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Autocomplete, TextField } from '@mui/material' +import { applyNSParam } from 'api/interceptors' +import { Stale } from 'api/queryUtils' +import { useGetCommonChaosAvailableNamespaces } from 'openapi' +import { useLocation, useNavigate } from 'react-router-dom' + +import Paper from '@ui/mui-extends/esm/Paper' + +import { useStoreDispatch, useStoreSelector } from 'store' + +import { setNameSpace } from 'slices/globalStatus' + +import i18n from 'components/T' + +const Namespace = () => { + const navigate = useNavigate() + const { pathname } = useLocation() + + const { data: namespaces } = useGetCommonChaosAvailableNamespaces({ + query: { + staleTime: Stale.DAY, + }, + }) + + const { namespace } = useStoreSelector((state) => state.globalStatus) + const dispatch = useStoreDispatch() + + const handleSelectGlobalNamespace = (_: any, newVal: any) => { + const ns = newVal + + applyNSParam(ns) + dispatch(setNameSpace(ns)) + + navigate('/namespaceSetted', { replace: true }) + setTimeout(() => navigate(pathname, { replace: true })) + } + + return ( + } + PaperComponent={(props) => } + /> + ) +} + +export default Namespace diff --git a/ui/app/src/components/TopContainer/Navbar.tsx b/ui/app/src/components/TopContainer/Navbar.tsx new file mode 100644 index 0000000000..b4e18c3ae3 --- /dev/null +++ b/ui/app/src/components/TopContainer/Navbar.tsx @@ -0,0 +1,48 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import MenuIcon from '@mui/icons-material/Menu' +import MenuOpenIcon from '@mui/icons-material/MenuOpen' +import { AppBar, Box, IconButton, Toolbar } from '@mui/material' + +import Space from '@ui/mui-extends/esm/Space' + +import Search from 'components/Search' + +import Namespace from './Namespace' + +interface HeaderProps { + openDrawer: boolean + handleDrawerToggle: () => void +} + +const Navbar: React.FC = ({ openDrawer, handleDrawerToggle }) => ( + + + + + {openDrawer ? : } + + + + + + + + +) + +export default Navbar diff --git a/ui/app/src/components/TopContainer/Sidebar.tsx b/ui/app/src/components/TopContainer/Sidebar.tsx new file mode 100644 index 0000000000..f6d7427b14 --- /dev/null +++ b/ui/app/src/components/TopContainer/Sidebar.tsx @@ -0,0 +1,184 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import AccountTreeOutlinedIcon from '@mui/icons-material/AccountTreeOutlined' +import ArchiveOutlinedIcon from '@mui/icons-material/ArchiveOutlined' +import DashboardOutlinedIcon from '@mui/icons-material/DashboardOutlined' +import MenuBookOutlinedIcon from '@mui/icons-material/MenuBookOutlined' +import ScheduleIcon from '@mui/icons-material/Schedule' +import ScienceOutlinedIcon from '@mui/icons-material/ScienceOutlined' +import SettingsOutlinedIcon from '@mui/icons-material/SettingsOutlined' +import TimelineOutlinedIcon from '@mui/icons-material/TimelineOutlined' +import { + Box, + CSSObject, + List, + ListItemButton, + ListItemIcon, + ListItemTextProps, + Drawer as MuiDrawer, + ListItemText as MuiListItemText, +} from '@mui/material' +import { Theme, styled } from '@mui/material/styles' +import { NavLink } from 'react-router-dom' + +import { useStoreSelector } from 'store' + +import i18n from 'components/T' + +import logoMiniWhite from 'images/logo-mini-white.svg' +import logoMini from 'images/logo-mini.svg' +import logoWhite from 'images/logo-white.svg' +import logo from 'images/logo.svg' + +export const openedWidth = 256 +export const closedWidth = 64 + +const openedMixin = (theme: Theme): CSSObject => ({ + width: openedWidth, + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.enteringScreen, + }), + overflowX: 'hidden', +}) + +const closedMixin = (theme: Theme): CSSObject => ({ + width: closedWidth, + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, + }), + overflowX: 'hidden', +}) + +const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== 'open' })(({ theme, open }) => ({ + width: openedWidth, + '& .MuiDrawer-paper': { + ...(open ? openedMixin(theme) : closedMixin(theme)), + }, + '& .MuiListItemButton-root': { + paddingLeft: !open ? theme.spacing(3) : 16, // original paddingLeft is 16 + }, +})) + +const SidebarNavHoverProperties = (theme: Theme) => ({ + background: theme.palette.secondaryContainer.main, + color: theme.palette.onSecondaryContainer.main, + borderRadius: 4, + '& .MuiListItemIcon-root': { + color: theme.palette.onSecondaryContainer.main, + }, +}) + +const SidebarNav = styled(List)(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + color: theme.palette.onSurfaceVariant.main, + '& .MuiListItemButton-root': { + width: '80%', + marginBottom: theme.spacing(4), + paddingTop: theme.spacing(1), + paddingBottom: theme.spacing(1), + '&:hover, &.active': SidebarNavHoverProperties(theme), + }, + '& .MuiListItemIcon-root': { + minWidth: 0, + marginRight: theme.spacing(8), + color: theme.palette.onSurfaceVariant.main, + }, +})) + +const ListItemText = (props: ListItemTextProps) => ( + +) + +const listItems = [ + { icon: , text: 'dashboard' }, + { + icon: , + text: 'workflows', + }, + { + icon: , + text: 'schedules', + }, + { + icon: , + text: 'experiments', + }, + { + icon: , + text: 'events', + }, + { + icon: , + text: 'archives', + }, + { + icon: , + text: 'settings', + }, +] + +interface SidebarProps { + open: boolean +} + +const Sidebar: React.FC = ({ open }) => { + const { theme } = useStoreSelector((state) => state.settings) + + return ( + + + + Chaos Mesh + + + + + {listItems.map(({ icon, text }) => ( + + {icon} + + + ))} + + + + + + + + + + + + + ) +} + +export default Sidebar diff --git a/ui/app/src/components/TopContainer/index.tsx b/ui/app/src/components/TopContainer/index.tsx new file mode 100644 index 0000000000..745662b35c --- /dev/null +++ b/ui/app/src/components/TopContainer/index.tsx @@ -0,0 +1,202 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import loadable from '@loadable/component' +import { + Alert, + Box, + BoxProps, + Container, + CssBaseline, + Divider, + Portal, + Snackbar, + useMediaQuery, + useTheme, +} from '@mui/material' +import { styled } from '@mui/material/styles' +import { applyAPIAuthentication, applyNSParam } from 'api/interceptors' +import { Stale } from 'api/queryUtils' +import Cookies from 'js-cookie' +import { useGetCommonConfig } from 'openapi' +import { useEffect, useState } from 'react' +import { Outlet } from 'react-router-dom' + +import ConfirmDialog from '@ui/mui-extends/esm/ConfirmDialog' +import Loading from '@ui/mui-extends/esm/Loading' + +import { useStoreDispatch, useStoreSelector } from 'store' + +import { setAlertOpen, setAuthOpen, setConfirmOpen, setNameSpace, setTokenName, setTokens } from 'slices/globalStatus' + +import { TokenFormValues } from 'components/Token' + +import insertCommonStyle from 'lib/d3/insertCommonStyle' +import LS from 'lib/localStorage' + +import Navbar from './Navbar' +import { closedWidth, openedWidth } from './Sidebar' +import Sidebar from './Sidebar' + +const Auth = loadable(() => import('./Auth')) + +const Root = styled(Box, { + shouldForwardProp: (prop) => prop !== 'open', +})(({ theme, open }) => ({ + position: 'relative', + width: `calc(100% - ${open ? openedWidth : closedWidth}px)`, + height: '100vh', + marginLeft: open ? openedWidth : closedWidth, + transition: theme.transitions.create(['width', 'margin'], { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration[open ? 'enteringScreen' : 'leavingScreen'], + }), + [theme.breakpoints.down('sm')]: { + minWidth: theme.breakpoints.values.md, + }, +})) + +const TopContainer = () => { + const theme = useTheme() + + const { alert, alertOpen, confirm, confirmOpen, authOpen } = useStoreSelector((state) => state.globalStatus) + + const dispatch = useStoreDispatch() + const handleSnackClose = () => dispatch(setAlertOpen(false)) + const handleConfirmClose = () => dispatch(setConfirmOpen(false)) + + // Sidebar related + const miniSidebar = LS.get('mini-sidebar') === 'y' + const [openDrawer, setOpenDrawer] = useState(!miniSidebar) + const handleDrawerToggle = () => { + setOpenDrawer(!openDrawer) + LS.set('mini-sidebar', openDrawer ? 'y' : 'n') + } + + const [loading, setLoading] = useState(true) + + /** + * Set authorization (RBAC token / GCP) for API use. + * + */ + function setAuth() { + // GCP + const accessToken = Cookies.get('access_token') + const expiry = Cookies.get('expiry') + + if (accessToken && expiry) { + const token = { + accessToken, + expiry, + } + + applyAPIAuthentication(token as any) + dispatch(setTokenName('gcp')) + + return + } + + const token = LS.get('token') + const tokenName = LS.get('token-name') + const globalNamespace = LS.get('global-namespace') + + if (token && tokenName) { + const tokens: TokenFormValues[] = JSON.parse(token) + + applyAPIAuthentication(tokens.find(({ name }) => name === tokenName)!.token) + dispatch(setTokens(tokens)) + dispatch(setTokenName(tokenName)) + } else { + dispatch(setAuthOpen(true)) + } + + if (globalNamespace) { + applyNSParam(globalNamespace) + dispatch(setNameSpace(globalNamespace)) + } + } + + useGetCommonConfig({ + query: { + staleTime: Stale.DAY, + onSuccess(data) { + if (data.security_mode) { + setAuth() + } + + setLoading(false) + }, + }, + }) + + useEffect(() => { + insertCommonStyle() + }, []) + + const isTabletScreen = useMediaQuery(theme.breakpoints.down('md')) + useEffect(() => { + if (isTabletScreen) { + setOpenDrawer(false) + } + }, [isTabletScreen]) + + return ( + <> + + + + + + + + + {loading ? : } + + + + + + + + + + {alert.message} + + + + + + + + + ) +} + +export default TopContainer diff --git a/ui/app/src/components/YAML/index.tsx b/ui/app/src/components/YAML/index.tsx new file mode 100644 index 0000000000..dabfa42660 --- /dev/null +++ b/ui/app/src/components/YAML/index.tsx @@ -0,0 +1,75 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import FileOpenIcon from '@mui/icons-material/FileOpen' +import LoadingButton, { LoadingButtonProps } from '@mui/lab/LoadingButton' +import { useState } from 'react' + +import { useStoreDispatch } from 'store' + +import { setAlert } from 'slices/globalStatus' + +import { T } from 'components/T' + +interface YAMLProps { + callback: (y: any) => void + ButtonProps?: LoadingButtonProps<'label'> +} + +const YAML: React.FC = ({ children, callback, ButtonProps }) => { + const [loading, setLoading] = useState(false) + + const dispatch = useStoreDispatch() + + const handleUploadYAML = (e: React.ChangeEvent) => { + setLoading(true) + + const f = e.target.files![0] + + const reader = new FileReader() + reader.onload = function () { + const y = reader.result + + callback(y) + + dispatch( + setAlert({ + type: 'success', + message: , + }) + ) + + setLoading(false) + } + reader.readAsText(f) + } + + return ( + } + > + {children || } + + + ) +} + +export default YAML diff --git a/ui/app/src/components/YAMLEditor/index.tsx b/ui/app/src/components/YAMLEditor/index.tsx new file mode 100644 index 0000000000..727450b04e --- /dev/null +++ b/ui/app/src/components/YAMLEditor/index.tsx @@ -0,0 +1,123 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import CloudDownloadOutlinedIcon from '@mui/icons-material/CloudDownloadOutlined' +import PublishIcon from '@mui/icons-material/Publish' +import { Box, Button } from '@mui/material' +import 'ace-builds' +import { Ace } from 'ace-builds' +import 'ace-builds/src-min-noconflict/mode-yaml' +import 'ace-builds/src-min-noconflict/theme-tomorrow' +import 'ace-builds/src-min-noconflict/theme-tomorrow_night_eighties' +import 'ace-builds/webpack-resolver' +import fileDownload from 'js-file-download' +import yaml from 'js-yaml' +import { memo } from 'react' +import { useState } from 'react' +import AceEditor, { IAceEditorProps } from 'react-ace' +import { useIntl } from 'react-intl' + +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch, useStoreSelector } from 'store' + +import { setConfirm } from 'slices/globalStatus' + +import i18n from 'components/T' + +interface YAMLEditorProps { + name?: string + data?: string + mountEditor?: (editor: Ace.Editor) => void + onUpdate?: (data: any) => void + download?: boolean + aceProps?: IAceEditorProps +} + +const YAMLEditor: React.FC = ({ name, data, mountEditor, onUpdate, download, aceProps }) => { + const intl = useIntl() + + const { theme } = useStoreSelector((state) => state.settings) + const dispatch = useStoreDispatch() + + const [editor, setEditor] = useState() + + const handleOnLoad = (editor: Ace.Editor) => { + setEditor(editor) + + typeof mountEditor === 'function' && mountEditor(editor) + } + + const handleSelect = () => { + dispatch( + setConfirm({ + title: `${i18n('common.update', intl)} ${name}`, + handle: handleOnUpdate, + }) + ) + } + + const handleOnUpdate = () => { + typeof onUpdate === 'function' && onUpdate(yaml.load(editor!.getValue())) + } + + const handleDownloadExperiment = () => fileDownload(editor!.getValue(), `${name}.yaml`) + + return ( + + + {(typeof onUpdate === 'function' || download) && ( + theme.spacing(1.5), right: (theme) => theme.spacing(3) }} + > + {download && ( + + )} + {typeof onUpdate === 'function' && ( + + )} + + )} + + ) +} + +export default memo(YAMLEditor, (prevProps, nextProps) => { + if (prevProps.data !== nextProps.data) { + return false + } + + return true +}) diff --git a/ui/app/src/formik/AWSChaos.ts b/ui/app/src/formik/AWSChaos.ts new file mode 100644 index 0000000000..f87fea5a2e --- /dev/null +++ b/ui/app/src/formik/AWSChaos.ts @@ -0,0 +1,46 @@ +/** + * This file was auto-generated by @ui/openapi. + * Do not make direct changes to the file. + */ + +export const actions = ['ec2-stop', 'ec2-restart', 'detach-volume'], + data = [ + { + field: 'text', + label: 'awsRegion', + value: '', + helperText: 'AWSRegion defines the region of aws.', + }, + { + field: 'text', + label: 'deviceName', + value: '', + helperText: 'Optional. DeviceName indicates the name of the device. Needed in detach-volume.', + when: "action=='detach-volume'", + }, + { + field: 'text', + label: 'ec2Instance', + value: '', + helperText: 'Ec2Instance indicates the ID of the ec2 instance.', + }, + { + field: 'text', + label: 'remoteCluster', + value: '', + helperText: 'Optional. RemoteCluster represents the remote cluster where the chaos will be deployed', + }, + { + field: 'text', + label: 'secretName', + value: '', + helperText: 'Optional. SecretName defines the name of kubernetes secret.', + }, + { + field: 'text', + label: 'volumeID', + value: '', + helperText: 'Optional. EbsVolume indicates the ID of the EBS volume. Needed in detach-volume.', + when: "action=='detach-volume'", + }, + ] diff --git a/ui/app/src/formik/DNSChaos.ts b/ui/app/src/formik/DNSChaos.ts new file mode 100644 index 0000000000..f2f30ae26e --- /dev/null +++ b/ui/app/src/formik/DNSChaos.ts @@ -0,0 +1,28 @@ +/** + * This file was auto-generated by @ui/openapi. + * Do not make direct changes to the file. + */ + +export const actions = ['error', 'random'], + data = [ + { + field: 'label', + label: 'containerNames', + value: [], + helperText: + 'Optional. ContainerNames indicates list of the name of affected container. If not set, the first container will be injected', + }, + { + field: 'label', + label: 'patterns', + value: [], + helperText: + 'Optional. Choose which domain names to take effect, support the placeholder ? and wildcard *, or the Specified domain name. Note: 1. The wildcard * must be at the end of the string. For example, chaos-*.org is invalid. 2. if the patterns is empty, will take effect on all the domain names. For example: The value is ["google.com", "github.*", "chaos-mes?.org"], will take effect on "google.com", "github.com" and "chaos-mesh.org"', + }, + { + field: 'text', + label: 'remoteCluster', + value: '', + helperText: 'Optional. RemoteCluster represents the remote cluster where the chaos will be deployed', + }, + ] diff --git a/ui/app/src/formik/GCPChaos.ts b/ui/app/src/formik/GCPChaos.ts new file mode 100644 index 0000000000..5f0a4658c9 --- /dev/null +++ b/ui/app/src/formik/GCPChaos.ts @@ -0,0 +1,45 @@ +/** + * This file was auto-generated by @ui/openapi. + * Do not make direct changes to the file. + */ + +export const actions = ['node-stop', 'node-reset', 'disk-loss'], + data = [ + { + field: 'label', + label: 'deviceNames', + value: [], + helperText: 'Optional. The device name of disks to detach. Needed in disk-loss.', + when: "action=='disk-loss'", + }, + { + field: 'text', + label: 'instance', + value: '', + helperText: 'Instance defines the name of the instance', + }, + { + field: 'text', + label: 'project', + value: '', + helperText: 'Project defines the ID of gcp project.', + }, + { + field: 'text', + label: 'remoteCluster', + value: '', + helperText: 'Optional. RemoteCluster represents the remote cluster where the chaos will be deployed', + }, + { + field: 'text', + label: 'secretName', + value: '', + helperText: 'Optional. SecretName defines the name of kubernetes secret. It is used for GCP credentials.', + }, + { + field: 'text', + label: 'zone', + value: '', + helperText: 'Zone defines the zone of gcp project.', + }, + ] diff --git a/ui/app/src/formik/HTTPChaos.ts b/ui/app/src/formik/HTTPChaos.ts new file mode 100644 index 0000000000..7af64cd67e --- /dev/null +++ b/ui/app/src/formik/HTTPChaos.ts @@ -0,0 +1,191 @@ +/** + * This file was auto-generated by @ui/openapi. + * Do not make direct changes to the file. + */ + +export const actions = [], + data = [ + { + field: 'select', + label: 'abort', + value: false, + items: [true, false], + helperText: 'Optional. Abort is a rule to abort a http session.', + }, + { + field: 'number', + label: 'code', + value: 0, + helperText: 'Optional. Code is a rule to select target by http status code in response.', + }, + { + field: 'text', + label: 'delay', + value: '', + helperText: + 'Optional. Delay represents the delay of the target request/response. A duration string is a possibly unsigned sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "2h45m". Valid time units are "ns", "us" (or "\u00B5s"), "ms", "s", "m", "h".', + }, + { + field: 'text', + label: 'method', + value: '', + helperText: 'Optional. Method is a rule to select target by http method in request.', + }, + { + field: 'ref', + label: 'patch', + children: [ + { + field: 'ref', + label: 'body', + children: [ + { + field: 'text', + label: 'type', + value: '', + helperText: + 'Type represents the patch type, only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) currently.', + }, + { + field: 'text', + label: 'value', + value: '', + helperText: 'Value is the patch contents.', + }, + ], + }, + { + field: 'text-label', + label: 'headers', + value: {}, + helperText: + 'Optional. Headers is a rule to append http headers of target. For example: `[["Set-Cookie", ""], ["Set-Cookie", ""]]`.', + }, + { + field: 'text-label', + label: 'queries', + value: {}, + helperText: + 'Optional. Queries is a rule to append uri queries of target(Request only). For example: `[["foo", "bar"], ["foo", "unknown"]]`.', + }, + ], + }, + { + field: 'text', + label: 'path', + value: '', + helperText: 'Optional. Path is a rule to select target by uri path in http request.', + }, + { + field: 'number', + label: 'port', + value: 0, + helperText: 'Port represents the target port to be proxy of.', + }, + { + field: 'text', + label: 'remoteCluster', + value: '', + helperText: 'Optional. RemoteCluster represents the remote cluster where the chaos will be deployed', + }, + { + field: 'ref', + label: 'replace', + children: [ + { + field: 'numbers', + label: 'body', + value: [], + helperText: 'Optional. Body is a rule to replace http message body in target.', + }, + { + field: 'number', + label: 'code', + value: 0, + helperText: 'Optional. Code is a rule to replace http status code in response.', + }, + { + field: 'text-text', + label: 'headers', + value: {}, + helperText: + 'Optional. Headers is a rule to replace http headers of target. The key-value pairs represent header name and header value pairs.', + }, + { + field: 'text', + label: 'method', + value: '', + helperText: 'Optional. Method is a rule to replace http method in request.', + }, + { + field: 'text', + label: 'path', + value: '', + helperText: 'Optional. Path is rule to to replace uri path in http request.', + }, + { + field: 'text-text', + label: 'queries', + value: {}, + helperText: + 'Optional. Queries is a rule to replace uri queries in http request. For example, with value `{ "foo": "unknown" }`, the `/?foo=bar` will be altered to `/?foo=unknown`,', + }, + ], + }, + { + field: 'text-text', + label: 'request_headers', + value: {}, + helperText: + 'Optional. RequestHeaders is a rule to select target by http headers in request. The key-value pairs represent header name and header value pairs.', + }, + { + field: 'text-text', + label: 'response_headers', + value: {}, + helperText: + 'Optional. ResponseHeaders is a rule to select target by http headers in response. The key-value pairs represent header name and header value pairs.', + }, + { + field: 'text', + label: 'target', + value: '', + helperText: 'Target is the object to be selected and injected.', + }, + { + field: 'ref', + label: 'tls', + children: [ + { + field: 'text', + label: 'caName', + value: '', + helperText: 'Optional. CAName represents the data name of ca file in secret, `ca.crt` for example', + }, + { + field: 'text', + label: 'certName', + value: '', + helperText: 'CertName represents the data name of cert file in secret, `tls.crt` for example', + }, + { + field: 'text', + label: 'keyName', + value: '', + helperText: 'KeyName represents the data name of key file in secret, `tls.key` for example', + }, + { + field: 'text', + label: 'secretName', + value: '', + helperText: 'SecretName represents the name of required secret resource', + }, + { + field: 'text', + label: 'secretNamespace', + value: '', + helperText: 'SecretNamespace represents the namespace of required secret resource', + }, + ], + }, + ] diff --git a/ui/app/src/formik/IOChaos.ts b/ui/app/src/formik/IOChaos.ts new file mode 100644 index 0000000000..09a57c6f37 --- /dev/null +++ b/ui/app/src/formik/IOChaos.ts @@ -0,0 +1,202 @@ +/** + * This file was auto-generated by @ui/openapi. + * Do not make direct changes to the file. + */ + +export const actions = ['latency', 'fault', 'attrOverride', 'mistake'], + data = [ + { + field: 'ref', + label: 'attr', + children: [ + { + field: 'ref', + label: 'atime', + children: [ + { + field: 'number', + label: 'nsec', + value: 0, + helperText: '', + }, + { + field: 'number', + label: 'sec', + value: 0, + helperText: '', + }, + ], + }, + { + field: 'number', + label: 'blocks', + value: 0, + helperText: 'Optional.', + }, + { + field: 'ref', + label: 'ctime', + children: [ + { + field: 'number', + label: 'nsec', + value: 0, + helperText: '', + }, + { + field: 'number', + label: 'sec', + value: 0, + helperText: '', + }, + ], + }, + { + field: 'number', + label: 'gid', + value: 0, + helperText: 'Optional.', + }, + { + field: 'number', + label: 'ino', + value: 0, + helperText: 'Optional.', + }, + { + field: 'text', + label: 'kind', + value: '', + helperText: 'Optional.', + }, + { + field: 'ref', + label: 'mtime', + children: [ + { + field: 'number', + label: 'nsec', + value: 0, + helperText: '', + }, + { + field: 'number', + label: 'sec', + value: 0, + helperText: '', + }, + ], + }, + { + field: 'number', + label: 'nlink', + value: 0, + helperText: 'Optional.', + }, + { + field: 'number', + label: 'perm', + value: 0, + helperText: 'Optional.', + }, + { + field: 'number', + label: 'rdev', + value: 0, + helperText: 'Optional.', + }, + { + field: 'number', + label: 'size', + value: 0, + helperText: 'Optional.', + }, + { + field: 'number', + label: 'uid', + value: 0, + helperText: 'Optional.', + }, + ], + when: "action=='attrOverride'", + }, + { + field: 'label', + label: 'containerNames', + value: [], + helperText: + 'Optional. ContainerNames indicates list of the name of affected container. If not set, the first container will be injected', + }, + { + field: 'text', + label: 'delay', + value: '', + helperText: + 'Optional. Delay defines the value of I/O chaos action delay. A delay string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms". Valid time units are "ns", "us" (or "\u00B5s"), "ms", "s", "m", "h".', + when: "action=='latency'", + }, + { + field: 'number', + label: 'errno', + value: 0, + helperText: + 'Optional. Errno defines the error code that returned by I/O action. refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html', + when: "action=='fault'", + }, + { + field: 'label', + label: 'methods', + value: [], + helperText: 'Optional. Methods defines the I/O methods for injecting I/O chaos action. default: all I/O methods.', + }, + { + field: 'ref', + label: 'mistake', + children: [ + { + field: 'text', + label: 'filling', + value: '', + helperText: 'Optional. Filling determines what is filled in the mistake data.', + }, + { + field: 'number', + label: 'maxLength', + value: 0, + helperText: 'Optional. Max length of each wrong data segment in bytes', + }, + { + field: 'number', + label: 'maxOccurrences', + value: 0, + helperText: 'Optional. There will be [1, MaxOccurrences] segments of wrong data.', + }, + ], + when: "action=='mistake'", + }, + { + field: 'text', + label: 'path', + value: '', + helperText: 'Optional. Path defines the path of files for injecting I/O chaos action.', + }, + { + field: 'number', + label: 'percent', + value: 0, + helperText: + 'Optional. Percent defines the percentage of injection errors and provides a number from 0-100. default: 100.', + }, + { + field: 'text', + label: 'remoteCluster', + value: '', + helperText: 'Optional. RemoteCluster represents the remote cluster where the chaos will be deployed', + }, + { + field: 'text', + label: 'volumePath', + value: '', + helperText: 'VolumePath represents the mount path of injected volume', + }, + ] diff --git a/ui/app/src/formik/JVMChaos.ts b/ui/app/src/formik/JVMChaos.ts new file mode 100644 index 0000000000..e10f49187d --- /dev/null +++ b/ui/app/src/formik/JVMChaos.ts @@ -0,0 +1,109 @@ +/** + * This file was auto-generated by @ui/openapi. + * Do not make direct changes to the file. + */ + +export const actions = ['latency', 'return', 'exception', 'stress', 'gc', 'ruleData', 'mysql'], + data = [ + { + field: 'text', + label: 'class', + value: '', + helperText: 'Optional. Java class', + }, + { + field: 'label', + label: 'containerNames', + value: [], + helperText: + 'Optional. ContainerNames indicates list of the name of affected container. If not set, the first container will be injected', + }, + { + field: 'number', + label: 'cpuCount', + value: 0, + helperText: 'Optional. the CPU core number needs to use, only set it when action is stress', + }, + { + field: 'text', + label: 'database', + value: '', + helperText: 'the match database default value is "", means match all database', + }, + { + field: 'text', + label: 'exception', + value: '', + helperText: + 'Optional. the exception which needs to throw for action `exception` or the exception message needs to throw in action `mysql`', + }, + { + field: 'number', + label: 'latency', + value: 0, + helperText: + "Optional. the latency duration for action 'latency', unit ms or the latency duration in action `mysql`", + }, + { + field: 'text', + label: 'memType', + value: '', + helperText: + "Optional. the memory type needs to locate, only set it when action is stress, the value can be 'stack' or 'heap'", + }, + { + field: 'text', + label: 'method', + value: '', + helperText: 'Optional. the method in Java class', + }, + { + field: 'text', + label: 'mysqlConnectorVersion', + value: '', + helperText: 'the version of mysql-connector-java, only support 5.X.X(set to "5") and 8.X.X(set to "8") now', + }, + { + field: 'text', + label: 'name', + value: '', + helperText: 'Optional. byteman rule name, should be unique, and will generate one if not set', + }, + { + field: 'number', + label: 'pid', + value: 0, + helperText: 'the pid of Java process which needs to attach', + }, + { + field: 'number', + label: 'port', + value: 0, + helperText: 'Optional. the port of agent server, default 9277', + }, + { + field: 'text', + label: 'remoteCluster', + value: '', + helperText: 'Optional. RemoteCluster represents the remote cluster where the chaos will be deployed', + }, + { + field: 'text', + label: 'ruleData', + value: '', + helperText: "Optional. the byteman rule's data for action 'ruleData'", + }, + { + field: 'text', + label: 'sqlType', + value: '', + helperText: + "the match sql type default value is \"\", means match all SQL type. The value can be 'select', 'insert', 'update', 'delete', 'replace'.", + }, + { + field: 'text', + label: 'table', + value: '', + helperText: 'the match table default value is "", means match all table', + }, + ] diff --git a/ui/app/src/formik/KernelChaos.ts b/ui/app/src/formik/KernelChaos.ts new file mode 100644 index 0000000000..eea0aafd2b --- /dev/null +++ b/ui/app/src/formik/KernelChaos.ts @@ -0,0 +1,80 @@ +/** + * This file was auto-generated by @ui/openapi. + * Do not make direct changes to the file. + */ + +export const actions = [], + data = [ + { + field: 'label', + label: 'containerNames', + value: [], + helperText: + 'Optional. ContainerNames indicates list of the name of affected container. If not set, the first container will be injected', + }, + { + field: 'ref', + label: 'failKernRequest', + children: [ + { + field: 'ref', + label: 'callchain', + multiple: true, + children: [ + { + field: 'text', + label: 'funcname', + value: '', + helperText: 'Funcname can be find from kernel source or `/proc/kallsyms`, such as `ext4_mount`', + }, + { + field: 'text', + label: 'parameters', + value: '', + helperText: + 'Parameters is used with predicate, for example, if you want to inject slab error in `d_alloc_parallel(struct dentry *parent, const struct qstr *name)` with a special name `bananas`, you need to set it to `struct dentry *parent, const struct qstr *name` otherwise omit it.', + }, + { + field: 'text', + label: 'predicate', + value: '', + helperText: + 'Predicate will access the arguments of this Frame, example with Parameters\'s, you can set it to `STRNCMP(name->name, "bananas", 8)` to make inject only with it, or omit it to inject for all d_alloc_parallel call chain.', + }, + ], + }, + { + field: 'number', + label: 'failtype', + value: 0, + helperText: + "FailType indicates what to fail, can be set to '0' / '1' / '2' If `0`, indicates slab to fail (should_failslab) If `1`, indicates alloc_page to fail (should_fail_alloc_page) If `2`, indicates bio to fail (should_fail_bio) You can read: 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt to learn more", + }, + { + field: 'label', + label: 'headers', + value: [], + helperText: + 'Headers indicates the appropriate kernel headers you need. Eg: "linux/mmzone.h", "linux/blkdev.h" and so on', + }, + { + field: 'number', + label: 'probability', + value: 0, + helperText: 'Probability indicates the fails with probability. If you want 1%, please set this field with 1.', + }, + { + field: 'number', + label: 'times', + value: 0, + helperText: 'Times indicates the max times of fails.', + }, + ], + }, + { + field: 'text', + label: 'remoteCluster', + value: '', + helperText: 'Optional. RemoteCluster represents the remote cluster where the chaos will be deployed', + }, + ] diff --git a/ui/app/src/formik/NetworkChaos.ts b/ui/app/src/formik/NetworkChaos.ts new file mode 100644 index 0000000000..f2158e0716 --- /dev/null +++ b/ui/app/src/formik/NetworkChaos.ts @@ -0,0 +1,263 @@ +/** + * This file was auto-generated by @ui/openapi. + * Do not make direct changes to the file. + */ + +export const actions = ['netem', 'delay', 'loss', 'duplicate', 'corrupt', 'partition', 'bandwidth'], + data = [ + { + field: 'ref', + label: 'bandwidth', + children: [ + { + field: 'number', + label: 'buffer', + value: 0, + helperText: 'Buffer is the maximum amount of bytes that tokens can be available for instantaneously.', + }, + { + field: 'number', + label: 'limit', + value: 0, + helperText: 'Limit is the number of bytes that can be queued waiting for tokens to become available.', + }, + { + field: 'number', + label: 'minburst', + value: 0, + helperText: + 'Optional. Minburst specifies the size of the peakrate bucket. For perfect accuracy, should be set to the MTU of the interface. If a peakrate is needed, but some burstiness is acceptable, this size can be raised. A 3000 byte minburst allows around 3mbit/s of peakrate, given 1000 byte packets.', + }, + { + field: 'number', + label: 'peakrate', + value: 0, + helperText: + 'Optional. Peakrate is the maximum depletion rate of the bucket. The peakrate does not need to be set, it is only necessary if perfect millisecond timescale shaping is required.', + }, + { + field: 'text', + label: 'rate', + value: '', + helperText: 'Rate is the speed knob. Allows bps, kbps, mbps, gbps, tbps unit. bps means bytes per second.', + }, + ], + when: "action=='bandwidth'", + }, + { + field: 'ref', + label: 'corrupt', + children: [ + { + field: 'text', + label: 'correlation', + value: '', + helperText: 'Optional.', + }, + { + field: 'text', + label: 'corrupt', + value: '', + helperText: '', + }, + ], + when: "action=='corrupt'", + }, + { + field: 'ref', + label: 'delay', + children: [ + { + field: 'text', + label: 'correlation', + value: '', + helperText: 'Optional.', + }, + { + field: 'text', + label: 'jitter', + value: '', + helperText: 'Optional.', + }, + { + field: 'text', + label: 'latency', + value: '', + helperText: '', + }, + { + field: 'ref', + label: 'reorder', + children: [ + { + field: 'text', + label: 'correlation', + value: '', + helperText: 'Optional.', + }, + { + field: 'number', + label: 'gap', + value: 0, + helperText: '', + }, + { + field: 'text', + label: 'reorder', + value: '', + helperText: '', + }, + ], + }, + ], + when: "action=='delay'", + }, + { + field: 'text', + label: 'device', + value: '', + helperText: 'Optional. Device represents the network device to be affected.', + }, + { + field: 'text', + label: 'direction', + value: '', + helperText: 'Optional. Direction represents the direction, this applies on netem and network partition action', + }, + { + field: 'ref', + label: 'duplicate', + children: [ + { + field: 'text', + label: 'correlation', + value: '', + helperText: 'Optional.', + }, + { + field: 'text', + label: 'duplicate', + value: '', + helperText: '', + }, + ], + when: "action=='duplicate'", + }, + { + field: 'label', + label: 'externalTargets', + value: [], + helperText: 'Optional. ExternalTargets represents network targets outside k8s', + }, + { + field: 'ref', + label: 'loss', + children: [ + { + field: 'text', + label: 'correlation', + value: '', + helperText: 'Optional.', + }, + { + field: 'text', + label: 'loss', + value: '', + helperText: '', + }, + ], + when: "action=='loss'", + }, + { + field: 'text', + label: 'remoteCluster', + value: '', + helperText: 'Optional. RemoteCluster represents the remote cluster where the chaos will be deployed', + }, + { + field: 'ref', + label: 'target', + children: [ + { + field: 'text', + label: 'mode', + value: '', + helperText: + 'Mode defines the mode to run chaos action. Supported mode: one / all / fixed / fixed-percent / random-max-percent', + }, + { + field: 'ref', + label: 'selector', + children: [ + { + field: 'text-text', + label: 'annotationSelectors', + value: {}, + helperText: + 'Optional. Map of string keys and values that can be used to select objects. A selector based on annotations.', + }, + { + field: 'text-text', + label: 'fieldSelectors', + value: {}, + helperText: + 'Optional. Map of string keys and values that can be used to select objects. A selector based on fields.', + }, + { + field: 'text-text', + label: 'labelSelectors', + value: {}, + helperText: + 'Optional. Map of string keys and values that can be used to select objects. A selector based on labels.', + }, + { + field: 'label', + label: 'namespaces', + value: [], + helperText: 'Optional. Namespaces is a set of namespace to which objects belong.', + }, + { + field: 'text-text', + label: 'nodeSelectors', + value: {}, + helperText: + "Optional. Map of string keys and values that can be used to select nodes. Selector which must match a node's labels, and objects must belong to these selected nodes.", + }, + { + field: 'label', + label: 'nodes', + value: [], + helperText: 'Optional. Nodes is a set of node name and objects must belong to these nodes.', + }, + { + field: 'label', + label: 'podPhaseSelectors', + value: [], + helperText: + 'Optional. PodPhaseSelectors is a set of condition of a pod at the current time. supported value: Pending / Running / Succeeded / Failed / Unknown', + }, + { + field: 'text-label', + label: 'pods', + value: {}, + helperText: + 'Optional. Pods is a map of string keys and a set values that used to select pods. The key defines the namespace which pods belong, and the each values is a set of pod names.', + }, + ], + }, + { + field: 'text', + label: 'value', + value: '', + helperText: + 'Optional. Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. If `FixedMode`, provide an integer of pods to do chaos action. If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action', + }, + ], + }, + { + field: 'text', + label: 'targetDevice', + value: '', + helperText: 'Optional. TargetDevice represents the network device to be affected in target scope.', + }, + ] diff --git a/ui/app/src/formik/PhysicalMachineChaos.ts b/ui/app/src/formik/PhysicalMachineChaos.ts new file mode 100644 index 0000000000..977db5654a --- /dev/null +++ b/ui/app/src/formik/PhysicalMachineChaos.ts @@ -0,0 +1,1511 @@ +/** + * This file was auto-generated by @ui/openapi. + * Do not make direct changes to the file. + */ + +export const actions = [ + 'stress-cpu', + 'stress-mem', + 'disk-read-payload', + 'disk-write-payload', + 'disk-fill', + 'network-corrupt', + 'network-duplicate', + 'network-loss', + 'network-delay', + 'network-partition', + 'network-dns', + 'network-bandwidth', + 'network-flood', + 'network-down', + 'process', + 'jvm-exception', + 'jvm-gc', + 'jvm-latency', + 'jvm-return', + 'jvm-stress', + 'jvm-rule-data', + 'jvm-mysql', + 'clock', + 'redis-expiration', + 'redis-penetration', + 'redis-cacheLimit', + 'redis-restart', + 'redis-stop', + 'kafka-fill', + 'kafka-flood', + 'kafka-io', + 'file-create', + 'file-modify', + 'file-delete', + 'file-rename', + 'file-append', + 'file-replace', + 'vm', + 'user_defined', + ], + data = [ + { + field: 'label', + label: 'address', + value: [], + helperText: 'Optional. DEPRECATED: Use Selector instead. Only one of Address and Selector could be specified.', + }, + { + field: 'ref', + label: 'clock', + children: [ + { + field: 'text', + label: 'clock-ids-slice', + value: '', + helperText: + 'the identifier of the particular clock on which to act. More clock description in linux kernel can be found in man page of clock_getres, clock_gettime, clock_settime. Muti clock ids should be split with ","', + }, + { + field: 'number', + label: 'pid', + value: 0, + helperText: 'the pid of target program.', + }, + { + field: 'text', + label: 'time-offset', + value: '', + helperText: 'specifies the length of time offset.', + }, + ], + when: "action=='clock'", + }, + { + field: 'ref', + label: 'disk-fill', + children: [ + { + field: 'select', + label: 'fill-by-fallocate', + value: false, + items: [true, false], + helperText: 'fill disk by fallocate', + }, + { + field: 'text', + label: 'path', + value: '', + helperText: + 'specifies the location to fill data in. if path not provided, payload will read/write from/into a temp file, temp file will be deleted after writing', + }, + { + field: 'text', + label: 'size', + value: '', + helperText: + 'specifies how many units of data will write into the file path. support unit: c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 BYTES. example : 1M | 512kB', + }, + ], + when: "action=='disk-fill'", + }, + { + field: 'ref', + label: 'disk-read-payload', + children: [ + { + field: 'text', + label: 'path', + value: '', + helperText: + 'specifies the location to fill data in. if path not provided, payload will read/write from/into a temp file, temp file will be deleted after writing', + }, + { + field: 'number', + label: 'payload-process-num', + value: 0, + helperText: 'specifies the number of process work on writing, default 1, only 1-255 is valid value', + }, + { + field: 'text', + label: 'size', + value: '', + helperText: + 'specifies how many units of data will write into the file path. support unit: c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 BYTES. example : 1M | 512kB', + }, + ], + when: "action=='disk-read-payload'", + }, + { + field: 'ref', + label: 'disk-write-payload', + children: [ + { + field: 'text', + label: 'path', + value: '', + helperText: + 'specifies the location to fill data in. if path not provided, payload will read/write from/into a temp file, temp file will be deleted after writing', + }, + { + field: 'number', + label: 'payload-process-num', + value: 0, + helperText: 'specifies the number of process work on writing, default 1, only 1-255 is valid value', + }, + { + field: 'text', + label: 'size', + value: '', + helperText: + 'specifies how many units of data will write into the file path. support unit: c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 BYTES. example : 1M | 512kB', + }, + ], + when: "action=='disk-write-payload'", + }, + { + field: 'ref', + label: 'file-append', + children: [ + { + field: 'number', + label: 'count', + value: 0, + helperText: 'Count is the number of times to append the data.', + }, + { + field: 'text', + label: 'data', + value: '', + helperText: 'Data is the data for append.', + }, + { + field: 'text', + label: 'file-name', + value: '', + helperText: 'FileName is the name of the file to be created, modified, deleted, renamed, or appended.', + }, + ], + when: "action=='file-append'", + }, + { + field: 'ref', + label: 'file-create', + children: [ + { + field: 'text', + label: 'dir-name', + value: '', + helperText: 'DirName is the directory name to create or delete.', + }, + { + field: 'text', + label: 'file-name', + value: '', + helperText: 'FileName is the name of the file to be created, modified, deleted, renamed, or appended.', + }, + ], + when: "action=='file-create'", + }, + { + field: 'ref', + label: 'file-delete', + children: [ + { + field: 'text', + label: 'dir-name', + value: '', + helperText: 'DirName is the directory name to create or delete.', + }, + { + field: 'text', + label: 'file-name', + value: '', + helperText: 'FileName is the name of the file to be created, modified, deleted, renamed, or appended.', + }, + ], + when: "action=='file-delete'", + }, + { + field: 'ref', + label: 'file-modify', + children: [ + { + field: 'text', + label: 'file-name', + value: '', + helperText: 'FileName is the name of the file to be created, modified, deleted, renamed, or appended.', + }, + { + field: 'number', + label: 'privilege', + value: 0, + helperText: 'Privilege is the file privilege to be set.', + }, + ], + when: "action=='file-modify'", + }, + { + field: 'ref', + label: 'file-rename', + children: [ + { + field: 'text', + label: 'dest-file', + value: '', + helperText: 'DestFile is the name to be renamed.', + }, + { + field: 'text', + label: 'source-file', + value: '', + helperText: 'SourceFile is the name need to be renamed.', + }, + ], + when: "action=='file-create'", + }, + { + field: 'ref', + label: 'file-replace', + children: [ + { + field: 'text', + label: 'dest-string', + value: '', + helperText: 'DestStr is the destination string of the file.', + }, + { + field: 'text', + label: 'file-name', + value: '', + helperText: 'FileName is the name of the file to be created, modified, deleted, renamed, or appended.', + }, + { + field: 'number', + label: 'line', + value: 0, + helperText: 'Line is the line number of the file to be replaced.', + }, + { + field: 'text', + label: 'origin-string', + value: '', + helperText: 'OriginStr is the origin string of the file.', + }, + ], + when: "action=='file-replace'", + }, + { + field: 'ref', + label: 'http-abort', + children: [ + { + field: 'text', + label: 'code', + value: '', + helperText: 'Code is a rule to select target by http status code in response', + }, + { + field: 'text', + label: 'method', + value: '', + helperText: 'HTTP method', + }, + { + field: 'text', + label: 'path', + value: '', + helperText: 'Match path of Uri with wildcard matches', + }, + { + field: 'number', + label: 'port', + value: 0, + helperText: 'The TCP port that the target service listens on', + }, + { + field: 'numbers', + label: 'proxy_ports', + value: [], + helperText: + 'Composed with one of the port of HTTP connection, we will only attack HTTP connection with port inside proxy_ports', + }, + { + field: 'text', + label: 'target', + value: '', + helperText: 'HTTP target: Request or Response', + }, + ], + when: "action=='http-abort'", + }, + { + field: 'ref', + label: 'http-config', + children: [ + { + field: 'text', + label: 'file_path', + value: '', + helperText: 'The config file path', + }, + ], + when: "action=='http-config'", + }, + { + field: 'ref', + label: 'http-delay', + children: [ + { + field: 'text', + label: 'code', + value: '', + helperText: 'Code is a rule to select target by http status code in response', + }, + { + field: 'text', + label: 'delay', + value: '', + helperText: 'Delay represents the delay of the target request/response', + }, + { + field: 'text', + label: 'method', + value: '', + helperText: 'HTTP method', + }, + { + field: 'text', + label: 'path', + value: '', + helperText: 'Match path of Uri with wildcard matches', + }, + { + field: 'number', + label: 'port', + value: 0, + helperText: 'The TCP port that the target service listens on', + }, + { + field: 'numbers', + label: 'proxy_ports', + value: [], + helperText: + 'Composed with one of the port of HTTP connection, we will only attack HTTP connection with port inside proxy_ports', + }, + { + field: 'text', + label: 'target', + value: '', + helperText: 'HTTP target: Request or Response', + }, + ], + when: "action=='http-delay'", + }, + { + field: 'ref', + label: 'http-request', + children: [ + { + field: 'number', + label: 'count', + value: 0, + helperText: 'The number of requests to send', + }, + { + field: 'select', + label: 'enable-conn-pool', + value: false, + items: [true, false], + helperText: 'Enable connection pool', + }, + { + field: 'text', + label: 'url', + value: '', + helperText: 'Request to send"', + }, + ], + when: "action=='http-request'", + }, + { + field: 'ref', + label: 'jvm-exception', + children: [ + { + field: 'text', + label: 'class', + value: '', + helperText: 'Optional. Java class', + }, + { + field: 'text', + label: 'exception', + value: '', + helperText: 'the exception which needs to throw for action `exception`', + }, + { + field: 'text', + label: 'method', + value: '', + helperText: 'Optional. the method in Java class', + }, + { + field: 'number', + label: 'pid', + value: 0, + helperText: 'the pid of Java process which needs to attach', + }, + { + field: 'number', + label: 'port', + value: 0, + helperText: 'Optional. the port of agent server, default 9277', + }, + ], + when: "action=='jvm-exception'", + }, + { + field: 'ref', + label: 'jvm-gc', + children: [ + { + field: 'number', + label: 'pid', + value: 0, + helperText: 'the pid of Java process which needs to attach', + }, + { + field: 'number', + label: 'port', + value: 0, + helperText: 'Optional. the port of agent server, default 9277', + }, + ], + when: "action=='jvm-gc'", + }, + { + field: 'ref', + label: 'jvm-latency', + children: [ + { + field: 'text', + label: 'class', + value: '', + helperText: 'Optional. Java class', + }, + { + field: 'number', + label: 'latency', + value: 0, + helperText: "the latency duration for action 'latency', unit ms", + }, + { + field: 'text', + label: 'method', + value: '', + helperText: 'Optional. the method in Java class', + }, + { + field: 'number', + label: 'pid', + value: 0, + helperText: 'the pid of Java process which needs to attach', + }, + { + field: 'number', + label: 'port', + value: 0, + helperText: 'Optional. the port of agent server, default 9277', + }, + ], + when: "action=='jvm-latency'", + }, + { + field: 'ref', + label: 'jvm-mysql', + children: [ + { + field: 'text', + label: 'database', + value: '', + helperText: 'the match database default value is "", means match all database', + }, + { + field: 'text', + label: 'exception', + value: '', + helperText: + 'The exception which needs to throw for action `exception` or the exception message needs to throw in action `mysql`', + }, + { + field: 'number', + label: 'latency', + value: 0, + helperText: "The latency duration for action 'latency' or the latency duration in action `mysql`", + }, + { + field: 'text', + label: 'mysqlConnectorVersion', + value: '', + helperText: 'the version of mysql-connector-java, only support 5.X.X(set to "5") and 8.X.X(set to "8") now', + }, + { + field: 'number', + label: 'pid', + value: 0, + helperText: 'the pid of Java process which needs to attach', + }, + { + field: 'number', + label: 'port', + value: 0, + helperText: 'Optional. the port of agent server, default 9277', + }, + { + field: 'text', + label: 'sqlType', + value: '', + helperText: + "the match sql type default value is \"\", means match all SQL type. The value can be 'select', 'insert', 'update', 'delete', 'replace'.", + }, + { + field: 'text', + label: 'table', + value: '', + helperText: 'the match table default value is "", means match all table', + }, + ], + when: "action=='jvm-mysql'", + }, + { + field: 'ref', + label: 'jvm-return', + children: [ + { + field: 'text', + label: 'class', + value: '', + helperText: 'Optional. Java class', + }, + { + field: 'text', + label: 'method', + value: '', + helperText: 'Optional. the method in Java class', + }, + { + field: 'number', + label: 'pid', + value: 0, + helperText: 'the pid of Java process which needs to attach', + }, + { + field: 'number', + label: 'port', + value: 0, + helperText: 'Optional. the port of agent server, default 9277', + }, + { + field: 'text', + label: 'value', + value: '', + helperText: "the return value for action 'return'", + }, + ], + when: "action=='jvm-return'", + }, + { + field: 'ref', + label: 'jvm-rule-data', + children: [ + { + field: 'number', + label: 'pid', + value: 0, + helperText: 'the pid of Java process which needs to attach', + }, + { + field: 'number', + label: 'port', + value: 0, + helperText: 'Optional. the port of agent server, default 9277', + }, + { + field: 'text', + label: 'rule-data', + value: '', + helperText: "RuleData used to save the rule file's data, will use it when recover", + }, + ], + when: "action=='jvm-rule-data'", + }, + { + field: 'ref', + label: 'jvm-stress', + children: [ + { + field: 'number', + label: 'cpu-count', + value: 0, + helperText: 'the CPU core number need to use, only set it when action is stress', + }, + { + field: 'text', + label: 'mem-type', + value: '', + helperText: + "the memory type need to locate, only set it when action is stress, the value can be 'stack' or 'heap'", + }, + { + field: 'number', + label: 'pid', + value: 0, + helperText: 'the pid of Java process which needs to attach', + }, + { + field: 'number', + label: 'port', + value: 0, + helperText: 'Optional. the port of agent server, default 9277', + }, + ], + when: "action=='jvm-stress'", + }, + { + field: 'ref', + label: 'kafka-fill', + children: [ + { + field: 'text', + label: 'host', + value: '', + helperText: 'The host of kafka server', + }, + { + field: 'number', + label: 'maxBytes', + value: 0, + helperText: 'The max bytes to fill', + }, + { + field: 'number', + label: 'messageSize', + value: 0, + helperText: 'The size of each message', + }, + { + field: 'text', + label: 'password', + value: '', + helperText: 'The password of kafka client', + }, + { + field: 'number', + label: 'port', + value: 0, + helperText: 'The port of kafka server', + }, + { + field: 'text', + label: 'reloadCommand', + value: '', + helperText: 'The command to reload kafka config', + }, + { + field: 'text', + label: 'topic', + value: '', + helperText: 'The topic to attack', + }, + { + field: 'text', + label: 'username', + value: '', + helperText: 'The username of kafka client', + }, + ], + when: "action=='kafka-fill'", + }, + { + field: 'ref', + label: 'kafka-flood', + children: [ + { + field: 'text', + label: 'host', + value: '', + helperText: 'The host of kafka server', + }, + { + field: 'number', + label: 'messageSize', + value: 0, + helperText: 'The size of each message', + }, + { + field: 'text', + label: 'password', + value: '', + helperText: 'The password of kafka client', + }, + { + field: 'number', + label: 'port', + value: 0, + helperText: 'The port of kafka server', + }, + { + field: 'number', + label: 'threads', + value: 0, + helperText: 'The number of worker threads', + }, + { + field: 'text', + label: 'topic', + value: '', + helperText: 'The topic to attack', + }, + { + field: 'text', + label: 'username', + value: '', + helperText: 'The username of kafka client', + }, + ], + when: "action=='kafka-flood'", + }, + { + field: 'ref', + label: 'kafka-io', + children: [ + { + field: 'text', + label: 'configFile', + value: '', + helperText: 'The path of server config', + }, + { + field: 'select', + label: 'nonReadable', + value: false, + items: [true, false], + helperText: 'Make kafka cluster non-readable', + }, + { + field: 'select', + label: 'nonWritable', + value: false, + items: [true, false], + helperText: 'Make kafka cluster non-writable', + }, + { + field: 'text', + label: 'topic', + value: '', + helperText: 'The topic to attack', + }, + ], + when: "action=='kafka-io'", + }, + { + field: 'ref', + label: 'network-bandwidth', + children: [ + { + field: 'number', + label: 'buffer', + value: 0, + helperText: '', + }, + { + field: 'text', + label: 'device', + value: '', + helperText: '', + }, + { + field: 'text', + label: 'hostname', + value: '', + helperText: '', + }, + { + field: 'text', + label: 'ip-address', + value: '', + helperText: '', + }, + { + field: 'number', + label: 'limit', + value: 0, + helperText: '', + }, + { + field: 'number', + label: 'minburst', + value: 0, + helperText: '', + }, + { + field: 'number', + label: 'peakrate', + value: 0, + helperText: '', + }, + { + field: 'text', + label: 'rate', + value: '', + helperText: '', + }, + ], + when: "action=='network-bandwidth'", + }, + { + field: 'ref', + label: 'network-corrupt', + children: [ + { + field: 'text', + label: 'correlation', + value: '', + helperText: 'correlation is percentage (10 is 10%)', + }, + { + field: 'text', + label: 'device', + value: '', + helperText: 'the network interface to impact', + }, + { + field: 'text', + label: 'egress-port', + value: '', + helperText: + "only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. it can only be used in conjunction with -p tcp or -p udp", + }, + { + field: 'text', + label: 'hostname', + value: '', + helperText: 'only impact traffic to these hostnames', + }, + { + field: 'text', + label: 'ip-address', + value: '', + helperText: 'only impact egress traffic to these IP addresses', + }, + { + field: 'text', + label: 'ip-protocol', + value: '', + helperText: 'only impact traffic using this IP protocol, supported: tcp, udp, icmp, all', + }, + { + field: 'text', + label: 'percent', + value: '', + helperText: 'percentage of packets to corrupt (10 is 10%)', + }, + { + field: 'text', + label: 'source-port', + value: '', + helperText: + "only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. it can only be used in conjunction with -p tcp or -p udp", + }, + ], + when: "action=='network-corrupt'", + }, + { + field: 'ref', + label: 'network-delay', + children: [ + { + field: 'text', + label: 'accept-tcp-flags', + value: '', + helperText: + 'only the packet which match the tcp flag can be accepted, others will be dropped. only set when the IPProtocol is tcp, used for partition.', + }, + { + field: 'text', + label: 'correlation', + value: '', + helperText: 'correlation is percentage (10 is 10%)', + }, + { + field: 'text', + label: 'device', + value: '', + helperText: 'the network interface to impact', + }, + { + field: 'text', + label: 'egress-port', + value: '', + helperText: + "only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. it can only be used in conjunction with -p tcp or -p udp", + }, + { + field: 'text', + label: 'hostname', + value: '', + helperText: 'only impact traffic to these hostnames', + }, + { + field: 'text', + label: 'ip-address', + value: '', + helperText: 'only impact egress traffic to these IP addresses', + }, + { + field: 'text', + label: 'ip-protocol', + value: '', + helperText: 'only impact traffic using this IP protocol, supported: tcp, udp, icmp, all', + }, + { + field: 'text', + label: 'jitter', + value: '', + helperText: 'jitter time, time units: ns, us (or \u00B5s), ms, s, m, h.', + }, + { + field: 'text', + label: 'latency', + value: '', + helperText: 'delay egress time, time units: ns, us (or \u00B5s), ms, s, m, h.', + }, + { + field: 'text', + label: 'source-port', + value: '', + helperText: + "only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. it can only be used in conjunction with -p tcp or -p udp", + }, + ], + when: "action=='network-delay'", + }, + { + field: 'ref', + label: 'network-dns', + children: [ + { + field: 'text', + label: 'dns-domain-name', + value: '', + helperText: 'map this host to specified IP', + }, + { + field: 'text', + label: 'dns-ip', + value: '', + helperText: 'map specified host to this IP address', + }, + { + field: 'text', + label: 'dns-server', + value: '', + helperText: 'update the DNS server in /etc/resolv.conf with this value', + }, + ], + when: "action=='network-dns'", + }, + { + field: 'ref', + label: 'network-down', + children: [ + { + field: 'text', + label: 'device', + value: '', + helperText: 'The network interface to impact', + }, + { + field: 'text', + label: 'duration', + value: '', + helperText: 'NIC down time, time units: ns, us (or \u00B5s), ms, s, m, h.', + }, + ], + when: "action=='network-down'", + }, + { + field: 'ref', + label: 'network-duplicate', + children: [ + { + field: 'text', + label: 'correlation', + value: '', + helperText: 'correlation is percentage (10 is 10%)', + }, + { + field: 'text', + label: 'device', + value: '', + helperText: 'the network interface to impact', + }, + { + field: 'text', + label: 'egress-port', + value: '', + helperText: + "only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. it can only be used in conjunction with -p tcp or -p udp", + }, + { + field: 'text', + label: 'hostname', + value: '', + helperText: 'only impact traffic to these hostnames', + }, + { + field: 'text', + label: 'ip-address', + value: '', + helperText: 'only impact egress traffic to these IP addresses', + }, + { + field: 'text', + label: 'ip-protocol', + value: '', + helperText: 'only impact traffic using this IP protocol, supported: tcp, udp, icmp, all', + }, + { + field: 'text', + label: 'percent', + value: '', + helperText: 'percentage of packets to duplicate (10 is 10%)', + }, + { + field: 'text', + label: 'source-port', + value: '', + helperText: + "only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. it can only be used in conjunction with -p tcp or -p udp", + }, + ], + when: "action=='network-duplicate'", + }, + { + field: 'ref', + label: 'network-flood', + children: [ + { + field: 'text', + label: 'duration', + value: '', + helperText: 'The number of seconds to run the iperf test', + }, + { + field: 'text', + label: 'ip-address', + value: '', + helperText: 'Generate traffic to this IP address', + }, + { + field: 'number', + label: 'parallel', + value: 0, + helperText: 'The number of iperf parallel client threads to run', + }, + { + field: 'text', + label: 'port', + value: '', + helperText: 'Generate traffic to this port on the IP address', + }, + { + field: 'text', + label: 'rate', + value: '', + helperText: + 'The speed of network traffic, allows bps, kbps, mbps, gbps, tbps unit. bps means bytes per second', + }, + ], + when: "action=='network-flood'", + }, + { + field: 'ref', + label: 'network-loss', + children: [ + { + field: 'text', + label: 'correlation', + value: '', + helperText: 'correlation is percentage (10 is 10%)', + }, + { + field: 'text', + label: 'device', + value: '', + helperText: 'the network interface to impact', + }, + { + field: 'text', + label: 'egress-port', + value: '', + helperText: + "only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. it can only be used in conjunction with -p tcp or -p udp", + }, + { + field: 'text', + label: 'hostname', + value: '', + helperText: 'only impact traffic to these hostnames', + }, + { + field: 'text', + label: 'ip-address', + value: '', + helperText: 'only impact egress traffic to these IP addresses', + }, + { + field: 'text', + label: 'ip-protocol', + value: '', + helperText: 'only impact traffic using this IP protocol, supported: tcp, udp, icmp, all', + }, + { + field: 'text', + label: 'percent', + value: '', + helperText: 'percentage of packets to loss (10 is 10%)', + }, + { + field: 'text', + label: 'source-port', + value: '', + helperText: + "only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. it can only be used in conjunction with -p tcp or -p udp", + }, + ], + when: "action=='network-loss'", + }, + { + field: 'ref', + label: 'network-partition', + children: [ + { + field: 'text', + label: 'accept-tcp-flags', + value: '', + helperText: + 'only the packet which match the tcp flag can be accepted, others will be dropped. only set when the IPProtocol is tcp, used for partition.', + }, + { + field: 'text', + label: 'device', + value: '', + helperText: 'the network interface to impact', + }, + { + field: 'text', + label: 'direction', + value: '', + helperText: + "specifies the partition direction, values can be 'from', 'to'. 'from' means packets coming from the 'IPAddress' or 'Hostname' and going to your server, 'to' means packets originating from your server and going to the 'IPAddress' or 'Hostname'.", + }, + { + field: 'text', + label: 'hostname', + value: '', + helperText: 'only impact traffic to these hostnames', + }, + { + field: 'text', + label: 'ip-address', + value: '', + helperText: 'only impact egress traffic to these IP addresses', + }, + { + field: 'text', + label: 'ip-protocol', + value: '', + helperText: 'only impact egress traffic to these IP addresses', + }, + ], + when: "action=='network-partition'", + }, + { + field: 'ref', + label: 'process', + children: [ + { + field: 'text', + label: 'process', + value: '', + helperText: 'the process name or the process ID', + }, + { + field: 'text', + label: 'recoverCmd', + value: '', + helperText: 'the command to be run when recovering experiment', + }, + { + field: 'number', + label: 'signal', + value: 0, + helperText: 'the signal number to send', + }, + ], + when: "action=='process'", + }, + { + field: 'ref', + label: 'redis-cacheLimit', + children: [ + { + field: 'text', + label: 'addr', + value: '', + helperText: 'The adress of Redis server', + }, + { + field: 'text', + label: 'cacheSize', + value: '', + helperText: 'The size of `maxmemory`', + }, + { + field: 'text', + label: 'password', + value: '', + helperText: 'The password of Redis server', + }, + { + field: 'text', + label: 'percent', + value: '', + helperText: 'Specifies maxmemory as a percentage of the original value', + }, + ], + when: "action=='redis-cacheLimit'", + }, + { + field: 'ref', + label: 'redis-expiration', + children: [ + { + field: 'text', + label: 'addr', + value: '', + helperText: 'The adress of Redis server', + }, + { + field: 'text', + label: 'expiration', + value: '', + helperText: 'The expiration of the keys', + }, + { + field: 'text', + label: 'key', + value: '', + helperText: 'The keys to be expired', + }, + { + field: 'text', + label: 'option', + value: '', + helperText: 'Additional options for `expiration`', + }, + { + field: 'text', + label: 'password', + value: '', + helperText: 'The password of Redis server', + }, + ], + when: "action=='redis-expiration'", + }, + { + field: 'ref', + label: 'redis-penetration', + children: [ + { + field: 'text', + label: 'addr', + value: '', + helperText: 'The adress of Redis server', + }, + { + field: 'text', + label: 'password', + value: '', + helperText: 'The password of Redis server', + }, + { + field: 'number', + label: 'requestNum', + value: 0, + helperText: 'The number of requests to be sent', + }, + ], + when: "action=='redis-penetration'", + }, + { + field: 'ref', + label: 'redis-restart', + children: [ + { + field: 'text', + label: 'addr', + value: '', + helperText: 'The adress of Redis server', + }, + { + field: 'text', + label: 'conf', + value: '', + helperText: 'The path of Sentinel conf', + }, + { + field: 'select', + label: 'flushConfig', + value: false, + items: [true, false], + helperText: 'The control flag determines whether to flush config', + }, + { + field: 'text', + label: 'password', + value: '', + helperText: 'The password of Redis server', + }, + { + field: 'select', + label: 'redisPath', + value: false, + items: [true, false], + helperText: 'The path of `redis-server` command-line tool', + }, + ], + when: "action=='redis-restart'", + }, + { + field: 'ref', + label: 'redis-stop', + children: [ + { + field: 'text', + label: 'addr', + value: '', + helperText: 'The adress of Redis server', + }, + { + field: 'text', + label: 'conf', + value: '', + helperText: 'The path of Sentinel conf', + }, + { + field: 'select', + label: 'flushConfig', + value: false, + items: [true, false], + helperText: 'The control flag determines whether to flush config', + }, + { + field: 'text', + label: 'password', + value: '', + helperText: 'The password of Redis server', + }, + { + field: 'select', + label: 'redisPath', + value: false, + items: [true, false], + helperText: 'The path of `redis-server` command-line tool', + }, + ], + when: "action=='redis-stop'", + }, + { + field: 'text', + label: 'remoteCluster', + value: '', + helperText: 'Optional. RemoteCluster represents the remote cluster where the chaos will be deployed', + }, + { + field: 'ref', + label: 'stress-cpu', + children: [ + { + field: 'number', + label: 'load', + value: 0, + helperText: + 'specifies P percent loading per CPU worker. 0 is effectively a sleep (no load) and 100 is full loading.', + }, + { + field: 'label', + label: 'options', + value: [], + helperText: 'extend stress-ng options', + }, + { + field: 'number', + label: 'workers', + value: 0, + helperText: 'specifies N workers to apply the stressor.', + }, + ], + when: "action=='stress-cpu'", + }, + { + field: 'ref', + label: 'stress-mem', + children: [ + { + field: 'label', + label: 'options', + value: [], + helperText: 'extend stress-ng options', + }, + { + field: 'text', + label: 'size', + value: '', + helperText: + 'specifies N bytes consumed per vm worker, default is the total available memory. One can specify the size as % of total available memory or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB..', + }, + ], + when: "action=='stress-mem'", + }, + { + field: 'ref', + label: 'user_defined', + children: [ + { + field: 'text', + label: 'attackCmd', + value: '', + helperText: 'The command to be executed when attack', + }, + { + field: 'text', + label: 'recoverCmd', + value: '', + helperText: 'The command to be executed when recover', + }, + ], + when: "action=='user_defined'", + }, + { + field: 'ref', + label: 'vm', + children: [ + { + field: 'text', + label: 'vm-name', + value: '', + helperText: 'The name of the VM to be injected', + }, + ], + when: "action=='vm'", + }, + ] diff --git a/ui/app/src/formik/PodChaos.ts b/ui/app/src/formik/PodChaos.ts new file mode 100644 index 0000000000..14d75d3640 --- /dev/null +++ b/ui/app/src/formik/PodChaos.ts @@ -0,0 +1,28 @@ +/** + * This file was auto-generated by @ui/openapi. + * Do not make direct changes to the file. + */ + +export const actions = ['pod-kill', 'pod-failure', 'container-kill'], + data = [ + { + field: 'label', + label: 'containerNames', + value: [], + helperText: + 'Optional. ContainerNames indicates list of the name of affected container. If not set, the first container will be injected', + }, + { + field: 'number', + label: 'gracePeriod', + value: 0, + helperText: + 'Optional. GracePeriod is used in pod-kill action. It represents the duration in seconds before the pod should be deleted. Value must be non-negative integer. The default value is zero that indicates delete immediately.', + }, + { + field: 'text', + label: 'remoteCluster', + value: '', + helperText: 'Optional. RemoteCluster represents the remote cluster where the chaos will be deployed', + }, + ] diff --git a/ui/app/src/formik/StressChaos.ts b/ui/app/src/formik/StressChaos.ts new file mode 100644 index 0000000000..97c7864a53 --- /dev/null +++ b/ui/app/src/formik/StressChaos.ts @@ -0,0 +1,93 @@ +/** + * This file was auto-generated by @ui/openapi. + * Do not make direct changes to the file. + */ + +export const actions = [], + data = [ + { + field: 'label', + label: 'containerNames', + value: [], + helperText: + 'Optional. ContainerNames indicates list of the name of affected container. If not set, the first container will be injected', + }, + { + field: 'text', + label: 'remoteCluster', + value: '', + helperText: 'Optional. RemoteCluster represents the remote cluster where the chaos will be deployed', + }, + { + field: 'text', + label: 'stressngStressors', + value: '', + helperText: + "Optional. StressngStressors defines plenty of stressors just like `Stressors` except that it's an experimental feature and more powerful. You can define stressors in `stress-ng` (see also `man stress-ng`) dialect, however not all of the supported stressors are well tested. It maybe retired in later releases. You should always use `Stressors` to define the stressors and use this only when you want more stressors unsupported by `Stressors`. When both `StressngStressors` and `Stressors` are defined, `StressngStressors` wins.", + }, + { + field: 'ref', + label: 'stressors', + children: [ + { + field: 'ref', + label: 'cpu', + children: [ + { + field: 'number', + label: 'load', + value: 0, + helperText: + 'Optional. Load specifies P percent loading per CPU worker. 0 is effectively a sleep (no load) and 100 is full loading.', + }, + { + field: 'label', + label: 'options', + value: [], + helperText: 'Optional. extend stress-ng options', + }, + { + field: 'number', + label: 'workers', + value: 0, + helperText: + 'Workers specifies N workers to apply the stressor. Maximum 8192 workers can run by stress-ng', + }, + ], + }, + { + field: 'ref', + label: 'memory', + children: [ + { + field: 'number', + label: 'oomScoreAdj', + value: 0, + helperText: + 'Optional. OOMScoreAdj sets the oom_score_adj of the stress process. See `man 5 proc` to know more about this option.', + }, + { + field: 'label', + label: 'options', + value: [], + helperText: 'Optional. extend stress-ng options', + }, + { + field: 'text', + label: 'size', + value: '', + helperText: + 'Optional. Size specifies N bytes consumed per vm worker, default is the total available memory. One can specify the size as % of total available memory or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.', + }, + { + field: 'number', + label: 'workers', + value: 0, + helperText: + 'Workers specifies N workers to apply the stressor. Maximum 8192 workers can run by stress-ng', + }, + ], + }, + ], + }, + ] diff --git a/ui/app/src/formik/TimeChaos.ts b/ui/app/src/formik/TimeChaos.ts new file mode 100644 index 0000000000..01b56c9008 --- /dev/null +++ b/ui/app/src/formik/TimeChaos.ts @@ -0,0 +1,35 @@ +/** + * This file was auto-generated by @ui/openapi. + * Do not make direct changes to the file. + */ + +export const actions = [], + data = [ + { + field: 'label', + label: 'clockIds', + value: [], + helperText: + 'ClockIds defines all affected clock id All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", "CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", "CLOCK_BOOTTIME_ALARM"] Default value is ["CLOCK_REALTIME"]', + }, + { + field: 'label', + label: 'containerNames', + value: [], + helperText: + 'Optional. ContainerNames indicates list of the name of affected container. If not set, the first container will be injected', + }, + { + field: 'text', + label: 'remoteCluster', + value: '', + helperText: 'Optional. RemoteCluster represents the remote cluster where the chaos will be deployed', + }, + { + field: 'text', + label: 'timeOffset', + value: '', + helperText: + 'TimeOffset defines the delta time of injected program. It\'s a possibly signed sequence of decimal numbers, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "\u00B5s"), "ms", "s", "m", "h".', + }, + ] diff --git a/ui/app/src/formik/actions.ts b/ui/app/src/formik/actions.ts new file mode 100644 index 0000000000..49e3ee741d --- /dev/null +++ b/ui/app/src/formik/actions.ts @@ -0,0 +1,61 @@ +/** + * This file was auto-generated by @ui/openapi. + * Do not make direct changes to the file. + */ + +const actions = { + AWSChaos: ['ec2-stop', 'ec2-restart', 'detach-volume'], + DNSChaos: ['error', 'random'], + GCPChaos: ['node-stop', 'node-reset', 'disk-loss'], + HTTPChaos: [], + IOChaos: ['latency', 'fault', 'attrOverride', 'mistake'], + JVMChaos: ['latency', 'return', 'exception', 'stress', 'gc', 'ruleData', 'mysql'], + KernelChaos: [], + NetworkChaos: ['netem', 'delay', 'loss', 'duplicate', 'corrupt', 'partition', 'bandwidth'], + PhysicalMachineChaos: [ + 'stress-cpu', + 'stress-mem', + 'disk-read-payload', + 'disk-write-payload', + 'disk-fill', + 'network-corrupt', + 'network-duplicate', + 'network-loss', + 'network-delay', + 'network-partition', + 'network-dns', + 'network-bandwidth', + 'network-flood', + 'network-down', + 'process', + 'jvm-exception', + 'jvm-gc', + 'jvm-latency', + 'jvm-return', + 'jvm-stress', + 'jvm-rule-data', + 'jvm-mysql', + 'clock', + 'redis-expiration', + 'redis-penetration', + 'redis-cacheLimit', + 'redis-restart', + 'redis-stop', + 'kafka-fill', + 'kafka-flood', + 'kafka-io', + 'file-create', + 'file-modify', + 'file-delete', + 'file-rename', + 'file-append', + 'file-replace', + 'vm', + 'user_defined', + ], + PodChaos: ['pod-kill', 'pod-failure', 'container-kill'], + StressChaos: [], + TimeChaos: [], +} + +export default actions diff --git a/ui/app/src/i18n/en.json b/ui/app/src/i18n/en.json new file mode 100644 index 0000000000..9fc9701ee6 --- /dev/null +++ b/ui/app/src/i18n/en.json @@ -0,0 +1,408 @@ +{ + "dashboard": { + "title": "Dashboard", + "tutorial": { + "title": "Tutorial", + "desc": "📖 Take a quick look at the functions of Chaos Mesh Dashboard", + "steps": { + "dashboard": "Dashboard is an overview of Chaos Mesh, where you can observe the running status of all experiments.", + "workflows": "Workflows manage all workflows. Here you can organize multiple experiments to simulate more realistic failures.", + "schedules": "Schedules manage all schedules. Here you can run an experiment periodically.", + "experiments": "Experiments manage all experiments, where you can perform various operations (pause, update, archive, etc.) on the experiment.", + "events": "Events show all the events generated.", + "archives": "Archives show all archived workflows, schedules, and experiments.", + "newW": "You can start your first workflow from here.", + "newS": "You can start your first schedule from here.", + "newE": "You can start your first experiment from here.", + "search": "Search provides multiple syntaxes to help you locate workflows, schedules, and experiments quickly.", + "namespace": "Browse the respective objects by selecting the different namespace.", + "predefined": "Predefined can store custom schedules and experiments for quick execution.", + "end": "🎉 Congratulations on completing all the tutorial steps! Click the blank space to exit." + } + }, + "newbie": "Newbie", + "newbieDesc": "⛑ Quickly inject a fault from a simple experiment", + "startAWorkflow": "Start with workflow", + "startAWorkflowDesc": "Workflow allows you to organize multiple experiments to simulate more realistic failures", + "startASchedule": "Start with schedule", + "startAScheduleDesc": "Schedule allows you to run an experiment periodically", + "totalStatus": "Total Experiments Status", + "predefined": "Predefined", + "predefinedDesc": "📦 Store custom experiments here for quick execution", + "noPredefinedFound": "No predefined found", + "recent": "Recent Events" + }, + "newE": { + "title": "New experiment", + "titleStep1": "Inject into", + "titleStep2": "Experiment Info", + "steps": { + "basic": "Metadata", + "scope": "Scope", + "run": "Run" + }, + "loadFrom": "Load from", + "byYAML": "By YAML", + "byYAMLDesc": "Create an experiment or schedule by filling in or uploading YAML", + "basic": { + "nameHelper": "Fill the experiment name.", + "namespaceHelper": "Select the namespace" + }, + "scope": { + "namespaceSelectorsHelper": "Specifies the namespaces to which target Pods belong.", + "labelSelectorsHelper": "Specifies the labels that target Pods come with.", + "annotationSelectorsHelper": "Specifies the annotations that target Pods come with.", + "phaseSelectorsHelper": "Specifies the phases of target Pods.", + "mode": "Mode", + "modeHelper": "Specifies the mode of the experiment.", + "modeValue": "Mode Value", + "modeValueHelper": "Please fill the mode value", + "targetPodsPreview": "Preview of Pods to be injected", + "targetPodsPreviewHelper": "Checking or unchecking Pods to further limit the scope.", + "noPodsFound": "No Pods found.", + "targetPhysicalMachinesPreview": "Preview of physical machines to be injected", + "targetPhysicalMachinesPreviewHelper": "Checking or unchecking physical machines to further limit the scope.", + "noPhysicalMachinesFound": "No physical machines found." + }, + "target": { + "kind": "Kind", + "action": "Action", + "aws": { + "title": "AWS Fault" + }, + "block": { + "title": "Block Fault" + }, + "disk": { + "title": "Disk Fault" + }, + "dns": { + "title": "DNS Fault" + }, + "gcp": { + "title": "GCP Fault" + }, + "io": { + "title": "IO Injection" + }, + "jvm": { + "title": "JVM Fault" + }, + "kernel": { + "title": "Kernel Fault" + }, + "network": { + "title": "Network Attack", + "target": { + "title": "Target", + "podsPreview": "Target Pods Preview" + } + }, + "http": { + "title": "HTTP Fault" + }, + "physicalmachine": { + "title": "Physic Fault" + }, + "pod": { + "title": "Pod Fault" + }, + "process": { + "title": "Process interruption" + }, + "stress": { + "title": "Stress Test" + }, + "time": { + "title": "Clock Skew" + } + }, + "run": { + "continuous": "Run continuously" + }, + "complete": "All steps are completed" + }, + "experiments": { + "title": "Experiments", + "single": "Experiment", + "notFound": "No experiments found", + "createdAt": "Created", + "deleteMulti": "Archive selected experiments", + "deleteDesc": "You can still find this experiment in the archives", + "pauseDesc": "You can restart the experiment in the same position", + "startDesc": "The operation will take effect immediately" + }, + "newW": { + "title": "New Workflow", + "titleBasic": "Workflow info", + "node": { + "choose": "Choose task type", + "single": "Single", + "serial": "Serial", + "parallel": "Parallel", + "suspend": "Suspend", + "custom": "Task", + "http": "HTTP Request", + "number": "Number", + "child": "Child task", + "nameHelper": "Fill the node name.", + "nameValidation": "The node name is required.", + "deadline": "Deadline", + "deadlineHelper": "The node will end within the deadline. Supported formats of the deadline are: ms / s / m / h.", + "deadlineValidation": "The node deadline is required.", + "container": { + "title": "Container", + "nameHelper": "The container name", + "nameValidation": "The container name is required", + "image": "Image", + "imageHelper": "The image of container", + "imageValidation": "The image is required", + "command": "Command", + "commandHelper": "Optional. Specifies the command running in the container, enter the string and ends Enter to create a single command." + }, + "conditionalBranches": { + "title": "Conditional branches (Optional)", + "branch": "Branch", + "target": "Target", + "expression": "Expression" + }, + "httpRequest": { + "url": "URL", + "urlHelper": "Request URL", + "method": "Method", + "methodHelper": "Request Method", + "body": "Body", + "bodyHelper": "Request Body", + "follow": "Follow 301/302 Location", + "json": "Json Content" + }, + "deleteDesc": "This task will be deleted", + "submitAll": "Submit All" + }, + "serialTitle": "Set serial", + "parallelTitle": "Set parallel", + "suspendTitle": "Set suspend", + "customTitle": "Set task", + "httpTitle": "Set HTTP Request", + "nameHelper": "The workflow name", + "nameValidation": "The workflow name is required", + "durationValidation": "The workflow duration is required", + "submit": "Submit workflow", + "messages": { + "m1": "Please complete the creation of the previous task first", + "m2": "Please fill in the current branch first", + "redundant": "Duplicate names detected, please create templates with unique names" + } + }, + "newS": { + "title": "New Schedule", + "titleStep2": "Fill the schedule info", + "basic": { + "nameHelper": "The schedule name", + "scheduleHelper": "The schedule is expressed in the form of CronJob. If you are not familiar with it, you can use {crontabguru} to help define it.", + "historyLimitHelper": "Maximum number of experiment records.", + "concurrencyPolicyHelper": "Whether to allow experiments to run at the same time.", + "forbid": "Forbid", + "allow": "Allow", + "startingDeadlineSecondsHelper": "Counts how many missed jobs occurred from the value of startingDeadlineSeconds until now." + } + }, + "schedules": { + "title": "Schedules", + "single": "Schedule", + "notFound": "No schedules found", + "deleteMulti": "Archive selected schedules", + "deleteDesc": "You can still find this schedule in the archives" + }, + "workflows": { + "title": "Workflows", + "notFound": "No workflows found", + "deleteDesc": "You can still find this workflow in the archives." + }, + "workflow": { + "entry": "Entry", + "time": "Time", + "status": "Status", + "topology": "Topology" + }, + "events": { + "title": "Events", + "notFound": "No events found", + "eventsPerPage": "Events per page", + "event": { + "uuid": "UUID", + "namespace": "Namespace", + "name": "name", + "kind": "Kind", + "started": "Started", + "message": "Message" + } + }, + "archives": { + "title": "Archives", + "single": "Archive", + "notFound": "No archives found", + "deleteMulti": "Delete selected archives", + "deleteDesc": "The Archive will be permanently deleted" + }, + "physics": { + "title": "Hosts", + "single": "Hosts", + "notFound": "No hosts found" + }, + "settings": { + "title": "Settings", + "debugMode": { + "title": "Debug mode", + "choose": "Creating an experiment doesn't send a real HTTP request, but prints the relevant information in the console." + }, + "enableKubeSystemNS": { + "title": "Allow kube-system namespace", + "choose": "The kube-system namespace is allowed to be selected in the scope when creating an experiment." + }, + "useNewPhysicalMachineCRD": { + "title": "Use new PhysicalMachine CRD", + "choose": "When creating PhysicalMachineChaos, retrieve the available PhysicalMachines instead of providing the address field." + }, + "useNextWorkflowInterface": { + "title": "Use the next generation of workflow interface", + "choose": "Over the past period of time, we have refactored the interface related to workflows. Now you can create workflows more easily in the form of the flowchart. (Note: This improvement is still under active development and the interface is still subject to change until it is stable.)" + }, + "theme": { + "title": "Theme", + "choose": "Choose a theme.", + "light": "Light", + "dark": "Dark" + }, + "lang": { + "title": "Language", + "choose": "Choose the interface language.", + "en": "English", + "zh": "Chinese" + }, + "addToken": { + "prompt": "Enter the token (RBAC Authorization) to continue", + "prompt2": "Don't know how to get the token?", + "prompt3": " Click here to generate", + "generator": "Token generator", + "generatorHelper": "👇 Generate different tokens by choosing different namespaces and roles.", + "generatorHelper2": "1. After choosing, save below content as rbac.yaml.", + "generatorHelper3": "2. Then run the following command:", + "generatorHelperGetTokenHeader": "3. Get the token", + "generatorHelperGetTokenCase1": "If you are using Kubernetes 1.24+, you need to create the token manually:", + "generatorHelperGetTokenCase2": "Else the token is generated automatically, you can view it with:", + "clustered": "Cluster scoped", + "role": "Role", + "roleHelper": "Choose role", + "nameHelper": "Please fill the token name", + "nameValidation": "The token name is required", + "token": "Token", + "tokenHelper": "Please fill the secret token", + "tokenValidation": "The token is required", + "duplicateDesc": "Token name can't be duplicate", + "or": "Or use the following authentication methods", + "gcp": "Currently signed in with Google" + } + }, + "swagger": { + "title": "Swagger API" + }, + "search": { + "placeholder": "Search", + "tip": { + "title": "Use the following syntax to quickly locate workflows, schedules, experiments and archives:", + "namespace": "namespace:default xxx / ns:default xxx will search for workflows, schedules, experiments and archives with namespace default", + "kind": "kind:NetworkChaos xxx will search for schedules, experiments and archives with kind NetworkChaos" + }, + "result": { + "acquiring": "Acquiring...", + "noResult": "No result" + } + }, + "common": { + "add": "Add", + "moreOptions": "More Options", + "batchOperation": "Batch operation", + "cancel": "Cancel", + "cancelEdit": "Cancel edit", + "chooseNamespace": "Choose namespace", + "close": "Close", + "configuration": "Configuration", + "confirm": "Confirm", + "copied": "Copied!", + "copy": "Copy", + "definition": "Definition", + "delete": "Delete", + "deleteDesc": "This operation is irreversible.", + "detail": "Detail", + "doc": "Documentation", + "download": "Download", + "duration": "Duration", + "durationHelper": "Supported formats of the duration are: ms / s / m / h.", + "edit": "Edit", + "ip": "IP address", + "isKVHelperText": "Type key:value and end with Enter to generate a key/value pair.", + "logout": "Logout", + "logoutDesc": "You need to re-enter the token after logging out", + "multiOptions": "Support mutiple options", + "name": "Name", + "noOptions": "No options", + "operation": "Operation", + "options": "Options", + "pause": "Pause", + "preview": "Preview", + "process": "Process", + "seconds": "s", + "selectAll": "Select all", + "start": "Start", + "state": "State", + "status": "Status", + "submit": "Submit", + "timeline": "Timeline", + "tutorial": "Tutorial", + "update": "Update", + "upload": "Upload", + "use": "Use", + "using": "Using", + "uuid": "UUID", + "version": "Version" + }, + "table": { + "created": "Created at" + }, + "status": { + "injecting": "Injecting", + "running": "Running", + "finished": "Completed", + "paused": "Paused", + "failed": "Failed", + "deleting": "Deleting", + "unknown": "Unknown" + }, + "confirm": { + "success": { + "archive": "Archived successfully", + "create": "Created successfully", + "delete": "Deleted successfully", + "load": "Loaded successfully", + "pause": "Paused successfully", + "update": "Updated successfully", + "start": "Started successfully", + "submit": "Submitted successfully" + } + }, + "k8s": { + "title": "Kubernetes", + "namespace": "Namespace", + "labels": "Labels", + "annotations": "Annotations", + "namespaceSelectors": "Namespace Selectors", + "labelSelectors": "Label Selectors", + "annotationSelectors": "Annotation Selectors", + "podPhaseSelectors": "Phase Selectors" + }, + "physic": { + "address": "Address", + "addressHelper": "Type and end with Enter to add one or more chaosd addresses." + } +} diff --git a/ui/app/src/i18n/messages.ts b/ui/app/src/i18n/messages.ts new file mode 100644 index 0000000000..2a3ddd5771 --- /dev/null +++ b/ui/app/src/i18n/messages.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import en from './en.json' +import zh from './zh.json' + +const messages: Record = { + en, + zh, +} + +export default messages diff --git a/ui/app/src/i18n/zh.json b/ui/app/src/i18n/zh.json new file mode 100644 index 0000000000..bf731abbd8 --- /dev/null +++ b/ui/app/src/i18n/zh.json @@ -0,0 +1,409 @@ +{ + "dashboard": { + "title": "仪表盘", + "tutorial": { + "title": "教程", + "desc": "📖 快速浏览 Chaos Mesh Dashboard 的各项功能", + "steps": { + "dashboard": "仪表盘是对 Chaos Mesh 的概览,这里你可以观察到所有实验的运行状态。", + "workflows": "工作流页面管理着所有的工作流。这里允许你编排多个实验来模拟更加真实的故障。", + "schedules": "计划页面管理着所有的计划。这里允许你周期性地运行一个实验。", + "experiments": "实验页面管理着所有的实验,这里你可以对实验进行多种操作(暂停,更新,归档等)。", + "events": "事件页面展示了所有产生的事件。", + "archives": "归档页面展示了所有已归档的工作流,计划和实验。", + "newW": "你可以在这里开始你的第一个工作流。", + "newS": "你可以在这里开始你的第一个计划。", + "newE": "你可以在这里开始你的第一个实验。", + "search": "搜索提供了多种语法来帮助你快速地定位工作流,计划和实验。", + "namespace": "通过选择不同的命名空间来浏览各自的对象。", + "predefined": "预定义可以存储自定义的计划和实验,方便快速执行。", + "end": "🎉 恭喜你完成了所有的教程步骤!点击空白处即可退出。" + } + }, + "newbie": "新手", + "newbieDesc": "⛑ 从一个简单的实验开始快速注入一个故障", + "startAWorkflow": "从工作流开始", + "startAWorkflowDesc": "工作流允许你编排多个实验来模拟更加真实的故障", + "startASchedule": "从计划开始", + "startAScheduleDesc": "计划允许你周期性地运行一个实验", + "totalStatus": "当前实验状态", + "predefined": "预定义", + "predefinedDesc": "📦 在这里存储自定义的实验以快速执行", + "noPredefinedFound": "未发现预定义", + "recent": "最近事件" + }, + "newE": { + "title": "新的实验", + "titleStep1": "注入到", + "titleStep2": "实验信息", + "steps": { + "basic": "元信息", + "scope": "范围", + "run": "运行" + }, + "loadFrom": "加载自", + "byYAML": "通过 YAML", + "byYAMLDesc": "通过填写或上传 YAML 的方式创建实验或计划", + "basic": { + "nameHelper": "实验的名称", + "namespaceHelper": "选择命名空间" + }, + "scope": { + "namespaceSelectorsHelper": "指定目标 Pod 所属的命名空间(namespace)。", + "labelSelectorsHelper": "指定目标 Pod 带有的标签(label)。", + "annotationSelectorsHelper": "指定目标 Pod 带有的注解(annotation)。", + "phaseSelectorsHelper": "指定目标 Pod 所处的阶段(phase)。", + "mode": "模式", + "modeHelper": "选择实验模式", + "modeValue": "模式值", + "modeValueHelper": "请填写模式值", + "targetPodsPreview": "预览目标 Pod", + "targetPodsPreviewHelper": "通过勾选 Pod 来进一步限制范围", + "noPodsFound": "未发现 Pod", + "targetPhysicalMachinesPreview": "预览目标物理机", + "targetPhysicalMachinesPreviewHelper": "通过勾选物理机来进一步限制范围", + "noPhysicalMachinesFound": "未发现物理机" + }, + "target": { + "kind": "类别", + "action": "行为", + "aws": { + "title": "AWS 故障" + }, + "disk": { + "title": "磁盘故障" + }, + "dns": { + "title": "DNS 故障" + }, + "gcp": { + "title": "GCP 故障" + }, + "io": { + "title": "文件系统注入" + }, + "jvm": { + "title": "JVM 故障" + }, + "block": { + "title": "块存储故障" + }, + "kernel": { + "title": "内核故障" + }, + "network": { + "title": "网络攻击", + "target": { + "title": "目标", + "podsPreview": "预览目标 Pod" + } + }, + "http": { + "title": "HTTP 故障" + }, + "physicalmachine": { + "title": "物理机故障" + }, + "pod": { + "title": "Pod 故障" + }, + "process": { + "title": "进程中断" + }, + "stress": { + "title": "压力测试" + }, + "time": { + "title": "时钟偏移" + } + }, + "run": { + "continuous": "持续运行" + }, + "complete": "所有步骤已完成" + }, + "experiments": { + "title": "实验", + "single": "实验", + "notFound": "未发现实验", + "deleteMulti": "归档所选实验", + "deleteDesc": "你仍然可以在归档中找到此实验", + "pauseDesc": "你可以在同一位置重启这个实验", + "startDesc": "此操作将立即生效" + }, + "newS": { + "title": "新的计划", + "titleStep2": "填写计划信息", + "basic": { + "nameHelper": "计划的名称", + "scheduleHelper": "计划以 CronJob 的形式表示。如果你还不熟悉它,可以借助 {crontabguru} 来辅助制定计划。", + "historyLimitHelper": "最大实验记录数。", + "concurrencyPolicyHelper": "是否允许实验同时运行。", + "forbid": "禁止", + "allow": "允许", + "startingDeadlineSecondsHelper": "统计从 startingDeadlineSeconds 设置的值到现在错过了多少次 job。" + } + }, + "schedules": { + "title": "计划", + "single": "计划", + "notFound": "未发现计划", + "deleteMulti": "归档所选计划", + "deleteDesc": "你仍然可以在归档中找到此计划" + }, + "newW": { + "title": "新的工作流", + "titleBasic": "工作流信息", + "node": { + "choose": "选择任务类型", + "single": "单一", + "serial": "串行", + "parallel": "并行", + "suspend": "暂停", + "custom": "自定义", + "http": "HTTP 请求", + "number": "数目", + "child": "子任务", + "nameHelper": "任务的名称", + "nameValidation": "任务名称不能为空", + "deadline": "超时时间", + "deadlineHelper": "任务将会在超时时间内结束。超时时间支持的格式有:ms / s / m / h。", + "deadlineValidation": "任务的超时时间不能为空", + "container": { + "title": "容器", + "nameHelper": "容器的名称", + "nameValidation": "容器名称不能为空", + "image": "镜像", + "imageHelper": "容器的镜像", + "imageValidation": "镜像不能为空", + "command": "命令", + "commandHelper": "可选项。指定在容器中运行的命令,输入字符串并以回车结束来创建单条命令。" + }, + "conditionalBranches": { + "title": "条件分支(可选)", + "branch": "分支", + "target": "目标", + "expression": "表达式" + }, + "httpRequest": { + "url": "URL", + "urlHelper": "请求 URL", + "method": "Method", + "methodHelper": "请求方法", + "body": "Body", + "bodyHelper": "请求体", + "follow": "跟随 301/302 跳转", + "json": "为 JSON 内容" + }, + "deleteDesc": "此任务将被删除", + "submitAll": "提交所有改动" + }, + "serialTitle": "填写串行任务", + "parallelTitle": "填写并行任务", + "suspendTitle": "设置暂停", + "customTitle": "自定义任务", + "httpTitle": "HTTP 请求", + "nameHelper": "工作流的名称", + "nameValidation": "工作流名称不能为空", + "durationValidation": "工作流持续时间不能为空", + "submit": "提交工作流", + "messages": { + "m1": "请先完成上一个任务的创建", + "m2": "请先填写当前分支", + "redundant": "检测到重复命名,请使用唯一的名称创建模版" + } + }, + "workflows": { + "title": "工作流", + "notFound": "未发现工作流", + "deleteDesc": "你仍然可以在归档中找到此工作流" + }, + "workflow": { + "entry": "入口", + "time": "时间", + "status": { + "Succeed": "完成" + }, + "topology": "拓扑" + }, + "events": { + "title": "事件", + "notFound": "未发现事件", + "eventsPerPage": "每页事件数", + "event": { + "uuid": "UUID", + "namespace": "命名空间", + "name": "名称", + "kind": "类别", + "started": "开始时间", + "message": "信息" + } + }, + "archives": { + "title": "归档", + "single": "归档", + "notFound": "未发现归档", + "deleteMulti": "删除所选归档", + "deleteDesc": "归档将被永久删除" + }, + "physics": { + "title": "物理机", + "single": "物理机", + "notFound": "未发现物理机" + }, + "settings": { + "title": "设置", + "debugMode": { + "title": "调试模式", + "choose": "创建实验不会发送真正的 HTTP 请求,而是将相关信息打印在控制台中。" + }, + "enableKubeSystemNS": { + "title": "允许 kube-system 命名空间", + "choose": "在创建实验时允许在范围内选择 kube-system 命名空间。" + }, + "useNewPhysicalMachineCRD": { + "title": "使用新的 PhysicalMachine CRD", + "choose": "创建 PhysicalMachineChaos 时,检索可用的 PhysicalMachines 而不是提供地址字段。" + }, + "useNextWorkflowInterface": { + "title": "使用全新的工作流界面", + "choose": "在过去的一段时间里,我们将工作流的相关界面进行了重构。现在你可以通过流程图的形式来更加方便地创建工作流。(注意:这项改进仍处于活跃地开发状态中,在它稳定前界面仍有可能会发生变动。)" + }, + "theme": { + "title": "主题", + "choose": "选择主题。", + "light": "浅色", + "dark": "暗色" + }, + "lang": { + "title": "语言", + "choose": "选择界面语言。", + "en": "英语", + "zh": "简体中文" + }, + "addToken": { + "prompt": "输入令牌(RBAC 鉴权)以继续", + "prompt2": "不知道如何获取令牌?", + "prompt3": "点击这里生成", + "generator": "令牌辅助生成器", + "generatorHelper": "👇 通过选择不同的命名空间和角色生成不同的令牌。", + "generatorHelper2": "1. 选择后,将以下内容另存为 rbac.yaml。", + "generatorHelper3": "2. 然后运行如下命令:", + "generatorHelperGetTokenHeader": "3. 获取令牌", + "generatorHelperGetTokenCase1": "如果您使用的 Kubernetes 版本高于 1.24,您需要手动生成令牌:", + "generatorHelperGetTokenCase2": "否则令牌已经自动生成,请通过如下命令查看:", + "clustered": "集群范围", + "role": "角色", + "roleHelper": "选择角色", + "nameHelper": "请输入令牌名称", + "nameValidation": "令牌名称不能为空", + "token": "令牌", + "tokenHelper": "请输入令牌", + "tokenValidation": "令牌不能为空", + "duplicateDesc": "令牌名称不能重复", + "or": "或者使用以下方式鉴权", + "gcp": "当前使用 Google 登录" + } + }, + "swagger": { + "title": "Swagger API" + }, + "search": { + "placeholder": "搜索", + "tip": { + "title": "使用以下语法来快速定位工作流,计划,实验和归档:", + "namespace": "namespace:default xxx / ns:default xxx 将搜索命名空间为 default 的工作流,计划,实验和归档", + "kind": "kind:NetworkChaos xxx 将搜索类型为 NetworkChaos 的计划,实验和归档" + }, + "result": { + "acquiring": "获取中...", + "noResult": "没有结果" + } + }, + "common": { + "add": "添加", + "moreOptions": "更多选项", + "batchOperation": "批量操作", + "cancel": "取消", + "cancelEdit": "取消修改", + "chooseNamespace": "选择命名空间", + "close": "关闭", + "configuration": "配置", + "confirm": "确认", + "copied": "已复制!", + "copy": "复制", + "definition": "定义", + "delete": "删除", + "deleteDesc": "此操作不可逆", + "detail": "详情", + "doc": "文档", + "download": "下载", + "duration": "持续时间", + "durationHelper": "持续时间支持的格式有:ms / s / m / h。", + "edit": "修改", + "ip": "IP 地址", + "isKVHelperText": "键入 key:value 并以回车结束来创建一个键值对。", + "logout": "登出", + "logoutDesc": "登出后需要重新输入令牌", + "multiOptions": "支持多选", + "name": "名称", + "noOptions": "无选项", + "operation": "操作", + "options": "选项", + "pause": "暂停", + "preview": "预览", + "process": "流程", + "seconds": "秒", + "selectAll": "全选", + "start": "启动", + "state": "状态", + "status": "状态", + "submit": "提交", + "timeline": "时间线", + "tutorial": "教程", + "update": "更新", + "upload": "上传", + "use": "使用", + "using": "使用中", + "uuid": "UUID", + "version": "版本" + }, + "table": { + "created": "创建于" + }, + "status": { + "injecting": "注入中", + "running": "运行中", + "finished": "完成", + "paused": "暂停", + "failed": "失败", + "deleting": "删除中", + "unknown": "未知" + }, + "confirm": { + "success": { + "archive": "归档成功", + "create": "创建成功", + "delete": "删除成功", + "load": "加载成功", + "pause": "暂停成功", + "update": "更新成功", + "start": "启动成功", + "submit": "提交成功" + } + }, + "k8s": { + "title": "Kubernetes", + "namespace": "命名空间", + "labels": "标签", + "annotations": "注解", + "namespaceSelectors": "命名空间选择器", + "labelSelectors": "标签选择器", + "annotationSelectors": "注解选择器", + "podPhaseSelectors": "阶段选择器" + }, + "physic": { + "address": "地址", + "addressHelper": "键入并以回车结束来添加一个或多个 chaosd 地址" + } +} diff --git a/ui/src/images/assets/undraw_empty_street-dark.svg b/ui/app/src/images/assets/undraw_empty_street-dark.svg similarity index 93% rename from ui/src/images/assets/undraw_empty_street-dark.svg rename to ui/app/src/images/assets/undraw_empty_street-dark.svg index 6637dabd1b..c9f3339572 100644 --- a/ui/src/images/assets/undraw_empty_street-dark.svg +++ b/ui/app/src/images/assets/undraw_empty_street-dark.svg @@ -1 +1,17 @@ + \ No newline at end of file diff --git a/ui/src/images/assets/undraw_empty_street.svg b/ui/app/src/images/assets/undraw_empty_street.svg similarity index 93% rename from ui/src/images/assets/undraw_empty_street.svg rename to ui/app/src/images/assets/undraw_empty_street.svg index 6e0fba431f..aaeb9f4a12 100644 --- a/ui/src/images/assets/undraw_empty_street.svg +++ b/ui/app/src/images/assets/undraw_empty_street.svg @@ -1 +1,17 @@ + \ No newline at end of file diff --git a/ui/app/src/images/assets/undraw_not_found.svg b/ui/app/src/images/assets/undraw_not_found.svg new file mode 100644 index 0000000000..15e5d5615f --- /dev/null +++ b/ui/app/src/images/assets/undraw_not_found.svg @@ -0,0 +1 @@ +not found \ No newline at end of file diff --git a/ui/src/images/chaos/aws.svg b/ui/app/src/images/chaos/aws.svg similarity index 84% rename from ui/src/images/chaos/aws.svg rename to ui/app/src/images/chaos/aws.svg index 0c165fb0a0..689624d951 100644 --- a/ui/src/images/chaos/aws.svg +++ b/ui/app/src/images/chaos/aws.svg @@ -1,4 +1,20 @@ + diff --git a/ui/app/src/images/chaos/disk.svg b/ui/app/src/images/chaos/disk.svg new file mode 100644 index 0000000000..8ed59bfb40 --- /dev/null +++ b/ui/app/src/images/chaos/disk.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/app/src/images/chaos/dns.svg b/ui/app/src/images/chaos/dns.svg new file mode 100644 index 0000000000..33a20b29f7 --- /dev/null +++ b/ui/app/src/images/chaos/dns.svg @@ -0,0 +1,22 @@ + + + + + + + diff --git a/ui/app/src/images/chaos/gcp.svg b/ui/app/src/images/chaos/gcp.svg new file mode 100644 index 0000000000..9885af3581 --- /dev/null +++ b/ui/app/src/images/chaos/gcp.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/app/src/images/chaos/http.svg b/ui/app/src/images/chaos/http.svg new file mode 100644 index 0000000000..99b358eaf7 --- /dev/null +++ b/ui/app/src/images/chaos/http.svg @@ -0,0 +1 @@ + diff --git a/ui/src/images/chaos/io.svg b/ui/app/src/images/chaos/io.svg similarity index 76% rename from ui/src/images/chaos/io.svg rename to ui/app/src/images/chaos/io.svg index 5d10f69cbc..d75eb1bfc7 100644 --- a/ui/src/images/chaos/io.svg +++ b/ui/app/src/images/chaos/io.svg @@ -1,3 +1,19 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/src/images/chaos/kernel.svg b/ui/app/src/images/chaos/kernel.svg similarity index 85% rename from ui/src/images/chaos/kernel.svg rename to ui/app/src/images/chaos/kernel.svg index 481f05726f..5c86fcacb8 100644 --- a/ui/src/images/chaos/kernel.svg +++ b/ui/app/src/images/chaos/kernel.svg @@ -1,3 +1,19 @@ + diff --git a/ui/src/images/chaos/pod.svg b/ui/app/src/images/chaos/pod.svg similarity index 86% rename from ui/src/images/chaos/pod.svg rename to ui/app/src/images/chaos/pod.svg index 064073c043..56449aa527 100644 --- a/ui/src/images/chaos/pod.svg +++ b/ui/app/src/images/chaos/pod.svg @@ -1,4 +1,20 @@ + diff --git a/ui/app/src/images/chaos/stress.svg b/ui/app/src/images/chaos/stress.svg new file mode 100644 index 0000000000..41318945bc --- /dev/null +++ b/ui/app/src/images/chaos/stress.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/app/src/images/chaos/time.svg b/ui/app/src/images/chaos/time.svg new file mode 100644 index 0000000000..80e1a5ed2a --- /dev/null +++ b/ui/app/src/images/chaos/time.svg @@ -0,0 +1,17 @@ + + diff --git a/ui/app/src/images/k8s.svg b/ui/app/src/images/k8s.svg new file mode 100644 index 0000000000..a304208102 --- /dev/null +++ b/ui/app/src/images/k8s.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/src/images/logo-mini-white.svg b/ui/app/src/images/logo-mini-white.svg similarity index 90% rename from ui/src/images/logo-mini-white.svg rename to ui/app/src/images/logo-mini-white.svg index 5a20daf73c..5fcb1116cf 100644 --- a/ui/src/images/logo-mini-white.svg +++ b/ui/app/src/images/logo-mini-white.svg @@ -1 +1,17 @@ + diff --git a/ui/src/images/logo-mini.svg b/ui/app/src/images/logo-mini.svg similarity index 90% rename from ui/src/images/logo-mini.svg rename to ui/app/src/images/logo-mini.svg index 3304a4c608..e148467f8d 100644 --- a/ui/src/images/logo-mini.svg +++ b/ui/app/src/images/logo-mini.svg @@ -1 +1,17 @@ + \ No newline at end of file diff --git a/ui/app/src/images/logo-white.svg b/ui/app/src/images/logo-white.svg new file mode 100644 index 0000000000..09d02c4d4e --- /dev/null +++ b/ui/app/src/images/logo-white.svg @@ -0,0 +1,17 @@ + + diff --git a/ui/app/src/images/logo.svg b/ui/app/src/images/logo.svg new file mode 100644 index 0000000000..1018beb289 --- /dev/null +++ b/ui/app/src/images/logo.svg @@ -0,0 +1,17 @@ + + diff --git a/ui/app/src/images/physic.svg b/ui/app/src/images/physic.svg new file mode 100644 index 0000000000..7bcd133588 --- /dev/null +++ b/ui/app/src/images/physic.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/app/src/index.tsx b/ui/app/src/index.tsx new file mode 100644 index 0000000000..83ce546adf --- /dev/null +++ b/ui/app/src/index.tsx @@ -0,0 +1,27 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import App from './App' +import React from 'react' +import ReactDOM from 'react-dom' + +ReactDOM.render( + + + , + document.getElementById('root') +) diff --git a/ui/app/src/lib/byKind.tsx b/ui/app/src/lib/byKind.tsx new file mode 100644 index 0000000000..22082e3568 --- /dev/null +++ b/ui/app/src/lib/byKind.tsx @@ -0,0 +1,118 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import LinearScaleIcon from '@mui/icons-material/LinearScale' +import TimelapseIcon from '@mui/icons-material/Timelapse' +import { SvgIcon } from '@mui/material' + +import { ExperimentKind } from 'components/NewExperiment/types' +import i18n from 'components/T' + +import { ReactComponent as AWSIcon } from 'images/chaos/aws.svg' +import { ReactComponent as DiskIcon } from 'images/chaos/disk.svg' +import { ReactComponent as DNSIcon } from 'images/chaos/dns.svg' +import { ReactComponent as GCPIcon } from 'images/chaos/gcp.svg' +import { ReactComponent as HTTPIcon } from 'images/chaos/http.svg' +import { ReactComponent as FileSystemIOIcon } from 'images/chaos/io.svg' +import { ReactComponent as JavaIcon } from 'images/chaos/java.svg' +import { ReactComponent as LinuxKernelIcon } from 'images/chaos/kernel.svg' +import { ReactComponent as NetworkIcon } from 'images/chaos/network.svg' +import { ReactComponent as PodLifecycleIcon } from 'images/chaos/pod.svg' +import { ReactComponent as ProcessIcon } from 'images/chaos/process.svg' +import { ReactComponent as StressIcon } from 'images/chaos/stress.svg' +import { ReactComponent as ClockIcon } from 'images/chaos/time.svg' +import { ReactComponent as K8SIcon } from 'images/k8s.svg' +import { ReactComponent as PhysicIcon } from 'images/physic.svg' + +export function iconByKind(kind: string, size: 'small' | 'inherit' | 'medium' | 'large' = 'medium') { + let icon + + switch (kind) { + case 'k8s': + icon = + break + case 'physic': + case 'PhysicalMachineChaos': + icon = + break + case 'AWSChaos': + icon = + break + case 'BlockChaos': + // TODO: add icon for BlockChaos + icon = + break + case 'DiskChaos': + icon = + break + case 'DNSChaos': + icon = + break + case 'GCPChaos': + icon = + break + case 'IOChaos': + icon = + break + case 'HTTPChaos': + icon = + break + case 'JVMChaos': + icon = + break + case 'KernelChaos': + icon = + break + case 'NetworkChaos': + icon = + break + case 'PodChaos': + icon = + break + case 'ProcessChaos': + icon = + break + case 'StressChaos': + icon = + break + case 'TimeChaos': + case 'Schedule': + icon = + break + case 'Serial': + return + case 'Parallel': + return + case 'Suspend': + return + } + + return {icon} +} + +export function transByKind(kind: ExperimentKind | 'Workflow' | 'Schedule') { + let id: string + + if (kind === 'Workflow') { + id = 'workflows.title' + } else if (kind === 'Schedule') { + id = 'schedules.title' + } else { + id = `newE.target.${kind.replace('Chaos', '').toLowerCase()}.title` + } + + return i18n(id) +} diff --git a/ui/app/src/lib/cytoscape.ts b/ui/app/src/lib/cytoscape.ts new file mode 100644 index 0000000000..13bcbe8289 --- /dev/null +++ b/ui/app/src/lib/cytoscape.ts @@ -0,0 +1,316 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Theme } from '@mui/material' +import { Node, WorkflowSingle } from 'api/workflows.type' +import cytoscape, { EdgeDefinition, EventHandler, NodeDefinition, Stylesheet } from 'cytoscape' +import dagre from 'cytoscape-dagre' +import _ from 'lodash' + +cytoscape.use(dagre) + +type RecursiveNodeDefinition = NodeDefinition | Array + +function generateWorkflowNodes(detail: WorkflowSingle) { + const { entry, topology } = detail + let entryNode: Node + const nodeMap = new Map( + topology.nodes.map((n) => { + if (n.template === entry) { + entryNode = n + } + + return [n.name, n] + }) + ) + function toCytoscapeNode(node: Node): RecursiveNodeDefinition { + const { name, type, state, template } = node + + if (type === 'SerialNode' && node.serial!.length) { + return [type, node.serial!.filter((d) => d.name).map((d) => toCytoscapeNode(nodeMap.get(d.name)!)), node.name] + } else if (type === 'ParallelNode' && node.parallel!.length) { + return [type, node.parallel!.filter((d) => d.name).map((d) => toCytoscapeNode(nodeMap.get(d.name)!)), node.name] + } else if (type === 'TaskNode' && node.conditional_branches?.length) { + return [ + type, + node.conditional_branches!.filter((d) => d.name).map((d) => toCytoscapeNode(nodeMap.get(d.name)!)), + node.name, + ] + } else { + return { + data: { + id: name, + type, + state, + template, + }, + classes: state, + } + } + } + + return [toCytoscapeNode(entryNode!)] +} + +function mergeStates(nodes: NodeDefinition[]) { + if (nodes.every((n) => n.data.state === 'Succeed')) { + return 'Succeed' + } + + return undefined +} + +// function connectSerial(edges: EdgeDefinition[], id: string, serial: RecursiveNodeDefinition[]) { +// const length = serial.length +// const first = serial[0] +// const last = serial[length - 1] + +// if (!Array.isArray(first) && !Array.isArray(last)) { +// edges.push({ +// data: { +// id, +// source: first.data.id!, +// target: last.data.id!, +// }, +// classes: 'bezier', +// }) +// } +// } + +function generateWorkflowEdges( + result: EdgeDefinition[], + connections: NodeDefinition[], + nodes: RecursiveNodeDefinition[] +) { + let source = nodes[0] as NodeDefinition + + // source != single node + if (Array.isArray(source)) { + const type = source[0] + + if (type === 'SerialNode') { + generateWorkflowEdges(result, connections, [...source[1], ...nodes.slice(1)]) + + // connectSerial(result, source[2], source[1]) + } else if (type === 'ParallelNode' || type === 'TaskNode') { + const c = { + data: { + id: `parallel-connection-${source[2]}`, + }, + classes: 'connection', + } + + ;(source[1] as NodeDefinition[]).forEach((d) => { + if (nodes.length >= 1) { + generateWorkflowEdges(result, connections, [d, c]) + } + }) + + connections.push(c) + + generateWorkflowEdges(result, connections, [c, ...nodes.slice(1)]) + } + } else { + // source = single node + const _nodes = nodes.slice(1) + + for (let i = 0; i < _nodes.length; i++) { + const sourceID = source.data.id! + const n = _nodes[i] + + // N (target) != single node + if (Array.isArray(n)) { + const target = n + const type = target[0] + + if (type === 'SerialNode') { + generateWorkflowEdges(result, connections, [ + source, + ...(target[1] as RecursiveNodeDefinition[]), + ...nodes.slice(i + 2), + ]) + + // connectSerial(result, target[2] as string, target[1] as NodeDefinition[]) + + break + } else if (type === 'ParallelNode') { + const c1 = { + data: { + id: `parallel-connection-${target[2]}`, + }, + classes: 'connection', + } + + // eslint-disable-next-line no-loop-func + ;(target[1] as NodeDefinition[]).forEach((d) => { + generateWorkflowEdges(result, connections, [source, d]) + generateWorkflowEdges(result, connections, [d, c1]) + }) + + generateWorkflowEdges(result, connections, [c1, ...nodes.slice(i + 2)]) + + connections.push(c1) + + break + } + } else { + // N (target) = single node + result.push({ + data: { + id: `${sourceID}-to-${n.data.id!}`, + source: sourceID, + target: n.data.id!, + }, + classes: mergeStates([source, n]), + }) + + source = n + } + } + } +} + +export const constructWorkflowTopology = ( + container: HTMLElement, + detail: WorkflowSingle, + theme: Theme, + onNodeClick: EventHandler +) => { + const workflowNodeStyle = { + width: 24, + height: 24, + color: theme.palette.text.primary, + opacity: 0, + 'background-color': theme.palette.grey[500], + 'text-margin-y': '-12px', + 'text-opacity': 0.87, + label: 'data(id)', + } + + const workflowStyle: Stylesheet[] = [ + { + selector: 'node', + style: workflowNodeStyle, + }, + { + selector: 'node.Succeed', + style: { + 'background-color': theme.palette.success.main, + }, + }, + { + selector: 'node.connection', + style: { + content: '', + }, + }, + { + selector: 'edge', + style: { + width: 3, + opacity: 0, + 'line-color': theme.palette.grey[500], + 'line-opacity': 0.38, + 'curve-style': 'taxi', + 'taxi-turn': '50%', + } as any, + }, + { + selector: 'edge.Succeed', + style: { + 'line-color': theme.palette.success.main, + }, + }, + { + selector: 'edge.bezier', + style: { + 'curve-style': 'bezier', + 'control-point-step-size': 40, + }, + }, + ] + + function generateElements(detail: WorkflowSingle) { + let nodes = generateWorkflowNodes(detail)! + const edges = [] as EdgeDefinition[] + const connections = [] as NodeDefinition[] + generateWorkflowEdges(edges, connections, nodes) + nodes = nodes.concat(connections) + + return { + nodes: _.flattenDeep(nodes).filter((d) => typeof d !== 'string') as NodeDefinition[], + edges: edges, + } + } + + const layout = { + name: 'dagre', + fit: false, + rankDir: 'LR', + nodeSep: 250, + minLen: 9, + } as any + + const animateOptions = (style: any) => ({ + style, + easing: 'ease-in-out' as 'ease-in-out', + }) + + const cy = cytoscape({ + container, + style: workflowStyle, + minZoom: 0.5, + maxZoom: 1.5, + }) + .pan({ x: 250, y: 250 }) + .zoom(0.75) + .on('click', 'node', function (e) { + if (e.target.hasClass('connection')) { + return + } + + onNodeClick(e) + }) + + let flashRunning: number + function updateElements(detail: WorkflowSingle) { + clearInterval(flashRunning) + flashRunning = window.setInterval(() => { + const nodes = cy.$('node.Running') + + if (nodes.length) { + nodes + .animate(animateOptions({ 'background-opacity': 0.12 }), { duration: 750 }) + .animate(animateOptions({ 'background-opacity': 1 }), { duration: 750 }) + } else { + clearInterval(flashRunning) + } + }, 2000) + + const elements = generateElements(detail) + cy.json({ + elements, + }) + cy.layout(layout).run() + + cy.elements().animate(animateOptions({ opacity: 1 }), { duration: 500 }) + cy.center() + } + + updateElements(detail) + + return { updateElements } +} diff --git a/ui/app/src/lib/d3/eventsChart.tsx b/ui/app/src/lib/d3/eventsChart.tsx new file mode 100644 index 0000000000..789f7199aa --- /dev/null +++ b/ui/app/src/lib/d3/eventsChart.tsx @@ -0,0 +1,317 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Box, Typography } from '@mui/material' +import * as d3 from 'd3' +import _ from 'lodash' +import { CoreEvent as Event } from 'openapi/index.schemas' +import { renderToString } from 'react-dom/server' + +import { Theme } from 'slices/settings' + +import DateTime, { format, now } from 'lib/luxon' + +import wrapText from './wrapText' + +/** + * The gen function generates the timeline of the events and returns an update function. + * + * @export + * @param {{ + * root: HTMLElement + * events: Event[] + * theme: Theme + * options?: { + * enableLegends?: boolean + * onSelectEvent?: (e: Event) => () => void + * } + * }} { + * root, + * events, + * intl, + * theme, + * options = { + * enableLegends: true, + * }, + * } + * @returns {gen~update} - Receive new events and update the chart. + */ +export default function gen({ + root, + events, + theme, + options = { + enableLegends: true, + }, +}: { + root: HTMLElement + events: Event[] + theme: Theme + options?: { + enableLegends?: boolean + onSelectEvent?: (e: Event) => () => void + } +}) { + const { enableLegends, onSelectEvent } = options + + let width = root.offsetWidth + const height = root.offsetHeight + + const margin = { + top: 0, + right: 0, + bottom: 30, + left: 0, + } + updateMargin() + + function updateMargin() { + margin.right = enableLegends && document.documentElement.offsetWidth > 768 ? 150 : 0 + } + + const halfHourLater = (events.length ? DateTime.fromISO(events[0].created_at!) : now()).plus({ + hours: 0.5, + }) + + const colorPalette = d3 + .scaleOrdinal() + .range(d3.schemeTableau10) + .domain(events.map((d) => d.object_id!)) + + const allUniqueExperiments = [...new Set(events.map((d) => d.name + '/' + d.object_id))].map((d) => { + const [name, uuid] = d.split('/') + + return { + name, + uuid, + } + }) + const allUniqueUUIDs = allUniqueExperiments.map((d) => d.uuid) + + let zoom: d3.ZoomBehavior + + const svg = d3 + .select(root) + .append('svg') + .attr('class', `chaos-chart${theme === 'light' ? '' : ' dark'}`) + .attr('width', width) + .attr('height', height) + + const x = d3 + .scaleLinear() + .range([margin.left, width - margin.right]) + .domain([halfHourLater.minus({ hours: 1 }), halfHourLater]) + let newX = x + const xAxis = d3 + .axisBottom(x) + .ticks(6) + .tickFormat(d3.timeFormat('%m-%d %H:%M') as any) + const gXAxis = svg + .append('g') + .attr('class', 'axis') + .attr('transform', `translate(0, ${height - margin.bottom})`) + .call(xAxis) + + // Wrap long text, also used in zoomed() and reGen() + gXAxis.selectAll('.tick text').call(wrapText, 30) + + const y = d3 + .scaleBand() + .range([0, height - margin.top - margin.bottom]) + .domain(allUniqueUUIDs) + .padding(0.5) + // gYAxisLeft + svg + .append('g') + .attr('class', 'axis') + .attr('transform', `translate(${margin.left}, ${margin.top})`) + .append('line') + .attr('stroke-width', 2) + .attr('y1', margin.top) + .attr('y2', height - 30) + const gYAxisRight = svg + .append('g') + .attr('class', 'axis') + .attr('transform', `translate(${width - margin.right + 0.5}, ${margin.top})`) + gYAxisRight + .append('line') + .attr('y1', margin.top) + .attr('y2', height - 30) + + const timelines = svg + .append('g') + .attr('transform', `translate(${margin.left}, ${margin.top})`) + .attr('stroke-opacity', 0.24) + .selectAll() + .data(allUniqueUUIDs) + .join('line') + .attr('y1', (d) => y(d)! + y.bandwidth() / 2) + .attr('y2', (d) => y(d)! + y.bandwidth() / 2) + .attr('x2', width - margin.right - margin.left) + .attr('stroke', colorPalette) + + // clipX + svg + .append('clipPath') + .attr('id', 'clip-x-axis') + .append('rect') + .attr('x', margin.left) + .attr('y', 0) + .attr('width', width - margin.left - margin.right) + .attr('height', height - margin.bottom) + const gMain = svg.append('g').attr('clip-path', 'url(#clip-x-axis)') + + // legends + const legendsRoot = d3 + .select(document.createElement('div')) + .attr('class', `chaos-events-legends${theme === 'light' ? '' : ' dark'}`) + if (enableLegends) { + legends() + } + function legends() { + const legends = legendsRoot + .selectAll() + .data(allUniqueExperiments) + .enter() + .append('div') + .on('click', function (_, d) { + const _events = events.filter((e) => e.object_id === d.uuid) + const event = _events[0] + + svg + .transition() + .duration(750) + .call( + zoom.transform, + d3.zoomIdentity + .translate((width - margin.left - margin.right) / 2, 0) + .scale(3) + .translate(-x(DateTime.fromISO(event.created_at!)), 0) + ) + }) + legends + .append('div') + .attr('class', 'square') + .attr('style', (d) => `background: ${colorPalette(d.uuid)};`) + legends + .insert('div') + .attr('class', 'experiment') + .attr('title', (d) => d.name) + .text((d) => _.truncate(d.name)) + } + + const tooltip = d3 + .select(document.createElement('div')) + .attr('class', `chaos-event-tooltip${theme === 'light' ? '' : ' dark'}`) + + function genTooltipContent(d: Event) { + return renderToString( + + {d.name} + {format(d.created_at!)} + + {d.message} + + + ) + } + + if (enableLegends) { + root.appendChild(legendsRoot.node()!) + } + root.style.position = 'relative' + root.appendChild(tooltip.node()!) + + /** + * Receive new events and update the chart. + * + * @param {Event[]} events + */ + function update(events: Event[]) { + const circles = gMain + .selectAll('circle') + .data(events) + .join((enter) => { + const newCx = (d: Event) => newX(DateTime.fromISO(d.created_at!)) + + return enter + .append('circle') + .attr('opacity', 0) + .attr('cx', (d) => newCx(d) + 30) + .call((enter) => enter.transition().duration(750).attr('opacity', 1).attr('cx', newCx)) + }) + .attr('cy', (d) => y(d.object_id!)! + y.bandwidth() / 2 + margin.top) + .attr('fill', (d) => colorPalette(d.object_id!)) + .attr('r', 4) + .style('cursor', 'pointer') + .on('click', (_, d) => { + if (typeof onSelectEvent === 'function') { + onSelectEvent(d)() + } + }) + .on('mouseover', function (event, d) { + let [x, y] = d3.pointer(event) + + tooltip.html(genTooltipContent(d)) + const { width } = tooltip.node()!.getBoundingClientRect() + + y += 50 + if (x > (root.offsetWidth / 3) * 2) { + x -= width + } + if (y > (root.offsetHeight / 3) * 2) { + y -= 200 + } + + tooltip + .style('left', x + 'px') + .style('top', y + 'px') + .style('opacity', 1) + .style('z-index', 'unset') + }) + .on('mouseleave', () => tooltip.style('opacity', 0).style('z-index', -1)) + + function zoomed({ transform }: d3.D3ZoomEvent) { + newX = transform.rescaleX(x) + + gXAxis.call(xAxis.scale(newX)) + gXAxis.selectAll('.tick text').call(wrapText, 30) + circles.attr('cx', (d) => newX(DateTime.fromISO(d.created_at!))!) + } + + zoom = d3.zoom().scaleExtent([0.1, 6]).on('zoom', zoomed) + svg.call(zoom) + + function reGen() { + const newWidth = root.offsetWidth + width = newWidth + + updateMargin() + + svg.attr('width', width).call(zoom.transform, d3.zoomIdentity) + gXAxis.call(xAxis.scale(x.range([margin.left, width - margin.right]))) + gXAxis.selectAll('.tick text').call(wrapText, 30) + gYAxisRight.attr('transform', `translate(${width - margin.right + 0.5}, ${margin.top})`) + timelines.attr('x2', width - margin.right - margin.left) + circles.attr('cx', (d) => x(DateTime.fromISO(d.created_at!))) + } + + d3.select(window).on('resize', _.debounce(reGen, 250)) + } + update(events) + + return update +} diff --git a/ui/src/lib/d3/insertCommonStyle.ts b/ui/app/src/lib/d3/insertCommonStyle.ts similarity index 75% rename from ui/src/lib/d3/insertCommonStyle.ts rename to ui/app/src/lib/d3/insertCommonStyle.ts index 40a920965e..15f70cc482 100644 --- a/ui/src/lib/d3/insertCommonStyle.ts +++ b/ui/app/src/lib/d3/insertCommonStyle.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ export default function insertCommonStyle() { document.head.insertAdjacentHTML( 'beforeend', diff --git a/ui/app/src/lib/d3/wrapText.ts b/ui/app/src/lib/d3/wrapText.ts new file mode 100644 index 0000000000..a7991f7010 --- /dev/null +++ b/ui/app/src/lib/d3/wrapText.ts @@ -0,0 +1,53 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import * as d3 from 'd3' + +export default function wrap(texts: d3.Selection, width: number) { + texts.each(function () { + const text = d3.select(this) + const words = text.text().split(/\s+/).reverse() + let word + let line: string[] = [] + let lineNumber = 0 + const lineHeight = 1.1 + const y = text.attr('y') + const dy = parseFloat(text.attr('dy')) + let tspan = text + .text(null) + .append('tspan') + .attr('x', 0) + .attr('y', y) + .attr('dy', dy + 'em') + + while ((word = words.pop())) { + line.push(word) + tspan.text(line.join(' ')) + + if (tspan.node()!.getComputedTextLength() > width) { + line.pop() + tspan.text(line.join(' ')) + line = [word] + tspan = text + .append('tspan') + .attr('x', 0) + .attr('y', y) + .attr('dy', `${++lineNumber * lineHeight + dy}em`) + .text(word) + } + } + }) +} diff --git a/ui/app/src/lib/formikhelpers.ts b/ui/app/src/lib/formikhelpers.ts new file mode 100644 index 0000000000..46a8e539ce --- /dev/null +++ b/ui/app/src/lib/formikhelpers.ts @@ -0,0 +1,518 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { templateTypeToFieldName } from 'api/zz_generated.frontend.chaos-mesh' +import yaml from 'js-yaml' +import _ from 'lodash' + +import { Env } from 'slices/experiments' +import { Template } from 'slices/workflows' + +import { podPhases } from 'components/AutoForm/data' +import { Experiment, ExperimentKind, Frame, Scope } from 'components/NewExperiment/types' +import basicData from 'components/NewExperimentNext/data/basic' +import { WorkflowBasic } from 'components/NewWorkflow' +import { ScheduleSpecific } from 'components/Schedule/types' + +import { arrToObjBySep, sanitize } from './utils' + +export function parseSubmit( + env: Env, + _kind: K, + e: Experiment>, + options: { + useNewPhysicalMachine: boolean + inSchedule?: boolean + } +) { + const kind = env === 'k8s' ? _kind : 'PhysicalMachineChaos' + const values: typeof e = JSON.parse(JSON.stringify(e)) + let { metadata, spec } = values + + // Set default namespace when it's not present. + if (!metadata.namespace) { + metadata.namespace = env === 'k8s' ? spec.selector.namespaces[0] : 'default' + } + + if (metadata.labels?.length) { + metadata.labels = arrToObjBySep(metadata.labels, ':', { removeAllSpaces: true }) as any + } else { + delete metadata.labels + } + + if (metadata.annotations?.length) { + metadata.annotations = arrToObjBySep(metadata.annotations, ':', { removeAllSpaces: true }) as any + } else { + delete metadata.annotations + } + + function parseSelector(scope: Scope['selector']) { + if (scope.labelSelectors?.length) { + scope.labelSelectors = arrToObjBySep(scope.labelSelectors, ':', { removeAllSpaces: true }) as any + } else { + delete scope.labelSelectors + } + + if (scope.annotationSelectors?.length) { + scope.annotationSelectors = arrToObjBySep(scope.annotationSelectors, ':', { removeAllSpaces: true }) as any + } else { + delete scope.annotationSelectors + } + + function parsePodsOrPhysicalMachines(data: string[]) { + return data.reduce((acc, d) => { + const [namespace, name] = d.split(':') + + if (acc.hasOwnProperty(namespace)) { + acc[namespace].push(name) + } else { + acc[namespace] = [name] + } + + return acc + }, {} as Record) + } + + // Parse pods if exists. + if (scope.pods?.length) { + scope.pods = parsePodsOrPhysicalMachines(scope.pods) as any + } else { + delete scope.pods + } + + // Parse physical machines if exists. + if (scope.physicalMachines?.length) { + scope.physicalMachines = parsePodsOrPhysicalMachines(scope.physicalMachines) as any + } else { + delete scope.physicalMachines + } + } + + parseSelector(spec.selector) + + if (env === 'k8s') { + delete (spec as any).address // Remove the address field because it's only used in PhysicalMachineChaos. + } + + if (env === 'k8s' && kind === 'NetworkChaos') { + if (!(spec as any).externalTargets.length) { + delete (spec as any).externalTargets + } + + if ((spec as any).target) { + if ((spec as any).target.mode) { + parseSelector((spec as any).target.selector) + } else { + ;(spec as any).target = undefined + } + } + } + + if (kind === 'IOChaos' && (spec as any).action === 'attrOverride') { + ;(spec as any).attr = arrToObjBySep((spec as any).attr, ':', { updateVal: (s: string) => parseInt(s, 10) }) + } + + if (kind === 'HTTPChaos') { + // Parse http headers to object + function helperHTTPHeaders(selectors: string[]) { + return selectors.reduce((acc: Record, d) => { + const [k, v] = d.split(':') + + acc[k.trim()] = v.trim() + + return acc + }, {}) + } + + // Parse http queries to patch object + function helperHTTPPatchQueries(selectors: string[]) { + return selectors.map((d) => { + return d.replace(/\s/g, '').split(':') + }) + } + + // Parse http headers to patch object + function helperHTTPPatchHeaders(selectors: string[]) { + return selectors.map((d) => { + return d.split(':').map((s) => s.trim()) + }) + } + + ;(spec as any).request_headers = helperHTTPHeaders((spec as any).request_headers) + if ((spec as any).response_headers) { + ;(spec as any).response_headers = helperHTTPHeaders((spec as any).response_headers) + } + if ((spec as any).replace && (spec as any).replace.headers) { + ;(spec as any).replace.headers = helperHTTPHeaders((spec as any).replace.headers) + } + if ((spec as any).replace && (spec as any).replace.queries) { + ;(spec as any).replace.queries = arrToObjBySep((spec as any).replace.queries, ':', { removeAllSpaces: true }) + } + if ((spec as any).patch && (spec as any).patch.headers) { + ;(spec as any).patch.headers = helperHTTPPatchHeaders((spec as any).patch.headers) + } + if ((spec as any).patch && (spec as any).patch.queries) { + ;(spec as any).patch.queries = helperHTTPPatchQueries((spec as any).patch.queries) + } + } + + function parsePhysicalMachineChaos(spec: any) { + const { action, address, selector, duration, mode } = spec as any + + delete spec.action + delete spec.selector + delete spec.address + delete spec.duration + delete spec.mode + + return { + ...(options.useNewPhysicalMachine ? { selector } : { address }), + action, + mode, + [action]: spec, + duration, + } + } + + if (options.inSchedule) { + const { schedule, historyLimit, concurrencyPolicy, startingDeadlineSeconds, ...rest } = + spec as unknown as ScheduleSpecific + const scheduleSpec = { + schedule, + historyLimit, + concurrencyPolicy, + startingDeadlineSeconds, + type: kind, + [templateTypeToFieldName(kind)]: kind === 'PhysicalMachineChaos' ? parsePhysicalMachineChaos(rest) : rest, + } + spec = scheduleSpec as any + } + + if (!options.inSchedule && kind === 'PhysicalMachineChaos') { + spec = parsePhysicalMachineChaos(spec) as any + } + + return sanitize({ + apiVersion: 'chaos-mesh.org/v1alpha1', + kind: options?.inSchedule ? 'Schedule' : kind, + metadata, + spec, + }) +} + +function podSelectorsToArr(selector: Object) { + return Object.entries(selector) + .map(([ns, pods]) => pods.map((p: string) => `${ns}: ${p}`)) + .flat() +} + +function selectorsToArr(selectors: Object, separator: string) { + return Object.entries(selectors).map(([key, val]) => `${key}${separator}${val}`) +} + +export function parseYAML(yamlObj: any): { kind: ExperimentKind; basic: any; spec: any } { + let { kind, metadata, spec }: { kind: ExperimentKind; metadata: any; spec: any } = yamlObj + + if (!kind || !metadata || !spec) { + throw new Error('Fail to parse the YAML file. Please check the kind, metadata, and spec fields.') + } + + const isSchedule = (kind as any) === 'Schedule' + + if (!isSchedule && kind !== 'PhysicalMachineChaos' && !spec.selector) { + throw new Error('The required spec.selector field is missing.') + } + + let basic = { + metadata: { + ...metadata, + labels: metadata.labels ? selectorsToArr(metadata.labels, ':') : [], + annotations: metadata.annotations ? selectorsToArr(metadata.annotations, ':') : [], + }, + spec: {}, + } + + function parseBasicSpec(kind: ExperimentKind, spec: typeof basicData.spec) { + return { + selector: { + ...basicData.spec.selector, + ...(kind !== 'PhysicalMachineChaos' + ? { + namespaces: spec.selector.namespaces ?? [], + labelSelectors: spec.selector.labelSelectors ? selectorsToArr(spec.selector.labelSelectors, ': ') : [], + annotation_selectors: spec.selector.annotationSelectors + ? selectorsToArr(spec.selector.annotationSelectors, ': ') + : [], + } + : undefined), + }, + + mode: spec.mode ?? 'one', + value: spec.value, + address: spec.address ?? [], + duration: spec.duration ?? '', + } + } + + if (isSchedule) { + const { schedule, historyLimit, concurrencyPolicy, startingDeadlineSeconds, ...rest } = + spec as unknown as ScheduleSpecific + const scheduleSpec = { + schedule, + historyLimit, + concurrencyPolicy, + startingDeadlineSeconds, + } + kind = (rest as any).type + spec = (rest as any)[templateTypeToFieldName(kind)] + basic.spec = { ...parseBasicSpec(kind, spec), ...scheduleSpec } + } else { + basic.spec = parseBasicSpec(kind, spec) + } + + if (kind === 'NetworkChaos') { + if (spec.target) { + spec.target.selector.labelSelectors = spec.target.selector.labelSelectors + ? selectorsToArr(spec.target.selector.labelSelectors, ': ') + : [] + spec.target.selector.annotationSelectors = spec.target.selector.annotationSelectors + ? selectorsToArr(spec.target.selector.annotationSelectors, ': ') + : [] + spec.target.selector.podPhaseSelectors = spec.target.selector.podPhaseSelectors || podPhases + spec.target.selector.pods = spec.target.selector.pods ? podSelectorsToArr(spec.target.selector.pods) : [] + } + } + + if (kind === 'IOChaos' && spec.attr) { + spec.attr = selectorsToArr(spec.attr, ':') + } + + if (kind === 'KernelChaos' && spec.failKernRequest) { + spec.failKernRequest.callchain = spec.failKernRequest.callchain.map((frame: Frame) => { + if (!frame.parameters) { + frame.parameters = '' + } + + if (!frame.predicate) { + frame.predicate = '' + } + + return frame + }) + } + + if (kind === 'StressChaos') { + spec.stressors.cpu = { + workers: 0, + load: 0, + options: [], + ...spec.stressors.cpu, + } + + spec.stressors.memory = { + workers: 0, + options: [], + ...spec.stressors.memory, + } + } + + if (kind === 'PhysicalMachineChaos') { + const action: string = spec.action + + spec = { + action, + ...spec[action], + } + + if (action.startsWith('disk')) { + kind = 'DiskChaos' as any + } + + if (action.startsWith('jvm')) { + kind = 'JVMChaos' + } + + if (action.startsWith('network')) { + kind = 'NetworkChaos' + } + + if (action.startsWith('process')) { + kind = 'ProcessChaos' as any + } + + if (action.startsWith('stress')) { + kind = 'StressChaos' + } + + if (action === 'clock') { + kind = 'TimeChaos' + } + } else { + const { selector, mode, value, duration, ...rest } = spec + spec = rest + } + + return sanitize({ + kind, + basic, + spec, + }) +} + +function validate(defaultI18n: string, i18n?: string) { + return function (value: string) { + let error + + if (value === '') { + error = i18n ?? defaultI18n + } + + return error + } +} +export const validateName = (i18n?: string) => validate('The name is required', i18n) +export const validateDuration = (i18n?: string) => validate('The duration is required', i18n) +export const validateSchedule = (i18n?: string) => validate('The schedule is required', i18n) +export const validateDeadline = (i18n?: string) => validate('The deadline is required', i18n) +export const validateImage = (i18n?: string) => validate('The image is required', i18n) + +export function constructWorkflow(basic: WorkflowBasic, templates: Template[]) { + const { name, namespace, deadline } = basic + const children: string[] = templates.map((d) => d.name) + const realTemplates: Record[] = [] + + function pushTemplate(template: any) { + if (!realTemplates.some((t) => t.name === template.name)) { + realTemplates.push(template) + } + } + + function pushSingle(template: Template) { + const exp = template.experiment + const kind = exp.kind + const { duration: deadline, ...rest } = exp.spec + + pushTemplate({ + name: template.name, + templateType: kind, + deadline, + [templateTypeToFieldName(kind)]: rest, + }) + } + + function recurInsertTemplates(templates: Template[]) { + templates.forEach((t) => { + switch (t.type) { + case 'single': + pushSingle(t) + + break + case 'serial': + case 'parallel': + case 'custom': + t.children!.forEach((d) => { + if (d.children) { + pushTemplate({ + name: d.name, + templateType: _.upperFirst(d.type), + deadline: d.deadline, + children: d.children!.map((dd) => dd.name), + }) + + recurInsertTemplates(d.children) + } else { + if (d.type === 'suspend') { + pushTemplate({ + name: d.name, + templateType: 'Suspend', + deadline: d.deadline, + }) + + return + } + + pushSingle(d) + } + }) + + pushTemplate({ + name: t.name, + templateType: _.upperFirst(t.type === 'custom' ? 'task' : t.type), + deadline: t.type !== 'custom' ? t.deadline : undefined, + children: t.type !== 'custom' ? t.children!.map((d) => d.name) : undefined, + task: + t.type === 'custom' + ? { + container: t.custom?.container, + } + : undefined, + conditionalBranches: t.type === 'custom' ? t.custom?.conditionalBranches : undefined, + }) + + break + case 'suspend': + pushTemplate({ + name: t.name, + templateType: 'Suspend', + deadline: t.deadline, + }) + + break + default: + break + } + }) + } + + recurInsertTemplates(templates) + + return yaml.dump( + { + apiVersion: 'chaos-mesh.org/v1alpha1', + kind: 'Workflow', + metadata: { + name, + namespace, + }, + spec: { + entry: 'entry', + templates: [ + { + name: 'entry', + templateType: 'Serial', + deadline, + children, + }, + ...realTemplates, + ], + }, + }, + { + replacer: (_, value) => { + if (Array.isArray(value)) { + return value.length ? value : undefined + } + + switch (typeof value) { + case 'string': + return value !== '' ? value : undefined + default: + return value + } + }, + } + ) +} diff --git a/ui/app/src/lib/hooks.ts b/ui/app/src/lib/hooks.ts new file mode 100644 index 0000000000..829366fe02 --- /dev/null +++ b/ui/app/src/lib/hooks.ts @@ -0,0 +1,32 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { useEffect, useRef } from 'react' +import { useLocation } from 'react-router-dom' + +export function usePrevious(value: T) { + const ref = useRef() + + useEffect(() => { + ref.current = value + }, [value]) + + return ref.current +} + +export function useQuery() { + return new URLSearchParams(useLocation().search) +} diff --git a/ui/app/src/lib/idb.ts b/ui/app/src/lib/idb.ts new file mode 100644 index 0000000000..ec13bbc336 --- /dev/null +++ b/ui/app/src/lib/idb.ts @@ -0,0 +1,51 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { DBSchema, IDBPDatabase, openDB } from 'idb' + +import { ExperimentKind } from 'components/NewExperiment/types' + +export interface PreDefinedValue { + name: string + kind: ExperimentKind | 'Schedule' + yaml: object +} + +interface DB extends DBSchema { + predefined: { + key: string + value: PreDefinedValue + } +} + +let db: IDBPDatabase + +export async function getDB() { + if (!db) { + db = await openDB('chaos-mesh', 1, { + upgrade(db, oldVersion) { + if (oldVersion === 0) { + db.createObjectStore('predefined', { + keyPath: 'name', + }) + } + }, + }) + } + + return db +} diff --git a/ui/app/src/lib/localStorage.ts b/ui/app/src/lib/localStorage.ts new file mode 100644 index 0000000000..1d5ab78ec8 --- /dev/null +++ b/ui/app/src/lib/localStorage.ts @@ -0,0 +1,42 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +const PREFIX = 'chaos-mesh-' + +export default class LocalStorage { + static ls = window.localStorage + + static get(key: string) { + return this.ls.getItem(PREFIX + key) + } + + static getObj(key: string) { + return JSON.parse(this.get(key) ?? '{}') + } + + static set(key: string, val: string) { + this.ls.setItem(PREFIX + key, val) + } + + static setObj(key: string, obj: any) { + this.set(key, JSON.stringify(obj)) + } + + static remove(key: string) { + this.ls.removeItem(PREFIX + key) + } +} diff --git a/ui/app/src/lib/luxon.ts b/ui/app/src/lib/luxon.ts new file mode 100644 index 0000000000..b4d3774851 --- /dev/null +++ b/ui/app/src/lib/luxon.ts @@ -0,0 +1,41 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { DateTime } from 'luxon' + +export function comparator(a: string, b: string) { + const da = DateTime.fromISO(a) + const db = DateTime.fromISO(b) + + if (da > db) { + return 1 + } + + if (da < db) { + return -1 + } + + return 0 +} + +export const now = DateTime.local + +export const format = (date: string, locale: string = 'en') => + DateTime.fromISO(date, { locale }).toFormat('yyyy-MM-dd HH:mm:ss a') + +export const toRelative = (date: string, locale: string = 'en') => DateTime.fromISO(date, { locale }).toRelative() + +export default DateTime diff --git a/ui/app/src/lib/search.ts b/ui/app/src/lib/search.ts new file mode 100644 index 0000000000..fb3f521f25 --- /dev/null +++ b/ui/app/src/lib/search.ts @@ -0,0 +1,136 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { CoreWorkflowMeta, TypesArchive, TypesExperiment, TypesSchedule } from 'openapi/index.schemas' + +type Keyword = 'namespace' | 'ns' | 'kind' + +interface SearchData { + workflows: CoreWorkflowMeta[] + schedules: TypesSchedule[] + experiments: TypesExperiment[] + archives: TypesArchive[] +} + +interface KeywordToken { + type: 'keyword' + keyword: Keyword + value: string +} + +interface ContentToken { + type: 'content' + value: string +} + +type Token = KeywordToken | ContentToken + +class SearchAutomata { + private keywords: Keyword[] + private tokens: Token[] + + constructor(keywords: Keyword[]) { + this.keywords = keywords + this.tokens = [] + } + + parseStart(s: string) { + if (s.length === 0) { + return this.parseEnd() + } + + return this.parseKeywords(s) + } + + private parseEnd() { + return this.tokens + } + + private parseKeywords(s: string) { + for (const keyword of this.keywords) { + const re = new RegExp(`(${keyword}):\\s*(\\S+)`) + const parsed = s.match(re) + + if (parsed) { + this.emit({ + type: 'keyword', + keyword: parsed[1] as Keyword, + value: parsed[2], + }) + + s = (s.substr(0, parsed.index) + s.substr(parsed.index! + parsed[0].length, s.length)).trim() + } + } + + return this.parseContent(s) + } + + private parseContent(s: string) { + this.emit({ + type: 'content', + value: s, + } as ContentToken) + + return this.parseEnd() + } + + private emit(token: Token) { + this.tokens.push(token) + } + + clearTokens() { + this.tokens = [] + } +} + +const automata = new SearchAutomata(['namespace', 'ns', 'kind']) + +export default function search(data: SearchData, s: string) { + const tokens = automata.parseStart(s) + + const workflows = searchObjects(data.workflows, tokens) + const schedules = searchObjects(data.schedules, tokens) + const experiments = searchObjects(data.experiments, tokens) + const archives = searchObjects(data.archives, tokens) + + automata.clearTokens() + + return { workflows, schedules, experiments, archives } +} + +function searchCommon(data: any, keyword: Keyword, value: string) { + if (keyword === 'ns') { + keyword = 'namespace' + } + + return data.filter((d: any) => d[keyword].toLowerCase().includes(value)) +} + +function searchObjects(data: T[], tokens: Token[]) { + let filtered = data + + tokens.forEach((t) => { + const val = t.value.toLowerCase() + + if (t.type === 'keyword') { + filtered = searchCommon(filtered, t.keyword, val) + } else if (t.type === 'content') { + filtered = filtered.filter((d) => d.name!.toLowerCase().includes(val)) + } + }) + + return filtered +} diff --git a/ui/app/src/lib/utils.test.ts b/ui/app/src/lib/utils.test.ts new file mode 100644 index 0000000000..70c21658d1 --- /dev/null +++ b/ui/app/src/lib/utils.test.ts @@ -0,0 +1,99 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { arrToObjBySep, isDeepEmpty, sanitize } from './utils' + +describe('lib/utils', () => { + describe('arrToObjBySep', () => { + it('should convert array to object', () => { + const arr = ['foo=bar', 'baz=qux'] + const result = arrToObjBySep(arr, '=') + + expect(result).toEqual({ foo: 'bar', baz: 'qux' }) + }) + + it('should remove all spaces from the array items', () => { + const arr = ['foo = bar', 'baz = qux '] + const result = arrToObjBySep(arr, '=', { removeAllSpaces: true }) + + expect(result).toEqual({ foo: 'bar', baz: 'qux' }) + }) + + it('should convert array to object with value to a number', () => { + const arr = ['foo=1', 'baz=2'] + const result = arrToObjBySep(arr, '=', { updateVal: (s) => +s }) + + expect(result).toEqual({ foo: 1, baz: 2 }) + }) + }) + + describe('isDeepEmpty', () => { + it('checks some primitive values', () => { + expect(isDeepEmpty(true)).toBeFalsy() + expect(isDeepEmpty(false)).toBeTruthy() + expect(isDeepEmpty(null)).toBeTruthy() + expect(isDeepEmpty(undefined)).toBeTruthy() + expect(isDeepEmpty(1)).toBeFalsy() + expect(isDeepEmpty(0)).toBeTruthy() + expect(isDeepEmpty(NaN)).toBeTruthy() + expect(isDeepEmpty('string')).toBeFalsy() + expect(isDeepEmpty('')).toBeTruthy() + }) + + it('checks arrays', () => { + expect(isDeepEmpty([])).toBeTruthy() + expect(isDeepEmpty([1])).toBeFalsy() + }) + + it('checks some objects', () => { + expect(isDeepEmpty({})).toBeTruthy() + expect(isDeepEmpty({ a: 1 })).toBeFalsy() + }) + + it('checks a nested object', () => { + expect(isDeepEmpty({ a: { b: { c: {} } } })).toBeTruthy() + }) + }) + + describe('sanitize', () => { + it('sanitizes an normal object', () => { + expect( + sanitize({ + a: 1, + b: '', + c: null, + d: 'd', + }) + ).toEqual({ + a: 1, + d: 'd', + }) + }) + + it('sanitizes an object where all values are empty', () => { + expect( + sanitize({ + a: 0, + b: '', + c: null, + d: undefined, + e: [], + f: {}, + }) + ).toEqual({}) + }) + }) +}) diff --git a/ui/app/src/lib/utils.ts b/ui/app/src/lib/utils.ts new file mode 100644 index 0000000000..ca801b10ee --- /dev/null +++ b/ui/app/src/lib/utils.ts @@ -0,0 +1,85 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import _ from 'lodash' + +export function objToArrBySep(obj: Record, separator: string) { + return Object.entries(obj).reduce( + (acc, [k, v]) => acc.concat(Array.isArray(v) ? v.map((d) => `${k}${separator}${d}`) : `${k}${separator}${v}`), + [] + ) +} + +export function arrToObjBySep( + arr: string[], + sep: string, + options?: { removeAllSpaces?: boolean; updateVal?: (s: string) => any } +) { + return arr.reduce>((acc, d) => { + let processed = d + + if (options?.removeAllSpaces) { + processed = processed.replace(/\s/g, '') + } + + let [k, v] = processed.split(sep) + + if (options?.updateVal) { + v = options.updateVal(v) + } + + acc[k] = v + + return acc + }, {}) +} + +/** + * Recursively check if a value is empty. + * + * @export + * @param {*} value + * @return {boolean} + */ +export function isDeepEmpty(value: any): boolean { + if (!value) { + return true + } + + if (_.isArray(value) && _.isEmpty(value)) { + return true + } + + if (_.isObject(value)) { + return _.every(value, isDeepEmpty) + } + + return false +} + +/** + * Remove empty values from nested object. + * + * @export + * @param {*} obj + */ +export function sanitize(obj: any) { + return JSON.parse(JSON.stringify(obj, (_, value: any) => (isDeepEmpty(value) ? undefined : value)) ?? '{}') +} + +export function concatKindAction(kind: string, action?: string) { + return `${kind}${action ? ` / ${action}` : ''}` +} diff --git a/ui/app/src/openapi/index.msw.ts b/ui/app/src/openapi/index.msw.ts new file mode 100644 index 0000000000..2cf3ec19ef --- /dev/null +++ b/ui/app/src/openapi/index.msw.ts @@ -0,0 +1,6542 @@ +/** + * Generated by orval v6.12.1 🍺 + * Do not edit manually. + * Chaos Mesh Dashboard API + * Swagger for Chaos Mesh Dashboard. If you encounter any problems with API, please click on the issues link below to report. + * OpenAPI spec version: 2.2 + */ +import { faker } from '@faker-js/faker' +import { rest } from 'msw' + +export const getDeleteArchivesMock = () => ({ status: faker.random.word() }) + +export const getGetArchivesMock = () => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + created_at: faker.random.word(), + kind: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + uid: faker.random.word(), + })) + +export const getDeleteArchivesUidMock = () => ({ status: faker.random.word() }) + +export const getGetArchivesUidMock = () => ({ + created_at: faker.random.word(), + kind: faker.random.word(), + kube_object: { + apiVersion: faker.random.word(), + kind: faker.random.word(), + metadata: { + annotations: { + clfp8d9ic0000v5difx71h6sk: faker.random.word(), + }, + labels: { + clfp8d9ic0001v5di1qpecewp: faker.random.word(), + }, + name: faker.random.word(), + namespace: faker.random.word(), + }, + spec: {}, + }, + name: faker.random.word(), + namespace: faker.random.word(), + uid: faker.random.word(), +}) + +export const getDeleteArchivesSchedulesMock = () => ({ status: faker.random.word() }) + +export const getGetArchivesSchedulesMock = () => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + created_at: faker.random.word(), + kind: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + uid: faker.random.word(), + })) + +export const getDeleteArchivesSchedulesUidMock = () => ({ status: faker.random.word() }) + +export const getGetArchivesSchedulesUidMock = () => ({ + created_at: faker.random.word(), + kind: faker.random.word(), + kube_object: { + apiVersion: faker.random.word(), + kind: faker.random.word(), + metadata: { + annotations: { + clfp8d9ij0002v5di52aze8xy: faker.random.word(), + }, + labels: { + clfp8d9ij0003v5diaz3ea0yz: faker.random.word(), + }, + name: faker.random.word(), + namespace: faker.random.word(), + }, + spec: {}, + }, + name: faker.random.word(), + namespace: faker.random.word(), + uid: faker.random.word(), +}) + +export const getDeleteArchivesWorkflowsMock = () => ({ status: faker.random.word() }) + +export const getGetArchivesWorkflowsMock = () => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + created_at: faker.random.word(), + kind: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + uid: faker.random.word(), + })) + +export const getDeleteArchivesWorkflowsUidMock = () => ({ status: faker.random.word() }) + +export const getGetArchivesWorkflowsUidMock = () => ({ + created_at: faker.random.word(), + kind: faker.random.word(), + kube_object: { + apiVersion: faker.random.word(), + kind: faker.random.word(), + metadata: { + annotations: { + clfp8d9ip0004v5di8qc61pfn: faker.random.word(), + }, + labels: { + clfp8d9ip0005v5di2vr17qsf: faker.random.word(), + }, + name: faker.random.word(), + namespace: faker.random.word(), + }, + spec: {}, + }, + name: faker.random.word(), + namespace: faker.random.word(), + uid: faker.random.word(), +}) + +export const getGetCommonAnnotationsMock = () => ({ + clfp8d9iq0006v5dicd5u41dp: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), +}) + +export const getGetCommonChaosAvailableNamespacesMock = () => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, () => faker.random.word()) + +export const getGetCommonConfigMock = () => ({ + burst: faker.datatype.number({ min: undefined, max: undefined }), + cluster_mode: faker.datatype.boolean(), + dns_server_create: faker.datatype.boolean(), + enableFilterNamespace: faker.datatype.boolean(), + enableProfiling: faker.datatype.boolean(), + gcp_security_mode: faker.datatype.boolean(), + listen_host: faker.random.word(), + listen_port: faker.datatype.number({ min: undefined, max: undefined }), + qps: faker.datatype.number({ min: undefined, max: undefined }), + root_path: faker.random.word(), + security_mode: faker.datatype.boolean(), + target_namespace: faker.random.word(), + version: faker.random.word(), +}) + +export const getGetCommonKindsMock = () => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, () => faker.random.word()) + +export const getGetCommonLabelsMock = () => ({ + clfp8d9iu0007v5di75ez04ik: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), +}) + +export const getGetCommonNamespacesMock = () => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, () => faker.random.word()) + +export const getGetCommonPhysicalmachineAnnotationsMock = () => ({ + clfp8d9iw0008v5di4nm7f7po: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), +}) + +export const getGetCommonPhysicalmachineLabelsMock = () => ({ + clfp8d9ix0009v5di6gu09nh2: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), +}) + +export const getPostCommonPhysicalmachinesMock = () => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + address: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + })) + +export const getPostCommonPodsMock = () => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + ip: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + state: faker.random.word(), + })) + +export const getGetCommonRbacConfigMock = () => ({ + clfp8d9j0000av5di9cbxbimk: faker.random.word(), +}) + +export const getGetEventsMock = () => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + created_at: faker.random.word(), + id: faker.datatype.number({ min: undefined, max: undefined }), + kind: faker.random.word(), + message: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + object_id: faker.random.word(), + reason: faker.random.word(), + type: faker.random.word(), + })) + +export const getGetEventsIdMock = () => ({ + created_at: faker.random.word(), + id: faker.datatype.number({ min: undefined, max: undefined }), + kind: faker.random.word(), + message: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + object_id: faker.random.word(), + reason: faker.random.word(), + type: faker.random.word(), +}) + +export const getGetEventsWorkflowUidMock = () => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + created_at: faker.random.word(), + id: faker.datatype.number({ min: undefined, max: undefined }), + kind: faker.random.word(), + message: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + object_id: faker.random.word(), + reason: faker.random.word(), + type: faker.random.word(), + })) + +export const getDeleteExperimentsMock = () => ({ status: faker.random.word() }) + +export const getGetExperimentsMock = () => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + created_at: faker.random.word(), + failed_message: faker.random.word(), + kind: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + status: faker.random.word(), + uid: faker.random.word(), + })) + +export const getPostExperimentsMock = () => ({}) + +export const getDeleteExperimentsUidMock = () => ({ status: faker.random.word() }) + +export const getGetExperimentsUidMock = () => ({ + created_at: faker.random.word(), + failed_message: faker.random.word(), + kind: faker.random.word(), + kube_object: { + apiVersion: faker.random.word(), + kind: faker.random.word(), + metadata: { + annotations: { + clfp8d9j5000bv5diaxnh4d8y: faker.random.word(), + }, + labels: { + clfp8d9j5000cv5digyqv64qk: faker.random.word(), + }, + name: faker.random.word(), + namespace: faker.random.word(), + }, + spec: {}, + }, + name: faker.random.word(), + namespace: faker.random.word(), + status: faker.random.word(), + uid: faker.random.word(), +}) + +export const getPutExperimentsPauseUidMock = () => ({ status: faker.random.word() }) + +export const getPutExperimentsStartUidMock = () => ({ status: faker.random.word() }) + +export const getGetExperimentsStateMock = () => ({ + deleting: faker.datatype.number({ min: undefined, max: undefined }), + finished: faker.datatype.number({ min: undefined, max: undefined }), + injecting: faker.datatype.number({ min: undefined, max: undefined }), + paused: faker.datatype.number({ min: undefined, max: undefined }), + running: faker.datatype.number({ min: undefined, max: undefined }), +}) + +export const getDeleteSchedulesMock = () => ({ status: faker.random.word() }) + +export const getGetSchedulesMock = () => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + created_at: faker.random.word(), + kind: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + status: faker.random.word(), + uid: faker.random.word(), + })) + +export const getPostSchedulesMock = () => ({ + annotations: { + clfp8d9j8000dv5di3r462nhf: faker.random.word(), + }, + apiVersion: faker.random.word(), + creationTimestamp: faker.random.word(), + deletionGracePeriodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + deletionTimestamp: faker.random.word(), + finalizers: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + generateName: faker.random.word(), + generation: faker.datatype.number({ min: undefined, max: undefined }), + kind: faker.random.word(), + labels: { + clfp8d9j9000ev5di4hwq5gga: faker.random.word(), + }, + managedFields: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + apiVersion: faker.random.word(), + fieldsType: faker.random.word(), + fieldsV1: {}, + manager: faker.random.word(), + operation: faker.random.word(), + subresource: faker.random.word(), + time: faker.random.word(), + })), + name: faker.random.word(), + namespace: faker.random.word(), + ownerReferences: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + apiVersion: faker.random.word(), + blockOwnerDeletion: faker.datatype.boolean(), + controller: faker.datatype.boolean(), + kind: faker.random.word(), + name: faker.random.word(), + uid: faker.random.word(), + })), + resourceVersion: faker.random.word(), + selfLink: faker.random.word(), + spec: { + awsChaos: { + action: faker.random.word(), + awsRegion: faker.random.word(), + deviceName: faker.random.word(), + duration: faker.random.word(), + ec2Instance: faker.random.word(), + endpoint: faker.random.word(), + remoteCluster: faker.random.word(), + secretName: faker.random.word(), + volumeID: faker.random.word(), + }, + azureChaos: { + action: faker.random.word(), + diskName: faker.random.word(), + duration: faker.random.word(), + lun: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + resourceGroupName: faker.random.word(), + secretName: faker.random.word(), + subscriptionID: faker.random.word(), + vmName: faker.random.word(), + }, + blockChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + delay: { correlation: faker.random.word(), jitter: faker.random.word(), latency: faker.random.word() }, + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9j9000fv5di2b9tggja: faker.random.word(), + }, + fieldSelectors: { + clfp8d9j9000gv5di86zk7inc: faker.random.word(), + }, + labelSelectors: { + clfp8d9j9000hv5dic6g0gz63: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9j9000iv5di6o26cvtm: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9j9000jv5diblvo8sa4: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + volumeName: faker.random.word(), + }, + concurrencyPolicy: faker.random.word(), + dnsChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + patterns: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9j9000kv5di955t1d6j: faker.random.word(), + }, + fieldSelectors: { + clfp8d9j9000lv5di3v0v374z: faker.random.word(), + }, + labelSelectors: { + clfp8d9j9000mv5didk4q59ol: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9j9000nv5di4kg38a86: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9j9000ov5di3qlx6reh: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + gcpChaos: { + action: faker.random.word(), + deviceNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + instance: faker.random.word(), + project: faker.random.word(), + remoteCluster: faker.random.word(), + secretName: faker.random.word(), + zone: faker.random.word(), + }, + historyLimit: faker.datatype.number({ min: undefined, max: undefined }), + httpChaos: { + abort: faker.datatype.boolean(), + code: faker.datatype.number({ min: undefined, max: undefined }), + delay: faker.random.word(), + duration: faker.random.word(), + method: faker.random.word(), + mode: faker.random.word(), + patch: { + body: { type: faker.random.word(), value: faker.random.word() }, + headers: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ) + ), + queries: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ) + ), + }, + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + replace: { + body: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + code: faker.datatype.number({ min: undefined, max: undefined }), + headers: { + clfp8d9j9000pv5di2r13gnr0: faker.random.word(), + }, + method: faker.random.word(), + path: faker.random.word(), + queries: { + clfp8d9j9000qv5di01wm5c1v: faker.random.word(), + }, + }, + request_headers: { + clfp8d9j9000rv5die4b6h53b: faker.random.word(), + }, + response_headers: { + clfp8d9j9000sv5dibxr865x9: faker.random.word(), + }, + selector: { + annotationSelectors: { + clfp8d9j9000tv5di65bc7uc5: faker.random.word(), + }, + fieldSelectors: { + clfp8d9j9000uv5dih8wo6io2: faker.random.word(), + }, + labelSelectors: { + clfp8d9j9000vv5di5azn1bv3: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9j9000wv5di1urx2s4m: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9j9000xv5di3hp47pdc: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + target: faker.random.word(), + tls: { + caName: faker.random.word(), + certName: faker.random.word(), + keyName: faker.random.word(), + secretName: faker.random.word(), + secretNamespace: faker.random.word(), + }, + value: faker.random.word(), + }, + ioChaos: { + action: faker.random.word(), + attr: { + atime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + blocks: faker.datatype.number({ min: undefined, max: undefined }), + ctime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + gid: faker.datatype.number({ min: undefined, max: undefined }), + ino: faker.datatype.number({ min: undefined, max: undefined }), + kind: faker.random.word(), + mtime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + nlink: faker.datatype.number({ min: undefined, max: undefined }), + perm: faker.datatype.number({ min: undefined, max: undefined }), + rdev: faker.datatype.number({ min: undefined, max: undefined }), + size: faker.datatype.number({ min: undefined, max: undefined }), + uid: faker.datatype.number({ min: undefined, max: undefined }), + }, + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + delay: faker.random.word(), + duration: faker.random.word(), + errno: faker.datatype.number({ min: undefined, max: undefined }), + methods: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + mistake: { + filling: faker.random.word(), + maxLength: faker.datatype.number({ min: undefined, max: undefined }), + maxOccurrences: faker.datatype.number({ min: undefined, max: undefined }), + }, + mode: faker.random.word(), + path: faker.random.word(), + percent: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9ja000yv5di5ina9m3z: faker.random.word(), + }, + fieldSelectors: { + clfp8d9ja000zv5dig3lg8oxv: faker.random.word(), + }, + labelSelectors: { + clfp8d9ja0010v5diam1847ud: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9ja0011v5di298t3ucp: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9ja0012v5dih825cbo9: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + volumePath: faker.random.word(), + }, + jvmChaos: { + action: faker.random.word(), + class: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + cpuCount: faker.datatype.number({ min: undefined, max: undefined }), + database: faker.random.word(), + duration: faker.random.word(), + exception: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + memType: faker.random.word(), + method: faker.random.word(), + mode: faker.random.word(), + mysqlConnectorVersion: faker.random.word(), + name: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + ruleData: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9ja0013v5dibydk8ieq: faker.random.word(), + }, + fieldSelectors: { + clfp8d9ja0014v5di9wab7et4: faker.random.word(), + }, + labelSelectors: { + clfp8d9ja0015v5di4w1h9137: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9ja0016v5di1ijhalvl: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9ja0017v5dif4sx8oq3: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + sqlType: faker.random.word(), + table: faker.random.word(), + value: faker.random.word(), + }, + kernelChaos: { + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + failKernRequest: { + callchain: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + funcname: faker.random.word(), + parameters: faker.random.word(), + predicate: faker.random.word(), + })), + failtype: faker.datatype.number({ min: undefined, max: undefined }), + headers: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + probability: faker.datatype.number({ min: undefined, max: undefined }), + times: faker.datatype.number({ min: undefined, max: undefined }), + }, + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9ja0018v5di8ifg11d4: faker.random.word(), + }, + fieldSelectors: { + clfp8d9ja0019v5dihknx1x25: faker.random.word(), + }, + labelSelectors: { + clfp8d9ja001av5di4fh53kbo: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9ja001bv5dihq2pe4i7: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9ja001cv5difw4sef7u: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + networkChaos: { + action: faker.random.word(), + bandwidth: { + buffer: faker.datatype.number({ min: undefined, max: undefined }), + limit: faker.datatype.number({ min: undefined, max: undefined }), + minburst: faker.datatype.number({ min: undefined, max: undefined }), + peakrate: faker.datatype.number({ min: undefined, max: undefined }), + rate: faker.random.word(), + }, + corrupt: { correlation: faker.random.word(), corrupt: faker.random.word() }, + delay: { + correlation: faker.random.word(), + jitter: faker.random.word(), + latency: faker.random.word(), + reorder: { + correlation: faker.random.word(), + gap: faker.datatype.number({ min: undefined, max: undefined }), + reorder: faker.random.word(), + }, + }, + device: faker.random.word(), + direction: faker.random.word(), + duplicate: { correlation: faker.random.word(), duplicate: faker.random.word() }, + duration: faker.random.word(), + externalTargets: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + loss: { correlation: faker.random.word(), loss: faker.random.word() }, + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9ja001dv5di0oyado2q: faker.random.word(), + }, + fieldSelectors: { + clfp8d9ja001ev5di6bizc71q: faker.random.word(), + }, + labelSelectors: { + clfp8d9ja001fv5dig35n3a5q: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9ja001gv5dihd445k5o: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9ja001hv5dihksig367: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + target: { + mode: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9ja001iv5di6voegp30: faker.random.word(), + }, + fieldSelectors: { + clfp8d9ja001jv5difklv01ir: faker.random.word(), + }, + labelSelectors: { + clfp8d9ja001kv5di8ere02cp: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9ja001lv5di934e1sze: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + pods: { + clfp8d9ja001mv5didx1jb4yg: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + targetDevice: faker.random.word(), + value: faker.random.word(), + }, + physicalmachineChaos: { + action: faker.random.word(), + address: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + clock: { + 'clock-ids-slice': faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + 'time-offset': faker.random.word(), + }, + 'disk-fill': { + 'fill-by-fallocate': faker.datatype.boolean(), + path: faker.random.word(), + size: faker.random.word(), + }, + 'disk-read-payload': { + path: faker.random.word(), + 'payload-process-num': faker.datatype.number({ min: undefined, max: undefined }), + size: faker.random.word(), + }, + 'disk-write-payload': { + path: faker.random.word(), + 'payload-process-num': faker.datatype.number({ min: undefined, max: undefined }), + size: faker.random.word(), + }, + duration: faker.random.word(), + 'file-append': { + count: faker.datatype.number({ min: undefined, max: undefined }), + data: faker.random.word(), + 'file-name': faker.random.word(), + }, + 'file-create': { 'dir-name': faker.random.word(), 'file-name': faker.random.word() }, + 'file-delete': { 'dir-name': faker.random.word(), 'file-name': faker.random.word() }, + 'file-modify': { + 'file-name': faker.random.word(), + privilege: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'file-rename': { 'dest-file': faker.random.word(), 'source-file': faker.random.word() }, + 'file-replace': { + 'dest-string': faker.random.word(), + 'file-name': faker.random.word(), + line: faker.datatype.number({ min: undefined, max: undefined }), + 'origin-string': faker.random.word(), + }, + 'http-abort': { + code: faker.random.word(), + method: faker.random.word(), + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + proxy_ports: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + target: faker.random.word(), + }, + 'http-config': { file_path: faker.random.word() }, + 'http-delay': { + code: faker.random.word(), + delay: faker.random.word(), + method: faker.random.word(), + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + proxy_ports: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + target: faker.random.word(), + }, + 'http-request': { + count: faker.datatype.number({ min: undefined, max: undefined }), + 'enable-conn-pool': faker.datatype.boolean(), + url: faker.random.word(), + }, + 'jvm-exception': { + class: faker.random.word(), + exception: faker.random.word(), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-gc': { + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-latency': { + class: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-mysql': { + database: faker.random.word(), + exception: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + mysqlConnectorVersion: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + sqlType: faker.random.word(), + table: faker.random.word(), + }, + 'jvm-return': { + class: faker.random.word(), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + value: faker.random.word(), + }, + 'jvm-rule-data': { + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + 'rule-data': faker.random.word(), + }, + 'jvm-stress': { + 'cpu-count': faker.datatype.number({ min: undefined, max: undefined }), + 'mem-type': faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'kafka-fill': { + host: faker.random.word(), + maxBytes: faker.datatype.number({ min: undefined, max: undefined }), + messageSize: faker.datatype.number({ min: undefined, max: undefined }), + password: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + reloadCommand: faker.random.word(), + topic: faker.random.word(), + username: faker.random.word(), + }, + 'kafka-flood': { + host: faker.random.word(), + messageSize: faker.datatype.number({ min: undefined, max: undefined }), + password: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + threads: faker.datatype.number({ min: undefined, max: undefined }), + topic: faker.random.word(), + username: faker.random.word(), + }, + 'kafka-io': { + configFile: faker.random.word(), + nonReadable: faker.datatype.boolean(), + nonWritable: faker.datatype.boolean(), + topic: faker.random.word(), + }, + mode: faker.random.word(), + 'network-bandwidth': { + buffer: faker.datatype.number({ min: undefined, max: undefined }), + device: faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + limit: faker.datatype.number({ min: undefined, max: undefined }), + minburst: faker.datatype.number({ min: undefined, max: undefined }), + peakrate: faker.datatype.number({ min: undefined, max: undefined }), + rate: faker.random.word(), + }, + 'network-corrupt': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-delay': { + 'accept-tcp-flags': faker.random.word(), + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + jitter: faker.random.word(), + latency: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-dns': { + 'dns-domain-name': faker.random.word(), + 'dns-ip': faker.random.word(), + 'dns-server': faker.random.word(), + }, + 'network-down': { device: faker.random.word(), duration: faker.random.word() }, + 'network-duplicate': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-flood': { + duration: faker.random.word(), + 'ip-address': faker.random.word(), + parallel: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.random.word(), + rate: faker.random.word(), + }, + 'network-loss': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-partition': { + 'accept-tcp-flags': faker.random.word(), + device: faker.random.word(), + direction: faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + }, + process: { + process: faker.random.word(), + recoverCmd: faker.random.word(), + signal: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'redis-cacheLimit': { + addr: faker.random.word(), + cacheSize: faker.random.word(), + password: faker.random.word(), + percent: faker.random.word(), + }, + 'redis-expiration': { + addr: faker.random.word(), + expiration: faker.random.word(), + key: faker.random.word(), + option: faker.random.word(), + password: faker.random.word(), + }, + 'redis-penetration': { + addr: faker.random.word(), + password: faker.random.word(), + requestNum: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'redis-restart': { + addr: faker.random.word(), + conf: faker.random.word(), + flushConfig: faker.datatype.boolean(), + password: faker.random.word(), + redisPath: faker.datatype.boolean(), + }, + 'redis-stop': { + addr: faker.random.word(), + conf: faker.random.word(), + flushConfig: faker.datatype.boolean(), + password: faker.random.word(), + redisPath: faker.datatype.boolean(), + }, + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jb001nv5di69wwa6o6: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jb001ov5di6oo6bwrj: faker.random.word(), + }, + labelSelectors: { + clfp8d9jb001pv5dihgl8e71j: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + physicalMachines: { + clfp8d9jb001qv5di99o85btd: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + 'stress-cpu': { + load: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'stress-mem': { + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + size: faker.random.word(), + }, + user_defined: { attackCmd: faker.random.word(), recoverCmd: faker.random.word() }, + value: faker.random.word(), + vm: { 'vm-name': faker.random.word() }, + }, + podChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + gracePeriod: faker.datatype.number({ min: undefined, max: undefined }), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jc001rv5di2l6vbtto: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jc001sv5di312kgvch: faker.random.word(), + }, + labelSelectors: { + clfp8d9jc001tv5di2y9tab5l: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jc001uv5digjts8kdr: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jc001vv5di8vh4br8r: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + schedule: faker.random.word(), + startingDeadlineSeconds: faker.datatype.number({ min: undefined, max: undefined }), + stressChaos: { + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jc001wv5digsmnc3tg: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jc001xv5dibnigf9ci: faker.random.word(), + }, + labelSelectors: { + clfp8d9jc001yv5di8e1rbl20: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jc001zv5di2kpt4eaj: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jc0020v5di83byaza8: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + stressngStressors: faker.random.word(), + stressors: { + cpu: { + load: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + memory: { + oomScoreAdj: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + size: faker.random.word(), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + value: faker.random.word(), + }, + timeChaos: { + clockIds: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jc0021v5di6wqu46dw: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jc0022v5di2with2su: faker.random.word(), + }, + labelSelectors: { + clfp8d9jc0023v5di7k7j2qs7: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jc0024v5di09sr0mmo: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jc0025v5diaqwp2exz: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + timeOffset: faker.random.word(), + value: faker.random.word(), + }, + type: faker.random.word(), + workflow: { + entry: faker.random.word(), + templates: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + abortWithStatusCheck: faker.datatype.boolean(), + awsChaos: { + action: faker.random.word(), + awsRegion: faker.random.word(), + deviceName: faker.random.word(), + duration: faker.random.word(), + ec2Instance: faker.random.word(), + endpoint: faker.random.word(), + remoteCluster: faker.random.word(), + secretName: faker.random.word(), + volumeID: faker.random.word(), + }, + azureChaos: { + action: faker.random.word(), + diskName: faker.random.word(), + duration: faker.random.word(), + lun: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + resourceGroupName: faker.random.word(), + secretName: faker.random.word(), + subscriptionID: faker.random.word(), + vmName: faker.random.word(), + }, + blockChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + delay: { correlation: faker.random.word(), jitter: faker.random.word(), latency: faker.random.word() }, + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jc0026v5di8hg1gb2k: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jc0027v5dietcw8to6: faker.random.word(), + }, + labelSelectors: { + clfp8d9jc0028v5did9pn4k5t: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jc0029v5dia2voaoxd: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + pods: { + clfp8d9jc002av5di5tud8tm0: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + volumeName: faker.random.word(), + }, + children: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + conditionalBranches: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ expression: faker.random.word(), target: faker.random.word() }) + ), + deadline: faker.random.word(), + dnsChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + patterns: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jc002bv5diervv3iz8: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jc002cv5di23iv36o8: faker.random.word(), + }, + labelSelectors: { + clfp8d9jc002dv5di5l3d33qk: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jc002ev5di06bt7z1p: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + pods: { + clfp8d9jc002fv5did7p1eqag: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + gcpChaos: { + action: faker.random.word(), + deviceNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + instance: faker.random.word(), + project: faker.random.word(), + remoteCluster: faker.random.word(), + secretName: faker.random.word(), + zone: faker.random.word(), + }, + httpChaos: { + abort: faker.datatype.boolean(), + code: faker.datatype.number({ min: undefined, max: undefined }), + delay: faker.random.word(), + duration: faker.random.word(), + method: faker.random.word(), + mode: faker.random.word(), + patch: { + body: { type: faker.random.word(), value: faker.random.word() }, + headers: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ) + ), + queries: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ) + ), + }, + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + replace: { + body: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + code: faker.datatype.number({ min: undefined, max: undefined }), + headers: { + clfp8d9jc002gv5di8um14lww: faker.random.word(), + }, + method: faker.random.word(), + path: faker.random.word(), + queries: { + clfp8d9jc002hv5dibvzf8pj1: faker.random.word(), + }, + }, + request_headers: { + clfp8d9jc002iv5di8x1i0feq: faker.random.word(), + }, + response_headers: { + clfp8d9jc002jv5di1h5h36ej: faker.random.word(), + }, + selector: { + annotationSelectors: { + clfp8d9jc002kv5di474a09rk: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jc002lv5dig9fkaiye: faker.random.word(), + }, + labelSelectors: { + clfp8d9jc002mv5diaet672nc: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jc002nv5di8fow3691: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + pods: { + clfp8d9jd002ov5di2e2q71i1: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + target: faker.random.word(), + tls: { + caName: faker.random.word(), + certName: faker.random.word(), + keyName: faker.random.word(), + secretName: faker.random.word(), + secretNamespace: faker.random.word(), + }, + value: faker.random.word(), + }, + ioChaos: { + action: faker.random.word(), + attr: { + atime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + blocks: faker.datatype.number({ min: undefined, max: undefined }), + ctime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + gid: faker.datatype.number({ min: undefined, max: undefined }), + ino: faker.datatype.number({ min: undefined, max: undefined }), + kind: faker.random.word(), + mtime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + nlink: faker.datatype.number({ min: undefined, max: undefined }), + perm: faker.datatype.number({ min: undefined, max: undefined }), + rdev: faker.datatype.number({ min: undefined, max: undefined }), + size: faker.datatype.number({ min: undefined, max: undefined }), + uid: faker.datatype.number({ min: undefined, max: undefined }), + }, + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + delay: faker.random.word(), + duration: faker.random.word(), + errno: faker.datatype.number({ min: undefined, max: undefined }), + methods: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + mistake: { + filling: faker.random.word(), + maxLength: faker.datatype.number({ min: undefined, max: undefined }), + maxOccurrences: faker.datatype.number({ min: undefined, max: undefined }), + }, + mode: faker.random.word(), + path: faker.random.word(), + percent: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jd002pv5di5s8h4po0: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jd002qv5dianlwhuzs: faker.random.word(), + }, + labelSelectors: { + clfp8d9jd002rv5di19u15trb: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jd002sv5di1p9v47zw: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + pods: { + clfp8d9jd002tv5di3k0116lh: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + volumePath: faker.random.word(), + }, + jvmChaos: { + action: faker.random.word(), + class: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + cpuCount: faker.datatype.number({ min: undefined, max: undefined }), + database: faker.random.word(), + duration: faker.random.word(), + exception: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + memType: faker.random.word(), + method: faker.random.word(), + mode: faker.random.word(), + mysqlConnectorVersion: faker.random.word(), + name: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + ruleData: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jd002uv5di5qe6hkp8: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jd002vv5diew3d807o: faker.random.word(), + }, + labelSelectors: { + clfp8d9jd002wv5di4yc8gwp6: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jd002xv5di80m54mp1: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + pods: { + clfp8d9jd002yv5dihpeqe3od: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + sqlType: faker.random.word(), + table: faker.random.word(), + value: faker.random.word(), + }, + kernelChaos: { + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + failKernRequest: { + callchain: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + funcname: faker.random.word(), + parameters: faker.random.word(), + predicate: faker.random.word(), + })), + failtype: faker.datatype.number({ min: undefined, max: undefined }), + headers: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + probability: faker.datatype.number({ min: undefined, max: undefined }), + times: faker.datatype.number({ min: undefined, max: undefined }), + }, + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jd002zv5didj4jc0et: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jd0030v5di74ez3rr2: faker.random.word(), + }, + labelSelectors: { + clfp8d9jd0031v5di4be66s3n: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jd0032v5di9ak42gu9: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + pods: { + clfp8d9jd0033v5di8a1uhxyt: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + name: faker.random.word(), + networkChaos: { + action: faker.random.word(), + bandwidth: { + buffer: faker.datatype.number({ min: undefined, max: undefined }), + limit: faker.datatype.number({ min: undefined, max: undefined }), + minburst: faker.datatype.number({ min: undefined, max: undefined }), + peakrate: faker.datatype.number({ min: undefined, max: undefined }), + rate: faker.random.word(), + }, + corrupt: { correlation: faker.random.word(), corrupt: faker.random.word() }, + delay: { + correlation: faker.random.word(), + jitter: faker.random.word(), + latency: faker.random.word(), + reorder: { + correlation: faker.random.word(), + gap: faker.datatype.number({ min: undefined, max: undefined }), + reorder: faker.random.word(), + }, + }, + device: faker.random.word(), + direction: faker.random.word(), + duplicate: { correlation: faker.random.word(), duplicate: faker.random.word() }, + duration: faker.random.word(), + externalTargets: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + loss: { correlation: faker.random.word(), loss: faker.random.word() }, + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jd0034v5di4oa6b11b: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jd0035v5didujqew6t: faker.random.word(), + }, + labelSelectors: { + clfp8d9jd0036v5difbsd90yc: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jd0037v5di1idrg4uj: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + pods: { + clfp8d9jd0038v5did8jphwar: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + target: { + mode: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jd0039v5di4hck5pbo: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jd003av5die00sglia: faker.random.word(), + }, + labelSelectors: { + clfp8d9jd003bv5die7md4mzj: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jd003cv5di0uf3153n: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + pods: { + clfp8d9jd003dv5difcpkadpr: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + targetDevice: faker.random.word(), + value: faker.random.word(), + }, + physicalmachineChaos: { + action: faker.random.word(), + address: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + clock: { + 'clock-ids-slice': faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + 'time-offset': faker.random.word(), + }, + 'disk-fill': { + 'fill-by-fallocate': faker.datatype.boolean(), + path: faker.random.word(), + size: faker.random.word(), + }, + 'disk-read-payload': { + path: faker.random.word(), + 'payload-process-num': faker.datatype.number({ min: undefined, max: undefined }), + size: faker.random.word(), + }, + 'disk-write-payload': { + path: faker.random.word(), + 'payload-process-num': faker.datatype.number({ min: undefined, max: undefined }), + size: faker.random.word(), + }, + duration: faker.random.word(), + 'file-append': { + count: faker.datatype.number({ min: undefined, max: undefined }), + data: faker.random.word(), + 'file-name': faker.random.word(), + }, + 'file-create': { 'dir-name': faker.random.word(), 'file-name': faker.random.word() }, + 'file-delete': { 'dir-name': faker.random.word(), 'file-name': faker.random.word() }, + 'file-modify': { + 'file-name': faker.random.word(), + privilege: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'file-rename': { 'dest-file': faker.random.word(), 'source-file': faker.random.word() }, + 'file-replace': { + 'dest-string': faker.random.word(), + 'file-name': faker.random.word(), + line: faker.datatype.number({ min: undefined, max: undefined }), + 'origin-string': faker.random.word(), + }, + 'http-abort': { + code: faker.random.word(), + method: faker.random.word(), + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + proxy_ports: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + target: faker.random.word(), + }, + 'http-config': { file_path: faker.random.word() }, + 'http-delay': { + code: faker.random.word(), + delay: faker.random.word(), + method: faker.random.word(), + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + proxy_ports: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + target: faker.random.word(), + }, + 'http-request': { + count: faker.datatype.number({ min: undefined, max: undefined }), + 'enable-conn-pool': faker.datatype.boolean(), + url: faker.random.word(), + }, + 'jvm-exception': { + class: faker.random.word(), + exception: faker.random.word(), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-gc': { + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-latency': { + class: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-mysql': { + database: faker.random.word(), + exception: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + mysqlConnectorVersion: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + sqlType: faker.random.word(), + table: faker.random.word(), + }, + 'jvm-return': { + class: faker.random.word(), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + value: faker.random.word(), + }, + 'jvm-rule-data': { + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + 'rule-data': faker.random.word(), + }, + 'jvm-stress': { + 'cpu-count': faker.datatype.number({ min: undefined, max: undefined }), + 'mem-type': faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'kafka-fill': { + host: faker.random.word(), + maxBytes: faker.datatype.number({ min: undefined, max: undefined }), + messageSize: faker.datatype.number({ min: undefined, max: undefined }), + password: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + reloadCommand: faker.random.word(), + topic: faker.random.word(), + username: faker.random.word(), + }, + 'kafka-flood': { + host: faker.random.word(), + messageSize: faker.datatype.number({ min: undefined, max: undefined }), + password: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + threads: faker.datatype.number({ min: undefined, max: undefined }), + topic: faker.random.word(), + username: faker.random.word(), + }, + 'kafka-io': { + configFile: faker.random.word(), + nonReadable: faker.datatype.boolean(), + nonWritable: faker.datatype.boolean(), + topic: faker.random.word(), + }, + mode: faker.random.word(), + 'network-bandwidth': { + buffer: faker.datatype.number({ min: undefined, max: undefined }), + device: faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + limit: faker.datatype.number({ min: undefined, max: undefined }), + minburst: faker.datatype.number({ min: undefined, max: undefined }), + peakrate: faker.datatype.number({ min: undefined, max: undefined }), + rate: faker.random.word(), + }, + 'network-corrupt': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-delay': { + 'accept-tcp-flags': faker.random.word(), + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + jitter: faker.random.word(), + latency: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-dns': { + 'dns-domain-name': faker.random.word(), + 'dns-ip': faker.random.word(), + 'dns-server': faker.random.word(), + }, + 'network-down': { device: faker.random.word(), duration: faker.random.word() }, + 'network-duplicate': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-flood': { + duration: faker.random.word(), + 'ip-address': faker.random.word(), + parallel: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.random.word(), + rate: faker.random.word(), + }, + 'network-loss': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-partition': { + 'accept-tcp-flags': faker.random.word(), + device: faker.random.word(), + direction: faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + }, + process: { + process: faker.random.word(), + recoverCmd: faker.random.word(), + signal: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'redis-cacheLimit': { + addr: faker.random.word(), + cacheSize: faker.random.word(), + password: faker.random.word(), + percent: faker.random.word(), + }, + 'redis-expiration': { + addr: faker.random.word(), + expiration: faker.random.word(), + key: faker.random.word(), + option: faker.random.word(), + password: faker.random.word(), + }, + 'redis-penetration': { + addr: faker.random.word(), + password: faker.random.word(), + requestNum: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'redis-restart': { + addr: faker.random.word(), + conf: faker.random.word(), + flushConfig: faker.datatype.boolean(), + password: faker.random.word(), + redisPath: faker.datatype.boolean(), + }, + 'redis-stop': { + addr: faker.random.word(), + conf: faker.random.word(), + flushConfig: faker.datatype.boolean(), + password: faker.random.word(), + redisPath: faker.datatype.boolean(), + }, + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9je003ev5di9daph5q3: faker.random.word(), + }, + fieldSelectors: { + clfp8d9je003fv5difs6wb6zg: faker.random.word(), + }, + labelSelectors: { + clfp8d9je003gv5dibj6wdcaw: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + physicalMachines: { + clfp8d9je003hv5di6mlc4bew: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + 'stress-cpu': { + load: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'stress-mem': { + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + size: faker.random.word(), + }, + user_defined: { attackCmd: faker.random.word(), recoverCmd: faker.random.word() }, + value: faker.random.word(), + vm: { 'vm-name': faker.random.word() }, + }, + podChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + gracePeriod: faker.datatype.number({ min: undefined, max: undefined }), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9je003iv5diafxuhrgj: faker.random.word(), + }, + fieldSelectors: { + clfp8d9je003jv5diay78brl1: faker.random.word(), + }, + labelSelectors: { + clfp8d9je003kv5dic5pvhowk: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9je003lv5di8otr4cyn: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + pods: { + clfp8d9je003mv5dich0b9rui: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + schedule: { + awsChaos: { + action: faker.random.word(), + awsRegion: faker.random.word(), + deviceName: faker.random.word(), + duration: faker.random.word(), + ec2Instance: faker.random.word(), + endpoint: faker.random.word(), + remoteCluster: faker.random.word(), + secretName: faker.random.word(), + volumeID: faker.random.word(), + }, + azureChaos: { + action: faker.random.word(), + diskName: faker.random.word(), + duration: faker.random.word(), + lun: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + resourceGroupName: faker.random.word(), + secretName: faker.random.word(), + subscriptionID: faker.random.word(), + vmName: faker.random.word(), + }, + blockChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + delay: { correlation: faker.random.word(), jitter: faker.random.word(), latency: faker.random.word() }, + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9je003nv5die2708di9: faker.random.word(), + }, + fieldSelectors: { + clfp8d9je003ov5di8q296vx8: faker.random.word(), + }, + labelSelectors: { + clfp8d9je003pv5dih6u2509n: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9je003qv5di9spb11fd: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + pods: { + clfp8d9jf003rv5di39m48we2: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + volumeName: faker.random.word(), + }, + concurrencyPolicy: faker.random.word(), + dnsChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + patterns: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jf003sv5dicvmbfsaf: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jf003tv5dibaro3f0u: faker.random.word(), + }, + labelSelectors: { + clfp8d9jf003uv5di2k5n1we1: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jf003vv5di4ro59lzq: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + pods: { + clfp8d9jf003wv5dib81harok: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + gcpChaos: { + action: faker.random.word(), + deviceNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + instance: faker.random.word(), + project: faker.random.word(), + remoteCluster: faker.random.word(), + secretName: faker.random.word(), + zone: faker.random.word(), + }, + historyLimit: faker.datatype.number({ min: undefined, max: undefined }), + httpChaos: { + abort: faker.datatype.boolean(), + code: faker.datatype.number({ min: undefined, max: undefined }), + delay: faker.random.word(), + duration: faker.random.word(), + method: faker.random.word(), + mode: faker.random.word(), + patch: { + body: { type: faker.random.word(), value: faker.random.word() }, + headers: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ) + ), + queries: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ) + ), + }, + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + replace: { + body: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + code: faker.datatype.number({ min: undefined, max: undefined }), + headers: { + clfp8d9jf003xv5di7dwvbhb5: faker.random.word(), + }, + method: faker.random.word(), + path: faker.random.word(), + queries: { + clfp8d9jf003yv5di5fu34d1t: faker.random.word(), + }, + }, + request_headers: { + clfp8d9jf003zv5di35cw22wl: faker.random.word(), + }, + response_headers: { + clfp8d9jf0040v5difjvf1hqb: faker.random.word(), + }, + selector: { + annotationSelectors: { + clfp8d9jf0041v5di9b7s9zmo: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jf0042v5di3zpzfvq3: faker.random.word(), + }, + labelSelectors: { + clfp8d9jf0043v5digs50enqm: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jf0044v5didzlwh1wt: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + pods: { + clfp8d9jf0045v5difkz0bbx1: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + target: faker.random.word(), + tls: { + caName: faker.random.word(), + certName: faker.random.word(), + keyName: faker.random.word(), + secretName: faker.random.word(), + secretNamespace: faker.random.word(), + }, + value: faker.random.word(), + }, + ioChaos: { + action: faker.random.word(), + attr: { + atime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + blocks: faker.datatype.number({ min: undefined, max: undefined }), + ctime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + gid: faker.datatype.number({ min: undefined, max: undefined }), + ino: faker.datatype.number({ min: undefined, max: undefined }), + kind: faker.random.word(), + mtime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + nlink: faker.datatype.number({ min: undefined, max: undefined }), + perm: faker.datatype.number({ min: undefined, max: undefined }), + rdev: faker.datatype.number({ min: undefined, max: undefined }), + size: faker.datatype.number({ min: undefined, max: undefined }), + uid: faker.datatype.number({ min: undefined, max: undefined }), + }, + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + delay: faker.random.word(), + duration: faker.random.word(), + errno: faker.datatype.number({ min: undefined, max: undefined }), + methods: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + mistake: { + filling: faker.random.word(), + maxLength: faker.datatype.number({ min: undefined, max: undefined }), + maxOccurrences: faker.datatype.number({ min: undefined, max: undefined }), + }, + mode: faker.random.word(), + path: faker.random.word(), + percent: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jf0046v5di2jhrd03l: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jf0047v5dibyv2f376: faker.random.word(), + }, + labelSelectors: { + clfp8d9jf0048v5didmlxcid9: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jf0049v5di0dlpd0sq: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + pods: { + clfp8d9jf004av5di31s2b2d6: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + volumePath: faker.random.word(), + }, + jvmChaos: { + action: faker.random.word(), + class: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + cpuCount: faker.datatype.number({ min: undefined, max: undefined }), + database: faker.random.word(), + duration: faker.random.word(), + exception: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + memType: faker.random.word(), + method: faker.random.word(), + mode: faker.random.word(), + mysqlConnectorVersion: faker.random.word(), + name: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + ruleData: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jf004bv5di0uw4hbce: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jf004cv5di5gd88h0n: faker.random.word(), + }, + labelSelectors: { + clfp8d9jf004dv5di70cr3aac: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jf004ev5dicz5qboq6: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + pods: { + clfp8d9jf004fv5difybobwrb: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + sqlType: faker.random.word(), + table: faker.random.word(), + value: faker.random.word(), + }, + kernelChaos: { + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + duration: faker.random.word(), + failKernRequest: { + callchain: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ + funcname: faker.random.word(), + parameters: faker.random.word(), + predicate: faker.random.word(), + }) + ), + failtype: faker.datatype.number({ min: undefined, max: undefined }), + headers: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + probability: faker.datatype.number({ min: undefined, max: undefined }), + times: faker.datatype.number({ min: undefined, max: undefined }), + }, + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jf004gv5di9dvoa3q0: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jf004hv5dibw257rsz: faker.random.word(), + }, + labelSelectors: { + clfp8d9jf004iv5dihgki49mm: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jf004jv5di5cp8dxwy: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + pods: { + clfp8d9jf004kv5di0hil0dcm: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + networkChaos: { + action: faker.random.word(), + bandwidth: { + buffer: faker.datatype.number({ min: undefined, max: undefined }), + limit: faker.datatype.number({ min: undefined, max: undefined }), + minburst: faker.datatype.number({ min: undefined, max: undefined }), + peakrate: faker.datatype.number({ min: undefined, max: undefined }), + rate: faker.random.word(), + }, + corrupt: { correlation: faker.random.word(), corrupt: faker.random.word() }, + delay: { + correlation: faker.random.word(), + jitter: faker.random.word(), + latency: faker.random.word(), + reorder: { + correlation: faker.random.word(), + gap: faker.datatype.number({ min: undefined, max: undefined }), + reorder: faker.random.word(), + }, + }, + device: faker.random.word(), + direction: faker.random.word(), + duplicate: { correlation: faker.random.word(), duplicate: faker.random.word() }, + duration: faker.random.word(), + externalTargets: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + loss: { correlation: faker.random.word(), loss: faker.random.word() }, + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jf004lv5dicmso1r45: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jf004mv5diheacc7dj: faker.random.word(), + }, + labelSelectors: { + clfp8d9jf004nv5didcvzc5h9: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jg004ov5diajjnhxfe: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + pods: { + clfp8d9jg004pv5di8zcq0w7v: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + target: { + mode: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jg004qv5di6fazgy4b: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jg004rv5diepcf2ct3: faker.random.word(), + }, + labelSelectors: { + clfp8d9jg004sv5di9mlo2lmw: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + nodeSelectors: { + clfp8d9jg004tv5dihx4hdn4t: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + pods: { + clfp8d9jg004uv5diaf8thqty: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + targetDevice: faker.random.word(), + value: faker.random.word(), + }, + physicalmachineChaos: { + action: faker.random.word(), + address: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + clock: { + 'clock-ids-slice': faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + 'time-offset': faker.random.word(), + }, + 'disk-fill': { + 'fill-by-fallocate': faker.datatype.boolean(), + path: faker.random.word(), + size: faker.random.word(), + }, + 'disk-read-payload': { + path: faker.random.word(), + 'payload-process-num': faker.datatype.number({ min: undefined, max: undefined }), + size: faker.random.word(), + }, + 'disk-write-payload': { + path: faker.random.word(), + 'payload-process-num': faker.datatype.number({ min: undefined, max: undefined }), + size: faker.random.word(), + }, + duration: faker.random.word(), + 'file-append': { + count: faker.datatype.number({ min: undefined, max: undefined }), + data: faker.random.word(), + 'file-name': faker.random.word(), + }, + 'file-create': { 'dir-name': faker.random.word(), 'file-name': faker.random.word() }, + 'file-delete': { 'dir-name': faker.random.word(), 'file-name': faker.random.word() }, + 'file-modify': { + 'file-name': faker.random.word(), + privilege: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'file-rename': { 'dest-file': faker.random.word(), 'source-file': faker.random.word() }, + 'file-replace': { + 'dest-string': faker.random.word(), + 'file-name': faker.random.word(), + line: faker.datatype.number({ min: undefined, max: undefined }), + 'origin-string': faker.random.word(), + }, + 'http-abort': { + code: faker.random.word(), + method: faker.random.word(), + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + proxy_ports: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + target: faker.random.word(), + }, + 'http-config': { file_path: faker.random.word() }, + 'http-delay': { + code: faker.random.word(), + delay: faker.random.word(), + method: faker.random.word(), + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + proxy_ports: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + target: faker.random.word(), + }, + 'http-request': { + count: faker.datatype.number({ min: undefined, max: undefined }), + 'enable-conn-pool': faker.datatype.boolean(), + url: faker.random.word(), + }, + 'jvm-exception': { + class: faker.random.word(), + exception: faker.random.word(), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-gc': { + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-latency': { + class: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-mysql': { + database: faker.random.word(), + exception: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + mysqlConnectorVersion: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + sqlType: faker.random.word(), + table: faker.random.word(), + }, + 'jvm-return': { + class: faker.random.word(), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + value: faker.random.word(), + }, + 'jvm-rule-data': { + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + 'rule-data': faker.random.word(), + }, + 'jvm-stress': { + 'cpu-count': faker.datatype.number({ min: undefined, max: undefined }), + 'mem-type': faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'kafka-fill': { + host: faker.random.word(), + maxBytes: faker.datatype.number({ min: undefined, max: undefined }), + messageSize: faker.datatype.number({ min: undefined, max: undefined }), + password: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + reloadCommand: faker.random.word(), + topic: faker.random.word(), + username: faker.random.word(), + }, + 'kafka-flood': { + host: faker.random.word(), + messageSize: faker.datatype.number({ min: undefined, max: undefined }), + password: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + threads: faker.datatype.number({ min: undefined, max: undefined }), + topic: faker.random.word(), + username: faker.random.word(), + }, + 'kafka-io': { + configFile: faker.random.word(), + nonReadable: faker.datatype.boolean(), + nonWritable: faker.datatype.boolean(), + topic: faker.random.word(), + }, + mode: faker.random.word(), + 'network-bandwidth': { + buffer: faker.datatype.number({ min: undefined, max: undefined }), + device: faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + limit: faker.datatype.number({ min: undefined, max: undefined }), + minburst: faker.datatype.number({ min: undefined, max: undefined }), + peakrate: faker.datatype.number({ min: undefined, max: undefined }), + rate: faker.random.word(), + }, + 'network-corrupt': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-delay': { + 'accept-tcp-flags': faker.random.word(), + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + jitter: faker.random.word(), + latency: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-dns': { + 'dns-domain-name': faker.random.word(), + 'dns-ip': faker.random.word(), + 'dns-server': faker.random.word(), + }, + 'network-down': { device: faker.random.word(), duration: faker.random.word() }, + 'network-duplicate': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-flood': { + duration: faker.random.word(), + 'ip-address': faker.random.word(), + parallel: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.random.word(), + rate: faker.random.word(), + }, + 'network-loss': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-partition': { + 'accept-tcp-flags': faker.random.word(), + device: faker.random.word(), + direction: faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + }, + process: { + process: faker.random.word(), + recoverCmd: faker.random.word(), + signal: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'redis-cacheLimit': { + addr: faker.random.word(), + cacheSize: faker.random.word(), + password: faker.random.word(), + percent: faker.random.word(), + }, + 'redis-expiration': { + addr: faker.random.word(), + expiration: faker.random.word(), + key: faker.random.word(), + option: faker.random.word(), + password: faker.random.word(), + }, + 'redis-penetration': { + addr: faker.random.word(), + password: faker.random.word(), + requestNum: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'redis-restart': { + addr: faker.random.word(), + conf: faker.random.word(), + flushConfig: faker.datatype.boolean(), + password: faker.random.word(), + redisPath: faker.datatype.boolean(), + }, + 'redis-stop': { + addr: faker.random.word(), + conf: faker.random.word(), + flushConfig: faker.datatype.boolean(), + password: faker.random.word(), + redisPath: faker.datatype.boolean(), + }, + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jg004vv5di7n5bg9x8: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jg004wv5dibnic6d12: faker.random.word(), + }, + labelSelectors: { + clfp8d9jg004xv5didspqe6s7: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + physicalMachines: { + clfp8d9jh004yv5di35cj81wt: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + 'stress-cpu': { + load: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'stress-mem': { + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + size: faker.random.word(), + }, + user_defined: { attackCmd: faker.random.word(), recoverCmd: faker.random.word() }, + value: faker.random.word(), + vm: { 'vm-name': faker.random.word() }, + }, + podChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + duration: faker.random.word(), + gracePeriod: faker.datatype.number({ min: undefined, max: undefined }), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jh004zv5di77pldmaj: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jh0050v5di3h35euif: faker.random.word(), + }, + labelSelectors: { + clfp8d9jh0051v5dibxbvhycy: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jh0052v5dihvqc00zm: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + pods: { + clfp8d9jh0053v5di2ibb4d2u: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + schedule: faker.random.word(), + startingDeadlineSeconds: faker.datatype.number({ min: undefined, max: undefined }), + stressChaos: { + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jh0054v5didsfe4kvk: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jh0055v5dih88chlqh: faker.random.word(), + }, + labelSelectors: { + clfp8d9jh0056v5di58sjbk04: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jh0057v5di0jiifk1v: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + pods: { + clfp8d9jh0058v5di7nj4gehc: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + stressngStressors: faker.random.word(), + stressors: { + cpu: { + load: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + memory: { + oomScoreAdj: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + size: faker.random.word(), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + value: faker.random.word(), + }, + timeChaos: { + clockIds: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jh0059v5di6swcc5ln: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jh005av5dig7e2afpu: faker.random.word(), + }, + labelSelectors: { + clfp8d9jh005bv5di4zjk273p: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jh005cv5di1idmeght: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + pods: { + clfp8d9jh005dv5dib6rl01nh: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + timeOffset: faker.random.word(), + value: faker.random.word(), + }, + type: faker.random.word(), + }, + statusCheck: { + duration: faker.random.word(), + failureThreshold: faker.datatype.number({ min: undefined, max: undefined }), + http: { + body: faker.random.word(), + criteria: { statusCode: faker.random.word() }, + headers: { + clfp8d9jh005ev5die7in20yv: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + method: faker.random.word(), + url: faker.random.word(), + }, + intervalSeconds: faker.datatype.number({ min: undefined, max: undefined }), + mode: faker.random.word(), + recordsHistoryLimit: faker.datatype.number({ min: undefined, max: undefined }), + successThreshold: faker.datatype.number({ min: undefined, max: undefined }), + timeoutSeconds: faker.datatype.number({ min: undefined, max: undefined }), + type: faker.random.word(), + }, + stressChaos: { + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jh005fv5didpoh6m27: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jh005gv5di49cf9boy: faker.random.word(), + }, + labelSelectors: { + clfp8d9jh005hv5dicmao0qb3: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jh005iv5di1qho9vwd: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + pods: { + clfp8d9jh005jv5di87l9gy2z: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + stressngStressors: faker.random.word(), + stressors: { + cpu: { + load: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + memory: { + oomScoreAdj: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + size: faker.random.word(), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + value: faker.random.word(), + }, + task: { + container: { + args: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + command: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + env: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + name: faker.random.word(), + value: faker.random.word(), + valueFrom: { + configMapKeyRef: { + key: faker.random.word(), + name: faker.random.word(), + optional: faker.datatype.boolean(), + }, + fieldRef: { apiVersion: faker.random.word(), fieldPath: faker.random.word() }, + resourceFieldRef: { + containerName: faker.random.word(), + divisor: { Format: faker.random.word() }, + resource: faker.random.word(), + }, + secretKeyRef: { + key: faker.random.word(), + name: faker.random.word(), + optional: faker.datatype.boolean(), + }, + }, + })), + envFrom: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + configMapRef: { name: faker.random.word(), optional: faker.datatype.boolean() }, + prefix: faker.random.word(), + secretRef: { name: faker.random.word(), optional: faker.datatype.boolean() }, + })), + image: faker.random.word(), + imagePullPolicy: faker.random.word(), + lifecycle: { + postStart: { + exec: { + command: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }, + httpGet: { + host: faker.random.word(), + httpHeaders: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ name: faker.random.word(), value: faker.random.word() }) + ), + path: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + scheme: faker.random.word(), + }, + tcpSocket: { + host: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + }, + preStop: { + exec: { + command: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }, + httpGet: { + host: faker.random.word(), + httpHeaders: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ name: faker.random.word(), value: faker.random.word() }) + ), + path: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + scheme: faker.random.word(), + }, + tcpSocket: { + host: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + }, + }, + livenessProbe: { + exec: { + command: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }, + failureThreshold: faker.datatype.number({ min: undefined, max: undefined }), + grpc: { port: faker.datatype.number({ min: undefined, max: undefined }), service: faker.random.word() }, + httpGet: { + host: faker.random.word(), + httpHeaders: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ name: faker.random.word(), value: faker.random.word() }) + ), + path: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + scheme: faker.random.word(), + }, + initialDelaySeconds: faker.datatype.number({ min: undefined, max: undefined }), + periodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + successThreshold: faker.datatype.number({ min: undefined, max: undefined }), + tcpSocket: { + host: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + terminationGracePeriodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + timeoutSeconds: faker.datatype.number({ min: undefined, max: undefined }), + }, + name: faker.random.word(), + ports: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + containerPort: faker.datatype.number({ min: undefined, max: undefined }), + hostIP: faker.random.word(), + hostPort: faker.datatype.number({ min: undefined, max: undefined }), + name: faker.random.word(), + protocol: faker.random.word(), + })), + readinessProbe: { + exec: { + command: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }, + failureThreshold: faker.datatype.number({ min: undefined, max: undefined }), + grpc: { port: faker.datatype.number({ min: undefined, max: undefined }), service: faker.random.word() }, + httpGet: { + host: faker.random.word(), + httpHeaders: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ name: faker.random.word(), value: faker.random.word() }) + ), + path: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + scheme: faker.random.word(), + }, + initialDelaySeconds: faker.datatype.number({ min: undefined, max: undefined }), + periodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + successThreshold: faker.datatype.number({ min: undefined, max: undefined }), + tcpSocket: { + host: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + terminationGracePeriodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + timeoutSeconds: faker.datatype.number({ min: undefined, max: undefined }), + }, + resources: { + claims: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + name: faker.random.word(), + })), + limits: { + clfp8d9ji005kv5di1qx17h2h: { Format: faker.random.word() }, + }, + requests: { + clfp8d9ji005lv5di4qwp47gh: { Format: faker.random.word() }, + }, + }, + securityContext: { + allowPrivilegeEscalation: faker.datatype.boolean(), + capabilities: { + add: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + drop: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }, + privileged: faker.datatype.boolean(), + procMount: faker.random.word(), + readOnlyRootFilesystem: faker.datatype.boolean(), + runAsGroup: faker.datatype.number({ min: undefined, max: undefined }), + runAsNonRoot: faker.datatype.boolean(), + runAsUser: faker.datatype.number({ min: undefined, max: undefined }), + seLinuxOptions: { + level: faker.random.word(), + role: faker.random.word(), + type: faker.random.word(), + user: faker.random.word(), + }, + seccompProfile: { localhostProfile: faker.random.word(), type: faker.random.word() }, + windowsOptions: { + gmsaCredentialSpec: faker.random.word(), + gmsaCredentialSpecName: faker.random.word(), + hostProcess: faker.datatype.boolean(), + runAsUserName: faker.random.word(), + }, + }, + startupProbe: { + exec: { + command: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }, + failureThreshold: faker.datatype.number({ min: undefined, max: undefined }), + grpc: { port: faker.datatype.number({ min: undefined, max: undefined }), service: faker.random.word() }, + httpGet: { + host: faker.random.word(), + httpHeaders: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ name: faker.random.word(), value: faker.random.word() }) + ), + path: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + scheme: faker.random.word(), + }, + initialDelaySeconds: faker.datatype.number({ min: undefined, max: undefined }), + periodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + successThreshold: faker.datatype.number({ min: undefined, max: undefined }), + tcpSocket: { + host: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + terminationGracePeriodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + timeoutSeconds: faker.datatype.number({ min: undefined, max: undefined }), + }, + stdin: faker.datatype.boolean(), + stdinOnce: faker.datatype.boolean(), + terminationMessagePath: faker.random.word(), + terminationMessagePolicy: faker.random.word(), + tty: faker.datatype.boolean(), + volumeDevices: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ devicePath: faker.random.word(), name: faker.random.word() }) + ), + volumeMounts: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ + mountPath: faker.random.word(), + mountPropagation: faker.random.word(), + name: faker.random.word(), + readOnly: faker.datatype.boolean(), + subPath: faker.random.word(), + subPathExpr: faker.random.word(), + }) + ), + workingDir: faker.random.word(), + }, + volumes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + awsElasticBlockStore: { + fsType: faker.random.word(), + partition: faker.datatype.number({ min: undefined, max: undefined }), + readOnly: faker.datatype.boolean(), + volumeID: faker.random.word(), + }, + azureDisk: { + cachingMode: faker.random.word(), + diskName: faker.random.word(), + diskURI: faker.random.word(), + fsType: faker.random.word(), + kind: faker.random.word(), + readOnly: faker.datatype.boolean(), + }, + azureFile: { + readOnly: faker.datatype.boolean(), + secretName: faker.random.word(), + shareName: faker.random.word(), + }, + cephfs: { + monitors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + path: faker.random.word(), + readOnly: faker.datatype.boolean(), + secretFile: faker.random.word(), + secretRef: { name: faker.random.word() }, + user: faker.random.word(), + }, + cinder: { + fsType: faker.random.word(), + readOnly: faker.datatype.boolean(), + secretRef: { name: faker.random.word() }, + volumeID: faker.random.word(), + }, + configMap: { + defaultMode: faker.datatype.number({ min: undefined, max: undefined }), + items: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + key: faker.random.word(), + mode: faker.datatype.number({ min: undefined, max: undefined }), + path: faker.random.word(), + })), + name: faker.random.word(), + optional: faker.datatype.boolean(), + }, + csi: { + driver: faker.random.word(), + fsType: faker.random.word(), + nodePublishSecretRef: { name: faker.random.word() }, + readOnly: faker.datatype.boolean(), + volumeAttributes: { + clfp8d9ji005mv5dicmkt77nd: faker.random.word(), + }, + }, + downwardAPI: { + defaultMode: faker.datatype.number({ min: undefined, max: undefined }), + items: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + fieldRef: { apiVersion: faker.random.word(), fieldPath: faker.random.word() }, + mode: faker.datatype.number({ min: undefined, max: undefined }), + path: faker.random.word(), + resourceFieldRef: { + containerName: faker.random.word(), + divisor: { Format: faker.random.word() }, + resource: faker.random.word(), + }, + })), + }, + emptyDir: { medium: faker.random.word(), sizeLimit: { Format: faker.random.word() } }, + ephemeral: { + volumeClaimTemplate: { + annotations: { + clfp8d9ji005nv5difz975qt0: faker.random.word(), + }, + creationTimestamp: faker.random.word(), + deletionGracePeriodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + deletionTimestamp: faker.random.word(), + finalizers: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + generateName: faker.random.word(), + generation: faker.datatype.number({ min: undefined, max: undefined }), + labels: { + clfp8d9jj005ov5die0h931sw: faker.random.word(), + }, + managedFields: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ + apiVersion: faker.random.word(), + fieldsType: faker.random.word(), + fieldsV1: {}, + manager: faker.random.word(), + operation: faker.random.word(), + subresource: faker.random.word(), + time: faker.random.word(), + }) + ), + name: faker.random.word(), + namespace: faker.random.word(), + ownerReferences: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => ({ + apiVersion: faker.random.word(), + blockOwnerDeletion: faker.datatype.boolean(), + controller: faker.datatype.boolean(), + kind: faker.random.word(), + name: faker.random.word(), + uid: faker.random.word(), + })), + resourceVersion: faker.random.word(), + selfLink: faker.random.word(), + uid: faker.random.word(), + }, + }, + fc: { + fsType: faker.random.word(), + lun: faker.datatype.number({ min: undefined, max: undefined }), + readOnly: faker.datatype.boolean(), + targetWWNs: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + wwids: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }, + flexVolume: { + driver: faker.random.word(), + fsType: faker.random.word(), + options: { + clfp8d9jj005pv5dieutp33c3: faker.random.word(), + }, + readOnly: faker.datatype.boolean(), + secretRef: { name: faker.random.word() }, + }, + flocker: { datasetName: faker.random.word(), datasetUUID: faker.random.word() }, + gcePersistentDisk: { + fsType: faker.random.word(), + partition: faker.datatype.number({ min: undefined, max: undefined }), + pdName: faker.random.word(), + readOnly: faker.datatype.boolean(), + }, + gitRepo: { directory: faker.random.word(), repository: faker.random.word(), revision: faker.random.word() }, + glusterfs: { + endpoints: faker.random.word(), + path: faker.random.word(), + readOnly: faker.datatype.boolean(), + }, + hostPath: { path: faker.random.word(), type: faker.random.word() }, + iscsi: { + chapAuthDiscovery: faker.datatype.boolean(), + chapAuthSession: faker.datatype.boolean(), + fsType: faker.random.word(), + initiatorName: faker.random.word(), + iqn: faker.random.word(), + iscsiInterface: faker.random.word(), + lun: faker.datatype.number({ min: undefined, max: undefined }), + portals: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + readOnly: faker.datatype.boolean(), + secretRef: { name: faker.random.word() }, + targetPortal: faker.random.word(), + }, + name: faker.random.word(), + nfs: { path: faker.random.word(), readOnly: faker.datatype.boolean(), server: faker.random.word() }, + persistentVolumeClaim: { claimName: faker.random.word(), readOnly: faker.datatype.boolean() }, + photonPersistentDisk: { fsType: faker.random.word(), pdID: faker.random.word() }, + portworxVolume: { + fsType: faker.random.word(), + readOnly: faker.datatype.boolean(), + volumeID: faker.random.word(), + }, + projected: { + defaultMode: faker.datatype.number({ min: undefined, max: undefined }), + sources: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + configMap: { + items: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ + key: faker.random.word(), + mode: faker.datatype.number({ min: undefined, max: undefined }), + path: faker.random.word(), + }) + ), + name: faker.random.word(), + optional: faker.datatype.boolean(), + }, + downwardAPI: { + items: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ + fieldRef: { apiVersion: faker.random.word(), fieldPath: faker.random.word() }, + mode: faker.datatype.number({ min: undefined, max: undefined }), + path: faker.random.word(), + resourceFieldRef: { + containerName: faker.random.word(), + divisor: { Format: faker.random.word() }, + resource: faker.random.word(), + }, + }) + ), + }, + secret: { + items: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ + key: faker.random.word(), + mode: faker.datatype.number({ min: undefined, max: undefined }), + path: faker.random.word(), + }) + ), + name: faker.random.word(), + optional: faker.datatype.boolean(), + }, + serviceAccountToken: { + audience: faker.random.word(), + expirationSeconds: faker.datatype.number({ min: undefined, max: undefined }), + path: faker.random.word(), + }, + })), + }, + quobyte: { + group: faker.random.word(), + readOnly: faker.datatype.boolean(), + registry: faker.random.word(), + tenant: faker.random.word(), + user: faker.random.word(), + volume: faker.random.word(), + }, + rbd: { + fsType: faker.random.word(), + image: faker.random.word(), + keyring: faker.random.word(), + monitors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pool: faker.random.word(), + readOnly: faker.datatype.boolean(), + secretRef: { name: faker.random.word() }, + user: faker.random.word(), + }, + scaleIO: { + fsType: faker.random.word(), + gateway: faker.random.word(), + protectionDomain: faker.random.word(), + readOnly: faker.datatype.boolean(), + secretRef: { name: faker.random.word() }, + sslEnabled: faker.datatype.boolean(), + storageMode: faker.random.word(), + storagePool: faker.random.word(), + system: faker.random.word(), + volumeName: faker.random.word(), + }, + secret: { + defaultMode: faker.datatype.number({ min: undefined, max: undefined }), + items: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + key: faker.random.word(), + mode: faker.datatype.number({ min: undefined, max: undefined }), + path: faker.random.word(), + })), + optional: faker.datatype.boolean(), + secretName: faker.random.word(), + }, + storageos: { + fsType: faker.random.word(), + readOnly: faker.datatype.boolean(), + secretRef: { name: faker.random.word() }, + volumeName: faker.random.word(), + volumeNamespace: faker.random.word(), + }, + vsphereVolume: { + fsType: faker.random.word(), + storagePolicyID: faker.random.word(), + storagePolicyName: faker.random.word(), + volumePath: faker.random.word(), + }, + })), + }, + templateType: faker.random.word(), + timeChaos: { + clockIds: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jk005qv5di34j8c9pd: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jk005rv5di4q5w9cr8: faker.random.word(), + }, + labelSelectors: { + clfp8d9jk005sv5di90rs9bcb: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jk005tv5dibc8eft7p: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + pods: { + clfp8d9jk005uv5di9jmt7qes: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + timeOffset: faker.random.word(), + value: faker.random.word(), + }, + })), + }, + }, + status: { + active: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + apiVersion: faker.random.word(), + fieldPath: faker.random.word(), + kind: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + resourceVersion: faker.random.word(), + uid: faker.random.word(), + })), + time: faker.random.word(), + }, + uid: faker.random.word(), +}) + +export const getDeleteSchedulesUidMock = () => ({ status: faker.random.word() }) + +export const getGetSchedulesUidMock = () => ({ + created_at: faker.random.word(), + experiment_uids: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + kind: faker.random.word(), + kube_object: { + apiVersion: faker.random.word(), + kind: faker.random.word(), + metadata: { + annotations: { + clfp8d9jm005vv5di9ymkht49: faker.random.word(), + }, + labels: { + clfp8d9jm005wv5di8m1zgrxv: faker.random.word(), + }, + name: faker.random.word(), + namespace: faker.random.word(), + }, + spec: {}, + }, + name: faker.random.word(), + namespace: faker.random.word(), + status: faker.random.word(), + uid: faker.random.word(), +}) + +export const getPutSchedulesPauseUidMock = () => ({ status: faker.random.word() }) + +export const getPutSchedulesStartUidMock = () => ({ status: faker.random.word() }) + +export const getGetTemplatesStatuschecksMock = () => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + created_at: faker.random.word(), + description: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + uid: faker.random.word(), + })) + +export const getPostTemplatesStatuschecksMock = () => ({ + description: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + spec: { + duration: faker.random.word(), + failureThreshold: faker.datatype.number({ min: undefined, max: undefined }), + http: { + body: faker.random.word(), + criteria: { statusCode: faker.random.word() }, + headers: { + clfp8d9jo005xv5di8pgx6uhg: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + method: faker.random.word(), + url: faker.random.word(), + }, + intervalSeconds: faker.datatype.number({ min: undefined, max: undefined }), + mode: faker.random.word(), + recordsHistoryLimit: faker.datatype.number({ min: undefined, max: undefined }), + successThreshold: faker.datatype.number({ min: undefined, max: undefined }), + timeoutSeconds: faker.datatype.number({ min: undefined, max: undefined }), + type: faker.random.word(), + }, +}) + +export const getDeleteTemplatesStatuschecksStatuscheckMock = () => ({ status: faker.random.word() }) + +export const getGetTemplatesStatuschecksStatuscheckMock = () => ({ + created_at: faker.random.word(), + description: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + spec: { + duration: faker.random.word(), + failureThreshold: faker.datatype.number({ min: undefined, max: undefined }), + http: { + body: faker.random.word(), + criteria: { statusCode: faker.random.word() }, + headers: { + clfp8d9jp005yv5dihw6c32wy: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + method: faker.random.word(), + url: faker.random.word(), + }, + intervalSeconds: faker.datatype.number({ min: undefined, max: undefined }), + mode: faker.random.word(), + recordsHistoryLimit: faker.datatype.number({ min: undefined, max: undefined }), + successThreshold: faker.datatype.number({ min: undefined, max: undefined }), + timeoutSeconds: faker.datatype.number({ min: undefined, max: undefined }), + type: faker.random.word(), + }, + uid: faker.random.word(), +}) + +export const getPutTemplatesStatuschecksStatuscheckMock = () => ({ + description: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + spec: { + duration: faker.random.word(), + failureThreshold: faker.datatype.number({ min: undefined, max: undefined }), + http: { + body: faker.random.word(), + criteria: { statusCode: faker.random.word() }, + headers: { + clfp8d9jp005zv5di73a3ehx1: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + method: faker.random.word(), + url: faker.random.word(), + }, + intervalSeconds: faker.datatype.number({ min: undefined, max: undefined }), + mode: faker.random.word(), + recordsHistoryLimit: faker.datatype.number({ min: undefined, max: undefined }), + successThreshold: faker.datatype.number({ min: undefined, max: undefined }), + timeoutSeconds: faker.datatype.number({ min: undefined, max: undefined }), + type: faker.random.word(), + }, +}) + +export const getGetWorkflowsMock = () => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + created_at: faker.random.word(), + end_time: faker.random.word(), + entry: faker.random.word(), + finish_time: faker.random.word(), + id: faker.datatype.number({ min: undefined, max: undefined }), + name: faker.random.word(), + namespace: faker.random.word(), + status: faker.random.word(), + uid: faker.random.word(), + })) + +export const getPostWorkflowsMock = () => ({ + created_at: faker.random.word(), + end_time: faker.random.word(), + entry: faker.random.word(), + finish_time: faker.random.word(), + id: faker.datatype.number({ min: undefined, max: undefined }), + kube_object: { + apiVersion: faker.random.word(), + kind: faker.random.word(), + metadata: { + annotations: { + clfp8d9jq0060v5dic6seg5ea: faker.random.word(), + }, + labels: { + clfp8d9jq0061v5di5zsgax87: faker.random.word(), + }, + name: faker.random.word(), + namespace: faker.random.word(), + }, + spec: {}, + }, + name: faker.random.word(), + namespace: faker.random.word(), + status: faker.random.word(), + topology: { + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + conditional_branches: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ expression: faker.random.word(), name: faker.random.word(), template: faker.random.word() }) + ), + name: faker.random.word(), + parallel: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + name: faker.random.word(), + template: faker.random.word(), + })), + serial: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + name: faker.random.word(), + template: faker.random.word(), + })), + state: faker.random.word(), + template: faker.random.word(), + type: faker.random.word(), + uid: faker.random.word(), + })), + }, + uid: faker.random.word(), +}) + +export const getDeleteWorkflowsUidMock = () => ({ status: faker.random.word() }) + +export const getGetWorkflowsUidMock = () => ({ + created_at: faker.random.word(), + end_time: faker.random.word(), + entry: faker.random.word(), + finish_time: faker.random.word(), + id: faker.datatype.number({ min: undefined, max: undefined }), + kube_object: { + apiVersion: faker.random.word(), + kind: faker.random.word(), + metadata: { + annotations: { + clfp8d9jr0062v5diezph2yko: faker.random.word(), + }, + labels: { + clfp8d9jr0063v5dics022gmz: faker.random.word(), + }, + name: faker.random.word(), + namespace: faker.random.word(), + }, + spec: {}, + }, + name: faker.random.word(), + namespace: faker.random.word(), + status: faker.random.word(), + topology: { + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + conditional_branches: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ expression: faker.random.word(), name: faker.random.word(), template: faker.random.word() }) + ), + name: faker.random.word(), + parallel: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + name: faker.random.word(), + template: faker.random.word(), + })), + serial: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + name: faker.random.word(), + template: faker.random.word(), + })), + state: faker.random.word(), + template: faker.random.word(), + type: faker.random.word(), + uid: faker.random.word(), + })), + }, + uid: faker.random.word(), +}) + +export const getPutWorkflowsUidMock = () => ({ + created_at: faker.random.word(), + end_time: faker.random.word(), + entry: faker.random.word(), + finish_time: faker.random.word(), + id: faker.datatype.number({ min: undefined, max: undefined }), + kube_object: { + apiVersion: faker.random.word(), + kind: faker.random.word(), + metadata: { + annotations: { + clfp8d9jr0064v5di9riu0uti: faker.random.word(), + }, + labels: { + clfp8d9jr0065v5di53k6dabk: faker.random.word(), + }, + name: faker.random.word(), + namespace: faker.random.word(), + }, + spec: {}, + }, + name: faker.random.word(), + namespace: faker.random.word(), + status: faker.random.word(), + topology: { + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + conditional_branches: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ expression: faker.random.word(), name: faker.random.word(), template: faker.random.word() }) + ), + name: faker.random.word(), + parallel: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + name: faker.random.word(), + template: faker.random.word(), + })), + serial: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + name: faker.random.word(), + template: faker.random.word(), + })), + state: faker.random.word(), + template: faker.random.word(), + type: faker.random.word(), + uid: faker.random.word(), + })), + }, + uid: faker.random.word(), +}) + +export const getPostWorkflowsParseTaskHttpMock = () => ({ + body: faker.random.word(), + followLocation: faker.datatype.boolean(), + header: { + clfp8d9js0066v5dicvfac03q: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + }, + jsonContent: faker.datatype.boolean(), + method: faker.random.word(), + name: faker.random.word(), + url: faker.random.word(), +}) + +export const getPostWorkflowsRenderTaskHttpMock = () => ({ + abortWithStatusCheck: faker.datatype.boolean(), + awsChaos: { + action: faker.random.word(), + awsRegion: faker.random.word(), + deviceName: faker.random.word(), + duration: faker.random.word(), + ec2Instance: faker.random.word(), + endpoint: faker.random.word(), + remoteCluster: faker.random.word(), + secretName: faker.random.word(), + volumeID: faker.random.word(), + }, + azureChaos: { + action: faker.random.word(), + diskName: faker.random.word(), + duration: faker.random.word(), + lun: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + resourceGroupName: faker.random.word(), + secretName: faker.random.word(), + subscriptionID: faker.random.word(), + vmName: faker.random.word(), + }, + blockChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + delay: { correlation: faker.random.word(), jitter: faker.random.word(), latency: faker.random.word() }, + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9js0067v5di221e3q0p: faker.random.word(), + }, + fieldSelectors: { + clfp8d9js0068v5dig7af6l1a: faker.random.word(), + }, + labelSelectors: { + clfp8d9js0069v5di6cx4hild: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9js006av5di5bp2gbjc: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9js006bv5di6q4bhcb7: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + volumeName: faker.random.word(), + }, + children: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + conditionalBranches: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + expression: faker.random.word(), + target: faker.random.word(), + })), + deadline: faker.random.word(), + dnsChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + patterns: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9js006cv5dicje6gjfd: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jt006dv5dic5v4drzx: faker.random.word(), + }, + labelSelectors: { + clfp8d9jt006ev5di0h80dwwp: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jt006fv5di366lfh6b: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jt006gv5di4iyh5lqj: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + gcpChaos: { + action: faker.random.word(), + deviceNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + instance: faker.random.word(), + project: faker.random.word(), + remoteCluster: faker.random.word(), + secretName: faker.random.word(), + zone: faker.random.word(), + }, + httpChaos: { + abort: faker.datatype.boolean(), + code: faker.datatype.number({ min: undefined, max: undefined }), + delay: faker.random.word(), + duration: faker.random.word(), + method: faker.random.word(), + mode: faker.random.word(), + patch: { + body: { type: faker.random.word(), value: faker.random.word() }, + headers: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ) + ), + queries: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ) + ), + }, + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + replace: { + body: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + code: faker.datatype.number({ min: undefined, max: undefined }), + headers: { + clfp8d9jt006hv5dib5yi3b4v: faker.random.word(), + }, + method: faker.random.word(), + path: faker.random.word(), + queries: { + clfp8d9jt006iv5di6oemdvkv: faker.random.word(), + }, + }, + request_headers: { + clfp8d9jt006jv5diegy7coad: faker.random.word(), + }, + response_headers: { + clfp8d9jt006kv5dib4lz95wy: faker.random.word(), + }, + selector: { + annotationSelectors: { + clfp8d9jt006lv5di5w838ued: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jt006mv5dibd5yf6nn: faker.random.word(), + }, + labelSelectors: { + clfp8d9jt006nv5dihhca1tc3: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jt006ov5dibdwm5e22: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jt006pv5di49mueih7: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + target: faker.random.word(), + tls: { + caName: faker.random.word(), + certName: faker.random.word(), + keyName: faker.random.word(), + secretName: faker.random.word(), + secretNamespace: faker.random.word(), + }, + value: faker.random.word(), + }, + ioChaos: { + action: faker.random.word(), + attr: { + atime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + blocks: faker.datatype.number({ min: undefined, max: undefined }), + ctime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + gid: faker.datatype.number({ min: undefined, max: undefined }), + ino: faker.datatype.number({ min: undefined, max: undefined }), + kind: faker.random.word(), + mtime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + nlink: faker.datatype.number({ min: undefined, max: undefined }), + perm: faker.datatype.number({ min: undefined, max: undefined }), + rdev: faker.datatype.number({ min: undefined, max: undefined }), + size: faker.datatype.number({ min: undefined, max: undefined }), + uid: faker.datatype.number({ min: undefined, max: undefined }), + }, + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + delay: faker.random.word(), + duration: faker.random.word(), + errno: faker.datatype.number({ min: undefined, max: undefined }), + methods: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + mistake: { + filling: faker.random.word(), + maxLength: faker.datatype.number({ min: undefined, max: undefined }), + maxOccurrences: faker.datatype.number({ min: undefined, max: undefined }), + }, + mode: faker.random.word(), + path: faker.random.word(), + percent: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jt006qv5digzhs9q1t: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jt006rv5dic8j6cl2i: faker.random.word(), + }, + labelSelectors: { + clfp8d9jt006sv5di5nenf61t: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jt006tv5di3q3v9tii: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jt006uv5di3wqm2p81: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + volumePath: faker.random.word(), + }, + jvmChaos: { + action: faker.random.word(), + class: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + cpuCount: faker.datatype.number({ min: undefined, max: undefined }), + database: faker.random.word(), + duration: faker.random.word(), + exception: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + memType: faker.random.word(), + method: faker.random.word(), + mode: faker.random.word(), + mysqlConnectorVersion: faker.random.word(), + name: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + ruleData: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jt006vv5didfo69ek4: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jt006wv5di1xvgba44: faker.random.word(), + }, + labelSelectors: { + clfp8d9jt006xv5dia8ey4yks: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jt006yv5di41lw5dzr: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jt006zv5di8ujbczds: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + sqlType: faker.random.word(), + table: faker.random.word(), + value: faker.random.word(), + }, + kernelChaos: { + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + failKernRequest: { + callchain: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + funcname: faker.random.word(), + parameters: faker.random.word(), + predicate: faker.random.word(), + })), + failtype: faker.datatype.number({ min: undefined, max: undefined }), + headers: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + probability: faker.datatype.number({ min: undefined, max: undefined }), + times: faker.datatype.number({ min: undefined, max: undefined }), + }, + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jt0070v5di1gk775w9: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jt0071v5di45ke1vvg: faker.random.word(), + }, + labelSelectors: { + clfp8d9jt0072v5didtzkfg21: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jt0073v5di6pkd08p8: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jt0074v5di3krabmgh: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + name: faker.random.word(), + networkChaos: { + action: faker.random.word(), + bandwidth: { + buffer: faker.datatype.number({ min: undefined, max: undefined }), + limit: faker.datatype.number({ min: undefined, max: undefined }), + minburst: faker.datatype.number({ min: undefined, max: undefined }), + peakrate: faker.datatype.number({ min: undefined, max: undefined }), + rate: faker.random.word(), + }, + corrupt: { correlation: faker.random.word(), corrupt: faker.random.word() }, + delay: { + correlation: faker.random.word(), + jitter: faker.random.word(), + latency: faker.random.word(), + reorder: { + correlation: faker.random.word(), + gap: faker.datatype.number({ min: undefined, max: undefined }), + reorder: faker.random.word(), + }, + }, + device: faker.random.word(), + direction: faker.random.word(), + duplicate: { correlation: faker.random.word(), duplicate: faker.random.word() }, + duration: faker.random.word(), + externalTargets: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + loss: { correlation: faker.random.word(), loss: faker.random.word() }, + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jt0075v5didcfa6lqv: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jt0076v5dihs8k84j0: faker.random.word(), + }, + labelSelectors: { + clfp8d9jt0077v5di5f9edh79: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jt0078v5difzco7dnw: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jt0079v5dig73g9c55: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + target: { + mode: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jt007av5didddj3u73: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jt007bv5di7ydq28zk: faker.random.word(), + }, + labelSelectors: { + clfp8d9jt007cv5di4aqt0t32: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jt007dv5di3gpo5hqk: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jt007ev5di4cngcsq8: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + targetDevice: faker.random.word(), + value: faker.random.word(), + }, + physicalmachineChaos: { + action: faker.random.word(), + address: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + clock: { + 'clock-ids-slice': faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + 'time-offset': faker.random.word(), + }, + 'disk-fill': { + 'fill-by-fallocate': faker.datatype.boolean(), + path: faker.random.word(), + size: faker.random.word(), + }, + 'disk-read-payload': { + path: faker.random.word(), + 'payload-process-num': faker.datatype.number({ min: undefined, max: undefined }), + size: faker.random.word(), + }, + 'disk-write-payload': { + path: faker.random.word(), + 'payload-process-num': faker.datatype.number({ min: undefined, max: undefined }), + size: faker.random.word(), + }, + duration: faker.random.word(), + 'file-append': { + count: faker.datatype.number({ min: undefined, max: undefined }), + data: faker.random.word(), + 'file-name': faker.random.word(), + }, + 'file-create': { 'dir-name': faker.random.word(), 'file-name': faker.random.word() }, + 'file-delete': { 'dir-name': faker.random.word(), 'file-name': faker.random.word() }, + 'file-modify': { + 'file-name': faker.random.word(), + privilege: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'file-rename': { 'dest-file': faker.random.word(), 'source-file': faker.random.word() }, + 'file-replace': { + 'dest-string': faker.random.word(), + 'file-name': faker.random.word(), + line: faker.datatype.number({ min: undefined, max: undefined }), + 'origin-string': faker.random.word(), + }, + 'http-abort': { + code: faker.random.word(), + method: faker.random.word(), + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + proxy_ports: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + target: faker.random.word(), + }, + 'http-config': { file_path: faker.random.word() }, + 'http-delay': { + code: faker.random.word(), + delay: faker.random.word(), + method: faker.random.word(), + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + proxy_ports: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + target: faker.random.word(), + }, + 'http-request': { + count: faker.datatype.number({ min: undefined, max: undefined }), + 'enable-conn-pool': faker.datatype.boolean(), + url: faker.random.word(), + }, + 'jvm-exception': { + class: faker.random.word(), + exception: faker.random.word(), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-gc': { + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-latency': { + class: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-mysql': { + database: faker.random.word(), + exception: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + mysqlConnectorVersion: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + sqlType: faker.random.word(), + table: faker.random.word(), + }, + 'jvm-return': { + class: faker.random.word(), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + value: faker.random.word(), + }, + 'jvm-rule-data': { + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + 'rule-data': faker.random.word(), + }, + 'jvm-stress': { + 'cpu-count': faker.datatype.number({ min: undefined, max: undefined }), + 'mem-type': faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'kafka-fill': { + host: faker.random.word(), + maxBytes: faker.datatype.number({ min: undefined, max: undefined }), + messageSize: faker.datatype.number({ min: undefined, max: undefined }), + password: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + reloadCommand: faker.random.word(), + topic: faker.random.word(), + username: faker.random.word(), + }, + 'kafka-flood': { + host: faker.random.word(), + messageSize: faker.datatype.number({ min: undefined, max: undefined }), + password: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + threads: faker.datatype.number({ min: undefined, max: undefined }), + topic: faker.random.word(), + username: faker.random.word(), + }, + 'kafka-io': { + configFile: faker.random.word(), + nonReadable: faker.datatype.boolean(), + nonWritable: faker.datatype.boolean(), + topic: faker.random.word(), + }, + mode: faker.random.word(), + 'network-bandwidth': { + buffer: faker.datatype.number({ min: undefined, max: undefined }), + device: faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + limit: faker.datatype.number({ min: undefined, max: undefined }), + minburst: faker.datatype.number({ min: undefined, max: undefined }), + peakrate: faker.datatype.number({ min: undefined, max: undefined }), + rate: faker.random.word(), + }, + 'network-corrupt': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-delay': { + 'accept-tcp-flags': faker.random.word(), + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + jitter: faker.random.word(), + latency: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-dns': { + 'dns-domain-name': faker.random.word(), + 'dns-ip': faker.random.word(), + 'dns-server': faker.random.word(), + }, + 'network-down': { device: faker.random.word(), duration: faker.random.word() }, + 'network-duplicate': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-flood': { + duration: faker.random.word(), + 'ip-address': faker.random.word(), + parallel: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.random.word(), + rate: faker.random.word(), + }, + 'network-loss': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-partition': { + 'accept-tcp-flags': faker.random.word(), + device: faker.random.word(), + direction: faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + }, + process: { + process: faker.random.word(), + recoverCmd: faker.random.word(), + signal: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'redis-cacheLimit': { + addr: faker.random.word(), + cacheSize: faker.random.word(), + password: faker.random.word(), + percent: faker.random.word(), + }, + 'redis-expiration': { + addr: faker.random.word(), + expiration: faker.random.word(), + key: faker.random.word(), + option: faker.random.word(), + password: faker.random.word(), + }, + 'redis-penetration': { + addr: faker.random.word(), + password: faker.random.word(), + requestNum: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'redis-restart': { + addr: faker.random.word(), + conf: faker.random.word(), + flushConfig: faker.datatype.boolean(), + password: faker.random.word(), + redisPath: faker.datatype.boolean(), + }, + 'redis-stop': { + addr: faker.random.word(), + conf: faker.random.word(), + flushConfig: faker.datatype.boolean(), + password: faker.random.word(), + redisPath: faker.datatype.boolean(), + }, + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9ju007fv5di0vq7en0o: faker.random.word(), + }, + fieldSelectors: { + clfp8d9ju007gv5dihc2397n5: faker.random.word(), + }, + labelSelectors: { + clfp8d9ju007hv5di5xby2ydn: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + physicalMachines: { + clfp8d9ju007iv5diey44gtxi: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + 'stress-cpu': { + load: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'stress-mem': { + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + size: faker.random.word(), + }, + user_defined: { attackCmd: faker.random.word(), recoverCmd: faker.random.word() }, + value: faker.random.word(), + vm: { 'vm-name': faker.random.word() }, + }, + podChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + gracePeriod: faker.datatype.number({ min: undefined, max: undefined }), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9ju007jv5di3bbn8siu: faker.random.word(), + }, + fieldSelectors: { + clfp8d9ju007kv5di7bpbcmsf: faker.random.word(), + }, + labelSelectors: { + clfp8d9ju007lv5dibeoldi35: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9ju007mv5di72bk4euy: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9ju007nv5di7bbv1is0: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + schedule: { + awsChaos: { + action: faker.random.word(), + awsRegion: faker.random.word(), + deviceName: faker.random.word(), + duration: faker.random.word(), + ec2Instance: faker.random.word(), + endpoint: faker.random.word(), + remoteCluster: faker.random.word(), + secretName: faker.random.word(), + volumeID: faker.random.word(), + }, + azureChaos: { + action: faker.random.word(), + diskName: faker.random.word(), + duration: faker.random.word(), + lun: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + resourceGroupName: faker.random.word(), + secretName: faker.random.word(), + subscriptionID: faker.random.word(), + vmName: faker.random.word(), + }, + blockChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + delay: { correlation: faker.random.word(), jitter: faker.random.word(), latency: faker.random.word() }, + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9ju007ov5di2o3y1hjh: faker.random.word(), + }, + fieldSelectors: { + clfp8d9ju007pv5didh0mhe65: faker.random.word(), + }, + labelSelectors: { + clfp8d9ju007qv5dih159a1nb: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9ju007rv5diahmt5n4y: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9ju007sv5di02xrcmpw: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + volumeName: faker.random.word(), + }, + concurrencyPolicy: faker.random.word(), + dnsChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + patterns: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9ju007tv5di1tc43wdk: faker.random.word(), + }, + fieldSelectors: { + clfp8d9ju007uv5dihnwmey5o: faker.random.word(), + }, + labelSelectors: { + clfp8d9ju007vv5dibi2i16l0: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9ju007wv5didoup5nur: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jv007xv5diepp61zq7: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + gcpChaos: { + action: faker.random.word(), + deviceNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + instance: faker.random.word(), + project: faker.random.word(), + remoteCluster: faker.random.word(), + secretName: faker.random.word(), + zone: faker.random.word(), + }, + historyLimit: faker.datatype.number({ min: undefined, max: undefined }), + httpChaos: { + abort: faker.datatype.boolean(), + code: faker.datatype.number({ min: undefined, max: undefined }), + delay: faker.random.word(), + duration: faker.random.word(), + method: faker.random.word(), + mode: faker.random.word(), + patch: { + body: { type: faker.random.word(), value: faker.random.word() }, + headers: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ) + ), + queries: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ) + ), + }, + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + replace: { + body: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + code: faker.datatype.number({ min: undefined, max: undefined }), + headers: { + clfp8d9jv007yv5die5hz6yr4: faker.random.word(), + }, + method: faker.random.word(), + path: faker.random.word(), + queries: { + clfp8d9jv007zv5di0l9hhiht: faker.random.word(), + }, + }, + request_headers: { + clfp8d9jv0080v5diaqggbuhq: faker.random.word(), + }, + response_headers: { + clfp8d9jv0081v5dibmkf6awu: faker.random.word(), + }, + selector: { + annotationSelectors: { + clfp8d9jv0082v5die8ns65vj: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jv0083v5didr5bedfr: faker.random.word(), + }, + labelSelectors: { + clfp8d9jv0084v5diaw3d3bax: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jv0085v5did8nedjlz: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jv0086v5di9v8d0f05: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + target: faker.random.word(), + tls: { + caName: faker.random.word(), + certName: faker.random.word(), + keyName: faker.random.word(), + secretName: faker.random.word(), + secretNamespace: faker.random.word(), + }, + value: faker.random.word(), + }, + ioChaos: { + action: faker.random.word(), + attr: { + atime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + blocks: faker.datatype.number({ min: undefined, max: undefined }), + ctime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + gid: faker.datatype.number({ min: undefined, max: undefined }), + ino: faker.datatype.number({ min: undefined, max: undefined }), + kind: faker.random.word(), + mtime: { + nsec: faker.datatype.number({ min: undefined, max: undefined }), + sec: faker.datatype.number({ min: undefined, max: undefined }), + }, + nlink: faker.datatype.number({ min: undefined, max: undefined }), + perm: faker.datatype.number({ min: undefined, max: undefined }), + rdev: faker.datatype.number({ min: undefined, max: undefined }), + size: faker.datatype.number({ min: undefined, max: undefined }), + uid: faker.datatype.number({ min: undefined, max: undefined }), + }, + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + delay: faker.random.word(), + duration: faker.random.word(), + errno: faker.datatype.number({ min: undefined, max: undefined }), + methods: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + mistake: { + filling: faker.random.word(), + maxLength: faker.datatype.number({ min: undefined, max: undefined }), + maxOccurrences: faker.datatype.number({ min: undefined, max: undefined }), + }, + mode: faker.random.word(), + path: faker.random.word(), + percent: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jv0087v5di5cns9jfp: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jv0088v5digpwnftaw: faker.random.word(), + }, + labelSelectors: { + clfp8d9jv0089v5di38lec6wo: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jv008av5di93g3aakj: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jv008bv5di7f3bgc2p: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + volumePath: faker.random.word(), + }, + jvmChaos: { + action: faker.random.word(), + class: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + cpuCount: faker.datatype.number({ min: undefined, max: undefined }), + database: faker.random.word(), + duration: faker.random.word(), + exception: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + memType: faker.random.word(), + method: faker.random.word(), + mode: faker.random.word(), + mysqlConnectorVersion: faker.random.word(), + name: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + remoteCluster: faker.random.word(), + ruleData: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jv008cv5di342cht6o: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jv008dv5didppwfi3b: faker.random.word(), + }, + labelSelectors: { + clfp8d9jv008ev5dicw5penij: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jv008fv5digdgl4ayn: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jv008gv5dierydgi7m: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + sqlType: faker.random.word(), + table: faker.random.word(), + value: faker.random.word(), + }, + kernelChaos: { + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + failKernRequest: { + callchain: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + funcname: faker.random.word(), + parameters: faker.random.word(), + predicate: faker.random.word(), + })), + failtype: faker.datatype.number({ min: undefined, max: undefined }), + headers: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + probability: faker.datatype.number({ min: undefined, max: undefined }), + times: faker.datatype.number({ min: undefined, max: undefined }), + }, + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jv008hv5di09k95572: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jv008iv5difmbfhymy: faker.random.word(), + }, + labelSelectors: { + clfp8d9jv008jv5dictjq0ffy: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jv008kv5difw6n8e5e: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jv008lv5difwa20zzn: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + networkChaos: { + action: faker.random.word(), + bandwidth: { + buffer: faker.datatype.number({ min: undefined, max: undefined }), + limit: faker.datatype.number({ min: undefined, max: undefined }), + minburst: faker.datatype.number({ min: undefined, max: undefined }), + peakrate: faker.datatype.number({ min: undefined, max: undefined }), + rate: faker.random.word(), + }, + corrupt: { correlation: faker.random.word(), corrupt: faker.random.word() }, + delay: { + correlation: faker.random.word(), + jitter: faker.random.word(), + latency: faker.random.word(), + reorder: { + correlation: faker.random.word(), + gap: faker.datatype.number({ min: undefined, max: undefined }), + reorder: faker.random.word(), + }, + }, + device: faker.random.word(), + direction: faker.random.word(), + duplicate: { correlation: faker.random.word(), duplicate: faker.random.word() }, + duration: faker.random.word(), + externalTargets: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + loss: { correlation: faker.random.word(), loss: faker.random.word() }, + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jv008mv5di1kqa7sb6: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jv008nv5di91bg2xtr: faker.random.word(), + }, + labelSelectors: { + clfp8d9jv008ov5di9dq9ek3i: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jv008pv5di6t3n1zid: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jv008qv5di7ioy0udy: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + target: { + mode: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jv008rv5didbs12dke: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jv008sv5di53zc8lt6: faker.random.word(), + }, + labelSelectors: { + clfp8d9jv008tv5di4bwra2uo: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jv008uv5di04or9lct: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => faker.random.word() + ), + pods: { + clfp8d9jv008vv5di8kn185wg: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + targetDevice: faker.random.word(), + value: faker.random.word(), + }, + physicalmachineChaos: { + action: faker.random.word(), + address: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + clock: { + 'clock-ids-slice': faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + 'time-offset': faker.random.word(), + }, + 'disk-fill': { + 'fill-by-fallocate': faker.datatype.boolean(), + path: faker.random.word(), + size: faker.random.word(), + }, + 'disk-read-payload': { + path: faker.random.word(), + 'payload-process-num': faker.datatype.number({ min: undefined, max: undefined }), + size: faker.random.word(), + }, + 'disk-write-payload': { + path: faker.random.word(), + 'payload-process-num': faker.datatype.number({ min: undefined, max: undefined }), + size: faker.random.word(), + }, + duration: faker.random.word(), + 'file-append': { + count: faker.datatype.number({ min: undefined, max: undefined }), + data: faker.random.word(), + 'file-name': faker.random.word(), + }, + 'file-create': { 'dir-name': faker.random.word(), 'file-name': faker.random.word() }, + 'file-delete': { 'dir-name': faker.random.word(), 'file-name': faker.random.word() }, + 'file-modify': { + 'file-name': faker.random.word(), + privilege: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'file-rename': { 'dest-file': faker.random.word(), 'source-file': faker.random.word() }, + 'file-replace': { + 'dest-string': faker.random.word(), + 'file-name': faker.random.word(), + line: faker.datatype.number({ min: undefined, max: undefined }), + 'origin-string': faker.random.word(), + }, + 'http-abort': { + code: faker.random.word(), + method: faker.random.word(), + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + proxy_ports: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + target: faker.random.word(), + }, + 'http-config': { file_path: faker.random.word() }, + 'http-delay': { + code: faker.random.word(), + delay: faker.random.word(), + method: faker.random.word(), + path: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + proxy_ports: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.datatype.number({ min: undefined, max: undefined }) + ), + target: faker.random.word(), + }, + 'http-request': { + count: faker.datatype.number({ min: undefined, max: undefined }), + 'enable-conn-pool': faker.datatype.boolean(), + url: faker.random.word(), + }, + 'jvm-exception': { + class: faker.random.word(), + exception: faker.random.word(), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-gc': { + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-latency': { + class: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'jvm-mysql': { + database: faker.random.word(), + exception: faker.random.word(), + latency: faker.datatype.number({ min: undefined, max: undefined }), + mysqlConnectorVersion: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + sqlType: faker.random.word(), + table: faker.random.word(), + }, + 'jvm-return': { + class: faker.random.word(), + method: faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + value: faker.random.word(), + }, + 'jvm-rule-data': { + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + 'rule-data': faker.random.word(), + }, + 'jvm-stress': { + 'cpu-count': faker.datatype.number({ min: undefined, max: undefined }), + 'mem-type': faker.random.word(), + pid: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'kafka-fill': { + host: faker.random.word(), + maxBytes: faker.datatype.number({ min: undefined, max: undefined }), + messageSize: faker.datatype.number({ min: undefined, max: undefined }), + password: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + reloadCommand: faker.random.word(), + topic: faker.random.word(), + username: faker.random.word(), + }, + 'kafka-flood': { + host: faker.random.word(), + messageSize: faker.datatype.number({ min: undefined, max: undefined }), + password: faker.random.word(), + port: faker.datatype.number({ min: undefined, max: undefined }), + threads: faker.datatype.number({ min: undefined, max: undefined }), + topic: faker.random.word(), + username: faker.random.word(), + }, + 'kafka-io': { + configFile: faker.random.word(), + nonReadable: faker.datatype.boolean(), + nonWritable: faker.datatype.boolean(), + topic: faker.random.word(), + }, + mode: faker.random.word(), + 'network-bandwidth': { + buffer: faker.datatype.number({ min: undefined, max: undefined }), + device: faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + limit: faker.datatype.number({ min: undefined, max: undefined }), + minburst: faker.datatype.number({ min: undefined, max: undefined }), + peakrate: faker.datatype.number({ min: undefined, max: undefined }), + rate: faker.random.word(), + }, + 'network-corrupt': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-delay': { + 'accept-tcp-flags': faker.random.word(), + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + jitter: faker.random.word(), + latency: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-dns': { + 'dns-domain-name': faker.random.word(), + 'dns-ip': faker.random.word(), + 'dns-server': faker.random.word(), + }, + 'network-down': { device: faker.random.word(), duration: faker.random.word() }, + 'network-duplicate': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-flood': { + duration: faker.random.word(), + 'ip-address': faker.random.word(), + parallel: faker.datatype.number({ min: undefined, max: undefined }), + port: faker.random.word(), + rate: faker.random.word(), + }, + 'network-loss': { + correlation: faker.random.word(), + device: faker.random.word(), + 'egress-port': faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + percent: faker.random.word(), + 'source-port': faker.random.word(), + }, + 'network-partition': { + 'accept-tcp-flags': faker.random.word(), + device: faker.random.word(), + direction: faker.random.word(), + hostname: faker.random.word(), + 'ip-address': faker.random.word(), + 'ip-protocol': faker.random.word(), + }, + process: { + process: faker.random.word(), + recoverCmd: faker.random.word(), + signal: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'redis-cacheLimit': { + addr: faker.random.word(), + cacheSize: faker.random.word(), + password: faker.random.word(), + percent: faker.random.word(), + }, + 'redis-expiration': { + addr: faker.random.word(), + expiration: faker.random.word(), + key: faker.random.word(), + option: faker.random.word(), + password: faker.random.word(), + }, + 'redis-penetration': { + addr: faker.random.word(), + password: faker.random.word(), + requestNum: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'redis-restart': { + addr: faker.random.word(), + conf: faker.random.word(), + flushConfig: faker.datatype.boolean(), + password: faker.random.word(), + redisPath: faker.datatype.boolean(), + }, + 'redis-stop': { + addr: faker.random.word(), + conf: faker.random.word(), + flushConfig: faker.datatype.boolean(), + password: faker.random.word(), + redisPath: faker.datatype.boolean(), + }, + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jw008wv5di7nzof32m: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jw008xv5dih2g35h7o: faker.random.word(), + }, + labelSelectors: { + clfp8d9jw008yv5dihhowbyl8: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + physicalMachines: { + clfp8d9jw008zv5di3qd4g5jt: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + 'stress-cpu': { + load: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + 'stress-mem': { + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + size: faker.random.word(), + }, + user_defined: { attackCmd: faker.random.word(), recoverCmd: faker.random.word() }, + value: faker.random.word(), + vm: { 'vm-name': faker.random.word() }, + }, + podChaos: { + action: faker.random.word(), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + gracePeriod: faker.datatype.number({ min: undefined, max: undefined }), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jw0090v5di0clnfm4t: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jw0091v5di9ngr7801: faker.random.word(), + }, + labelSelectors: { + clfp8d9jw0092v5dicuqj7yi2: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jw0093v5dia7xf7lf8: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jw0094v5di3cttc4vh: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + value: faker.random.word(), + }, + schedule: faker.random.word(), + startingDeadlineSeconds: faker.datatype.number({ min: undefined, max: undefined }), + stressChaos: { + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jw0095v5dih3uc65e3: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jw0096v5diezml7z4p: faker.random.word(), + }, + labelSelectors: { + clfp8d9jw0097v5dibcgf3l4f: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jw0098v5di7dap51b2: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jw0099v5dicrui84bp: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + stressngStressors: faker.random.word(), + stressors: { + cpu: { + load: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + memory: { + oomScoreAdj: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + size: faker.random.word(), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + value: faker.random.word(), + }, + timeChaos: { + clockIds: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jw009av5dic642cd0f: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jw009bv5dihsggg5k9: faker.random.word(), + }, + labelSelectors: { + clfp8d9jw009cv5di0s5sgv7r: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jw009dv5diesja0pjt: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jw009ev5di0tfx2p26: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + timeOffset: faker.random.word(), + value: faker.random.word(), + }, + type: faker.random.word(), + }, + statusCheck: { + duration: faker.random.word(), + failureThreshold: faker.datatype.number({ min: undefined, max: undefined }), + http: { + body: faker.random.word(), + criteria: { statusCode: faker.random.word() }, + headers: { + clfp8d9jw009fv5di5xl0dc5x: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + method: faker.random.word(), + url: faker.random.word(), + }, + intervalSeconds: faker.datatype.number({ min: undefined, max: undefined }), + mode: faker.random.word(), + recordsHistoryLimit: faker.datatype.number({ min: undefined, max: undefined }), + successThreshold: faker.datatype.number({ min: undefined, max: undefined }), + timeoutSeconds: faker.datatype.number({ min: undefined, max: undefined }), + type: faker.random.word(), + }, + stressChaos: { + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jw009gv5dib7y39h69: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jw009hv5di1g9m3v36: faker.random.word(), + }, + labelSelectors: { + clfp8d9jw009iv5di9tis0myi: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jw009jv5di2163h5u2: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jx009kv5difj7a4vrq: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + stressngStressors: faker.random.word(), + stressors: { + cpu: { + load: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + memory: { + oomScoreAdj: faker.datatype.number({ min: undefined, max: undefined }), + options: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + size: faker.random.word(), + workers: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + value: faker.random.word(), + }, + task: { + container: { + args: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + command: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + env: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + name: faker.random.word(), + value: faker.random.word(), + valueFrom: { + configMapKeyRef: { key: faker.random.word(), name: faker.random.word(), optional: faker.datatype.boolean() }, + fieldRef: { apiVersion: faker.random.word(), fieldPath: faker.random.word() }, + resourceFieldRef: { + containerName: faker.random.word(), + divisor: { Format: faker.random.word() }, + resource: faker.random.word(), + }, + secretKeyRef: { key: faker.random.word(), name: faker.random.word(), optional: faker.datatype.boolean() }, + }, + })), + envFrom: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + configMapRef: { name: faker.random.word(), optional: faker.datatype.boolean() }, + prefix: faker.random.word(), + secretRef: { name: faker.random.word(), optional: faker.datatype.boolean() }, + })), + image: faker.random.word(), + imagePullPolicy: faker.random.word(), + lifecycle: { + postStart: { + exec: { + command: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }, + httpGet: { + host: faker.random.word(), + httpHeaders: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ name: faker.random.word(), value: faker.random.word() }) + ), + path: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + scheme: faker.random.word(), + }, + tcpSocket: { + host: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + }, + preStop: { + exec: { + command: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }, + httpGet: { + host: faker.random.word(), + httpHeaders: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ name: faker.random.word(), value: faker.random.word() }) + ), + path: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + scheme: faker.random.word(), + }, + tcpSocket: { + host: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + }, + }, + livenessProbe: { + exec: { + command: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }, + failureThreshold: faker.datatype.number({ min: undefined, max: undefined }), + grpc: { port: faker.datatype.number({ min: undefined, max: undefined }), service: faker.random.word() }, + httpGet: { + host: faker.random.word(), + httpHeaders: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + name: faker.random.word(), + value: faker.random.word(), + })), + path: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + scheme: faker.random.word(), + }, + initialDelaySeconds: faker.datatype.number({ min: undefined, max: undefined }), + periodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + successThreshold: faker.datatype.number({ min: undefined, max: undefined }), + tcpSocket: { + host: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + terminationGracePeriodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + timeoutSeconds: faker.datatype.number({ min: undefined, max: undefined }), + }, + name: faker.random.word(), + ports: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + containerPort: faker.datatype.number({ min: undefined, max: undefined }), + hostIP: faker.random.word(), + hostPort: faker.datatype.number({ min: undefined, max: undefined }), + name: faker.random.word(), + protocol: faker.random.word(), + })), + readinessProbe: { + exec: { + command: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }, + failureThreshold: faker.datatype.number({ min: undefined, max: undefined }), + grpc: { port: faker.datatype.number({ min: undefined, max: undefined }), service: faker.random.word() }, + httpGet: { + host: faker.random.word(), + httpHeaders: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + name: faker.random.word(), + value: faker.random.word(), + })), + path: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + scheme: faker.random.word(), + }, + initialDelaySeconds: faker.datatype.number({ min: undefined, max: undefined }), + periodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + successThreshold: faker.datatype.number({ min: undefined, max: undefined }), + tcpSocket: { + host: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + terminationGracePeriodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + timeoutSeconds: faker.datatype.number({ min: undefined, max: undefined }), + }, + resources: { + claims: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + name: faker.random.word(), + })), + limits: { + clfp8d9jx009lv5difcwraz30: { Format: faker.random.word() }, + }, + requests: { + clfp8d9jx009mv5dibhtd2tla: { Format: faker.random.word() }, + }, + }, + securityContext: { + allowPrivilegeEscalation: faker.datatype.boolean(), + capabilities: { + add: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + drop: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }, + privileged: faker.datatype.boolean(), + procMount: faker.random.word(), + readOnlyRootFilesystem: faker.datatype.boolean(), + runAsGroup: faker.datatype.number({ min: undefined, max: undefined }), + runAsNonRoot: faker.datatype.boolean(), + runAsUser: faker.datatype.number({ min: undefined, max: undefined }), + seLinuxOptions: { + level: faker.random.word(), + role: faker.random.word(), + type: faker.random.word(), + user: faker.random.word(), + }, + seccompProfile: { localhostProfile: faker.random.word(), type: faker.random.word() }, + windowsOptions: { + gmsaCredentialSpec: faker.random.word(), + gmsaCredentialSpecName: faker.random.word(), + hostProcess: faker.datatype.boolean(), + runAsUserName: faker.random.word(), + }, + }, + startupProbe: { + exec: { + command: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }, + failureThreshold: faker.datatype.number({ min: undefined, max: undefined }), + grpc: { port: faker.datatype.number({ min: undefined, max: undefined }), service: faker.random.word() }, + httpGet: { + host: faker.random.word(), + httpHeaders: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + name: faker.random.word(), + value: faker.random.word(), + })), + path: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + scheme: faker.random.word(), + }, + initialDelaySeconds: faker.datatype.number({ min: undefined, max: undefined }), + periodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + successThreshold: faker.datatype.number({ min: undefined, max: undefined }), + tcpSocket: { + host: faker.random.word(), + port: { + intVal: faker.datatype.number({ min: undefined, max: undefined }), + strVal: faker.random.word(), + type: faker.datatype.number({ min: undefined, max: undefined }), + }, + }, + terminationGracePeriodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + timeoutSeconds: faker.datatype.number({ min: undefined, max: undefined }), + }, + stdin: faker.datatype.boolean(), + stdinOnce: faker.datatype.boolean(), + terminationMessagePath: faker.random.word(), + terminationMessagePolicy: faker.random.word(), + tty: faker.datatype.boolean(), + volumeDevices: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + devicePath: faker.random.word(), + name: faker.random.word(), + })), + volumeMounts: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + mountPath: faker.random.word(), + mountPropagation: faker.random.word(), + name: faker.random.word(), + readOnly: faker.datatype.boolean(), + subPath: faker.random.word(), + subPathExpr: faker.random.word(), + })), + workingDir: faker.random.word(), + }, + volumes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + awsElasticBlockStore: { + fsType: faker.random.word(), + partition: faker.datatype.number({ min: undefined, max: undefined }), + readOnly: faker.datatype.boolean(), + volumeID: faker.random.word(), + }, + azureDisk: { + cachingMode: faker.random.word(), + diskName: faker.random.word(), + diskURI: faker.random.word(), + fsType: faker.random.word(), + kind: faker.random.word(), + readOnly: faker.datatype.boolean(), + }, + azureFile: { + readOnly: faker.datatype.boolean(), + secretName: faker.random.word(), + shareName: faker.random.word(), + }, + cephfs: { + monitors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + path: faker.random.word(), + readOnly: faker.datatype.boolean(), + secretFile: faker.random.word(), + secretRef: { name: faker.random.word() }, + user: faker.random.word(), + }, + cinder: { + fsType: faker.random.word(), + readOnly: faker.datatype.boolean(), + secretRef: { name: faker.random.word() }, + volumeID: faker.random.word(), + }, + configMap: { + defaultMode: faker.datatype.number({ min: undefined, max: undefined }), + items: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + key: faker.random.word(), + mode: faker.datatype.number({ min: undefined, max: undefined }), + path: faker.random.word(), + })), + name: faker.random.word(), + optional: faker.datatype.boolean(), + }, + csi: { + driver: faker.random.word(), + fsType: faker.random.word(), + nodePublishSecretRef: { name: faker.random.word() }, + readOnly: faker.datatype.boolean(), + volumeAttributes: { + clfp8d9jx009nv5di1xyl7zd5: faker.random.word(), + }, + }, + downwardAPI: { + defaultMode: faker.datatype.number({ min: undefined, max: undefined }), + items: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + fieldRef: { apiVersion: faker.random.word(), fieldPath: faker.random.word() }, + mode: faker.datatype.number({ min: undefined, max: undefined }), + path: faker.random.word(), + resourceFieldRef: { + containerName: faker.random.word(), + divisor: { Format: faker.random.word() }, + resource: faker.random.word(), + }, + })), + }, + emptyDir: { medium: faker.random.word(), sizeLimit: { Format: faker.random.word() } }, + ephemeral: { + volumeClaimTemplate: { + annotations: { + clfp8d9jy009ov5di4jntb0kk: faker.random.word(), + }, + creationTimestamp: faker.random.word(), + deletionGracePeriodSeconds: faker.datatype.number({ min: undefined, max: undefined }), + deletionTimestamp: faker.random.word(), + finalizers: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + generateName: faker.random.word(), + generation: faker.datatype.number({ min: undefined, max: undefined }), + labels: { + clfp8d9jy009pv5dihvhp46kf: faker.random.word(), + }, + managedFields: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ + apiVersion: faker.random.word(), + fieldsType: faker.random.word(), + fieldsV1: {}, + manager: faker.random.word(), + operation: faker.random.word(), + subresource: faker.random.word(), + time: faker.random.word(), + }) + ), + name: faker.random.word(), + namespace: faker.random.word(), + ownerReferences: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ + apiVersion: faker.random.word(), + blockOwnerDeletion: faker.datatype.boolean(), + controller: faker.datatype.boolean(), + kind: faker.random.word(), + name: faker.random.word(), + uid: faker.random.word(), + }) + ), + resourceVersion: faker.random.word(), + selfLink: faker.random.word(), + spec: { + accessModes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + dataSource: { apiGroup: faker.random.word(), kind: faker.random.word(), name: faker.random.word() }, + dataSourceRef: { + apiGroup: faker.random.word(), + kind: faker.random.word(), + name: faker.random.word(), + namespace: faker.random.word(), + }, + resources: { + claims: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + name: faker.random.word(), + })), + limits: { + clfp8d9jy009qv5di8l0r3jhd: { Format: faker.random.word() }, + }, + requests: { + clfp8d9jy009rv5di5nl6ewp4: { Format: faker.random.word() }, + }, + }, + selector: { + matchExpressions: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map( + () => ({ + key: faker.random.word(), + operator: faker.random.word(), + values: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }) + ), + matchLabels: { + clfp8d9jy009sv5difd3bg3pu: faker.random.word(), + }, + }, + storageClassName: faker.random.word(), + volumeMode: faker.random.word(), + volumeName: faker.random.word(), + }, + uid: faker.random.word(), + }, + }, + fc: { + fsType: faker.random.word(), + lun: faker.datatype.number({ min: undefined, max: undefined }), + readOnly: faker.datatype.boolean(), + targetWWNs: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + wwids: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + }, + flexVolume: { + driver: faker.random.word(), + fsType: faker.random.word(), + options: { + clfp8d9jy009tv5di5ur7c7kh: faker.random.word(), + }, + readOnly: faker.datatype.boolean(), + secretRef: { name: faker.random.word() }, + }, + flocker: { datasetName: faker.random.word(), datasetUUID: faker.random.word() }, + gcePersistentDisk: { + fsType: faker.random.word(), + partition: faker.datatype.number({ min: undefined, max: undefined }), + pdName: faker.random.word(), + readOnly: faker.datatype.boolean(), + }, + gitRepo: { directory: faker.random.word(), repository: faker.random.word(), revision: faker.random.word() }, + glusterfs: { endpoints: faker.random.word(), path: faker.random.word(), readOnly: faker.datatype.boolean() }, + hostPath: { path: faker.random.word(), type: faker.random.word() }, + iscsi: { + chapAuthDiscovery: faker.datatype.boolean(), + chapAuthSession: faker.datatype.boolean(), + fsType: faker.random.word(), + initiatorName: faker.random.word(), + iqn: faker.random.word(), + iscsiInterface: faker.random.word(), + lun: faker.datatype.number({ min: undefined, max: undefined }), + portals: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + readOnly: faker.datatype.boolean(), + secretRef: { name: faker.random.word() }, + targetPortal: faker.random.word(), + }, + name: faker.random.word(), + nfs: { path: faker.random.word(), readOnly: faker.datatype.boolean(), server: faker.random.word() }, + persistentVolumeClaim: { claimName: faker.random.word(), readOnly: faker.datatype.boolean() }, + photonPersistentDisk: { fsType: faker.random.word(), pdID: faker.random.word() }, + portworxVolume: { + fsType: faker.random.word(), + readOnly: faker.datatype.boolean(), + volumeID: faker.random.word(), + }, + projected: { + defaultMode: faker.datatype.number({ min: undefined, max: undefined }), + sources: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + configMap: { + items: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + key: faker.random.word(), + mode: faker.datatype.number({ min: undefined, max: undefined }), + path: faker.random.word(), + })), + name: faker.random.word(), + optional: faker.datatype.boolean(), + }, + downwardAPI: { + items: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + fieldRef: { apiVersion: faker.random.word(), fieldPath: faker.random.word() }, + mode: faker.datatype.number({ min: undefined, max: undefined }), + path: faker.random.word(), + resourceFieldRef: { + containerName: faker.random.word(), + divisor: { Format: faker.random.word() }, + resource: faker.random.word(), + }, + })), + }, + secret: { + items: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + key: faker.random.word(), + mode: faker.datatype.number({ min: undefined, max: undefined }), + path: faker.random.word(), + })), + name: faker.random.word(), + optional: faker.datatype.boolean(), + }, + serviceAccountToken: { + audience: faker.random.word(), + expirationSeconds: faker.datatype.number({ min: undefined, max: undefined }), + path: faker.random.word(), + }, + })), + }, + quobyte: { + group: faker.random.word(), + readOnly: faker.datatype.boolean(), + registry: faker.random.word(), + tenant: faker.random.word(), + user: faker.random.word(), + volume: faker.random.word(), + }, + rbd: { + fsType: faker.random.word(), + image: faker.random.word(), + keyring: faker.random.word(), + monitors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pool: faker.random.word(), + readOnly: faker.datatype.boolean(), + secretRef: { name: faker.random.word() }, + user: faker.random.word(), + }, + scaleIO: { + fsType: faker.random.word(), + gateway: faker.random.word(), + protectionDomain: faker.random.word(), + readOnly: faker.datatype.boolean(), + secretRef: { name: faker.random.word() }, + sslEnabled: faker.datatype.boolean(), + storageMode: faker.random.word(), + storagePool: faker.random.word(), + system: faker.random.word(), + volumeName: faker.random.word(), + }, + secret: { + defaultMode: faker.datatype.number({ min: undefined, max: undefined }), + items: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ + key: faker.random.word(), + mode: faker.datatype.number({ min: undefined, max: undefined }), + path: faker.random.word(), + })), + optional: faker.datatype.boolean(), + secretName: faker.random.word(), + }, + storageos: { + fsType: faker.random.word(), + readOnly: faker.datatype.boolean(), + secretRef: { name: faker.random.word() }, + volumeName: faker.random.word(), + volumeNamespace: faker.random.word(), + }, + vsphereVolume: { + fsType: faker.random.word(), + storagePolicyID: faker.random.word(), + storagePolicyName: faker.random.word(), + volumePath: faker.random.word(), + }, + })), + }, + templateType: faker.random.word(), + timeChaos: { + clockIds: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + containerNames: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + duration: faker.random.word(), + mode: faker.random.word(), + remoteCluster: faker.random.word(), + selector: { + annotationSelectors: { + clfp8d9jy009uv5dictndbnnh: faker.random.word(), + }, + fieldSelectors: { + clfp8d9jy009vv5di5wwwey4z: faker.random.word(), + }, + labelSelectors: { + clfp8d9jy009wv5dift8e7y2w: faker.random.word(), + }, + namespaces: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + nodeSelectors: { + clfp8d9jy009xv5diepnl9y1i: faker.random.word(), + }, + nodes: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + podPhaseSelectors: Array.from({ length: faker.datatype.number({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => + faker.random.word() + ), + pods: { + clfp8d9jy009yv5di9ebo6st3: Array.from( + { length: faker.datatype.number({ min: 1, max: 10 }) }, + (_, i) => i + 1 + ).map(() => faker.random.word()), + }, + }, + timeOffset: faker.random.word(), + value: faker.random.word(), + }, +}) + +export const getPostWorkflowsValidateTaskHttpMock = () => faker.datatype.boolean() + +export const getChaosMeshDashboardAPIMSW = () => [ + rest.delete('*/archives', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getDeleteArchivesMock())) + }), + rest.get('*/archives', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetArchivesMock())) + }), + rest.delete('*/archives/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getDeleteArchivesUidMock())) + }), + rest.get('*/archives/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetArchivesUidMock())) + }), + rest.delete('*/archives/schedules', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getDeleteArchivesSchedulesMock())) + }), + rest.get('*/archives/schedules', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetArchivesSchedulesMock())) + }), + rest.delete('*/archives/schedules/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getDeleteArchivesSchedulesUidMock())) + }), + rest.get('*/archives/schedules/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetArchivesSchedulesUidMock())) + }), + rest.delete('*/archives/workflows', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getDeleteArchivesWorkflowsMock())) + }), + rest.get('*/archives/workflows', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetArchivesWorkflowsMock())) + }), + rest.delete('*/archives/workflows/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getDeleteArchivesWorkflowsUidMock())) + }), + rest.get('*/archives/workflows/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetArchivesWorkflowsUidMock())) + }), + rest.get('*/common/annotations', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetCommonAnnotationsMock())) + }), + rest.get('*/common/chaos-available-namespaces', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetCommonChaosAvailableNamespacesMock())) + }), + rest.get('*/common/config', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetCommonConfigMock())) + }), + rest.get('*/common/kinds', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetCommonKindsMock())) + }), + rest.get('*/common/labels', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetCommonLabelsMock())) + }), + rest.get('*/common/namespaces', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetCommonNamespacesMock())) + }), + rest.get('*/common/physicalmachine-annotations', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetCommonPhysicalmachineAnnotationsMock())) + }), + rest.get('*/common/physicalmachine-labels', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetCommonPhysicalmachineLabelsMock())) + }), + rest.post('*/common/physicalmachines', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPostCommonPhysicalmachinesMock())) + }), + rest.post('*/common/pods', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPostCommonPodsMock())) + }), + rest.get('*/common/rbac-config', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetCommonRbacConfigMock())) + }), + rest.get('*/events', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetEventsMock())) + }), + rest.get('*/events/:id', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetEventsIdMock())) + }), + rest.get('*/events/workflow/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetEventsWorkflowUidMock())) + }), + rest.delete('*/experiments', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getDeleteExperimentsMock())) + }), + rest.get('*/experiments', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetExperimentsMock())) + }), + rest.post('*/experiments', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPostExperimentsMock())) + }), + rest.delete('*/experiments/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getDeleteExperimentsUidMock())) + }), + rest.get('*/experiments/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetExperimentsUidMock())) + }), + rest.put('*/experiments/pause/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPutExperimentsPauseUidMock())) + }), + rest.put('*/experiments/start/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPutExperimentsStartUidMock())) + }), + rest.get('*/experiments/state', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetExperimentsStateMock())) + }), + rest.delete('*/schedules', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getDeleteSchedulesMock())) + }), + rest.get('*/schedules', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetSchedulesMock())) + }), + rest.post('*/schedules', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPostSchedulesMock())) + }), + rest.delete('*/schedules/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getDeleteSchedulesUidMock())) + }), + rest.get('*/schedules/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetSchedulesUidMock())) + }), + rest.put('*/schedules/pause/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPutSchedulesPauseUidMock())) + }), + rest.put('*/schedules/start/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPutSchedulesStartUidMock())) + }), + rest.get('*/templates/statuschecks', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetTemplatesStatuschecksMock())) + }), + rest.post('*/templates/statuschecks', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPostTemplatesStatuschecksMock())) + }), + rest.delete('*/templates/statuschecks/statuscheck', (_req, res, ctx) => { + return res( + ctx.delay(0), + ctx.status(200, 'Mocked status'), + ctx.json(getDeleteTemplatesStatuschecksStatuscheckMock()) + ) + }), + rest.get('*/templates/statuschecks/statuscheck', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetTemplatesStatuschecksStatuscheckMock())) + }), + rest.put('*/templates/statuschecks/statuscheck', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPutTemplatesStatuschecksStatuscheckMock())) + }), + rest.get('*/workflows', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetWorkflowsMock())) + }), + rest.post('*/workflows', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPostWorkflowsMock())) + }), + rest.delete('*/workflows/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getDeleteWorkflowsUidMock())) + }), + rest.get('*/workflows/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getGetWorkflowsUidMock())) + }), + rest.put('*/workflows/:uid', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPutWorkflowsUidMock())) + }), + rest.post('*/workflows/parse-task/http', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPostWorkflowsParseTaskHttpMock())) + }), + rest.post('*/workflows/render-task/http', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPostWorkflowsRenderTaskHttpMock())) + }), + rest.post('*/workflows/validate-task/http', (_req, res, ctx) => { + return res(ctx.delay(0), ctx.status(200, 'Mocked status'), ctx.json(getPostWorkflowsValidateTaskHttpMock())) + }), +] diff --git a/ui/app/src/openapi/index.schemas.ts b/ui/app/src/openapi/index.schemas.ts new file mode 100644 index 0000000000..b01599c4a1 --- /dev/null +++ b/ui/app/src/openapi/index.schemas.ts @@ -0,0 +1,4507 @@ +/** + * Generated by orval v6.12.1 🍺 + * Do not edit manually. + * Chaos Mesh Dashboard API + * Swagger for Chaos Mesh Dashboard. If you encounter any problems with API, please click on the issues link below to report. + * OpenAPI spec version: 2.2 + */ +export type GetWorkflowsStatus = (typeof GetWorkflowsStatus)[keyof typeof GetWorkflowsStatus] + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const GetWorkflowsStatus = { + Initializing: 'Initializing', + Running: 'Running', + Errored: 'Errored', + Finished: 'Finished', +} as const + +export type GetWorkflowsParams = { + /** + * namespace, given empty string means list from all namespace + */ + namespace?: string + /** + * status + */ + status?: GetWorkflowsStatus +} + +export type GetTemplatesStatuschecksStatuscheckParams = { + /** + * the namespace of status check templates + */ + namespace: string + /** + * the name of status check templates + */ + name: string +} + +export type DeleteTemplatesStatuschecksStatuscheckParams = { + /** + * the namespace of status check templates + */ + namespace: string + /** + * the name of status check templates + */ + name: string +} + +export type GetTemplatesStatuschecksParams = { + /** + * filter status check templates by namespace + */ + namespace?: string + /** + * filter status check templates by name + */ + name?: string +} + +export type GetSchedulesParams = { + /** + * filter schedules by namespace + */ + namespace?: string + /** + * filter schedules by name + */ + name?: string +} + +export type DeleteSchedulesParams = { + /** + * the schedule uids, split with comma. Example: ?uids=uid1,uid2 + */ + uids: string +} + +export type GetExperimentsStateParams = { + /** + * namespace + */ + namespace?: string +} + +export type DeleteExperimentsUidForce = (typeof DeleteExperimentsUidForce)[keyof typeof DeleteExperimentsUidForce] + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const DeleteExperimentsUidForce = { + true: 'true', + false: 'false', +} as const + +export type DeleteExperimentsUidParams = { + /** + * force + */ + force?: DeleteExperimentsUidForce +} + +export type PostExperiments200 = { [key: string]: any } + +export type PostExperimentsBody = { [key: string]: any } + +export type GetExperimentsStatus = (typeof GetExperimentsStatus)[keyof typeof GetExperimentsStatus] + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const GetExperimentsStatus = { + Injecting: 'Injecting', + Running: 'Running', + Finished: 'Finished', + Paused: 'Paused', +} as const + +export type GetExperimentsKind = (typeof GetExperimentsKind)[keyof typeof GetExperimentsKind] + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const GetExperimentsKind = { + PodChaos: 'PodChaos', + NetworkChaos: 'NetworkChaos', + IOChaos: 'IOChaos', + StressChaos: 'StressChaos', + KernelChaos: 'KernelChaos', + TimeChaos: 'TimeChaos', + DNSChaos: 'DNSChaos', + AWSChaos: 'AWSChaos', + GCPChaos: 'GCPChaos', + JVMChaos: 'JVMChaos', + HTTPChaos: 'HTTPChaos', +} as const + +export type GetExperimentsParams = { + /** + * filter exps by namespace + */ + namespace?: string + /** + * filter exps by name + */ + name?: string + /** + * filter exps by kind + */ + kind?: GetExperimentsKind + /** + * filter exps by status + */ + status?: GetExperimentsStatus +} + +export type DeleteExperimentsForce = (typeof DeleteExperimentsForce)[keyof typeof DeleteExperimentsForce] + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const DeleteExperimentsForce = { + true: 'true', + false: 'false', +} as const + +export type DeleteExperimentsParams = { + /** + * the experiment uids, split with comma. Example: ?uids=uid1,uid2 + */ + uids: string + /** + * force + */ + force?: DeleteExperimentsForce +} + +export type GetEventsWorkflowUidParams = { + /** + * The namespace of the object + */ + namespace?: string + /** + * The max length of events list + */ + limit?: number +} + +export type GetEventsKind = (typeof GetEventsKind)[keyof typeof GetEventsKind] + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const GetEventsKind = { + PodChaos: 'PodChaos', + IOChaos: 'IOChaos', + NetworkChaos: 'NetworkChaos', + TimeChaos: 'TimeChaos', + KernelChaos: 'KernelChaos', + StressChaos: 'StressChaos', + AWSChaos: 'AWSChaos', + GCPChaos: 'GCPChaos', + DNSChaos: 'DNSChaos', + Schedule: 'Schedule', +} as const + +export type GetEventsParams = { + /** + * The create time of events + */ + created_at?: string + /** + * The name of the object + */ + name?: string + /** + * The namespace of the object + */ + namespace?: string + /** + * The UID of the object + */ + object_id?: string + /** + * kind + */ + kind?: GetEventsKind + /** + * The max length of events list + */ + limit?: number +} + +export type GetCommonRbacConfig200 = { [key: string]: string } + +export type GetCommonRbacConfigParams = { + /** + * The namespace of RBAC + */ + namespace?: string + /** + * The role of RBAC + */ + role?: string +} + +export type GetCommonPhysicalmachineLabelsParams = { + /** + * The physicalMachine's namespace list, split by , + */ + physicalMachineNamespaceList: string +} + +export type GetCommonPhysicalmachineAnnotationsParams = { + /** + * The physicalMachine's namespace list, split by , + */ + physicalMachineNamespaceList: string +} + +export type GetCommonLabelsParams = { + /** + * The pod's namespace list, split by , + */ + podNamespaceList: string +} + +export type GetCommonAnnotationsParams = { + /** + * The pod's namespace list, split by , + */ + podNamespaceList: string +} + +export type GetArchivesWorkflowsParams = { + /** + * namespace + */ + namespace?: string + /** + * name + */ + name?: string +} + +export type DeleteArchivesWorkflowsParams = { + /** + * uids + */ + uids: string +} + +export type GetArchivesSchedulesParams = { + /** + * namespace + */ + namespace?: string + /** + * name + */ + name?: string +} + +export type DeleteArchivesSchedulesParams = { + /** + * uids + */ + uids: string +} + +export type GetArchivesKind = (typeof GetArchivesKind)[keyof typeof GetArchivesKind] + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const GetArchivesKind = { + PodChaos: 'PodChaos', + IOChaos: 'IOChaos', + NetworkChaos: 'NetworkChaos', + TimeChaos: 'TimeChaos', + KernelChaos: 'KernelChaos', + StressChaos: 'StressChaos', +} as const + +export type GetArchivesParams = { + /** + * namespace + */ + namespace?: string + /** + * name + */ + name?: string + /** + * kind + */ + kind?: GetArchivesKind +} + +export type DeleteArchivesParams = { + /** + * uids + */ + uids: string +} + +/** + * Rendered Task + */ +export type V1alpha1TemplateBody = V1alpha1Template + +/** + * Request body + */ +export type V1alpha1WorkflowBody = V1alpha1Workflow + +export interface V1alpha1WorkflowSpec { + entry?: string + templates?: V1alpha1Template[] +} + +export interface V1alpha1WorkflowCondition { + reason?: string + startTime?: string + status?: string + type?: string +} + +export interface V1alpha1WorkflowStatus { + /** Represents the latest available observations of a workflow's current state. ++optional ++patchMergeKey=type ++patchStrategy=merge */ + conditions?: V1alpha1WorkflowCondition[] + /** +optional */ + endTime?: string + /** +optional */ + entryNode?: string + /** +optional */ + startTime?: string +} + +/** + * Map of string keys and values that can be used to organize and categorize +(scope and select) objects. May match selectors of replication controllers +and services. +More info: http://kubernetes.io/docs/user-guide/labels ++optional + */ +export type V1alpha1WorkflowLabels = { [key: string]: string } + +/** + * Annotations is an unstructured key value map stored with a resource that may be +set by external tools to store and retrieve arbitrary metadata. They are not +queryable and should be preserved when modifying objects. +More info: http://kubernetes.io/docs/user-guide/annotations ++optional + */ +export type V1alpha1WorkflowAnnotations = { [key: string]: string } + +export interface V1alpha1Workflow { + /** Annotations is an unstructured key value map stored with a resource that may be +set by external tools to store and retrieve arbitrary metadata. They are not +queryable and should be preserved when modifying objects. +More info: http://kubernetes.io/docs/user-guide/annotations ++optional */ + annotations?: V1alpha1WorkflowAnnotations + /** APIVersion defines the versioned schema of this representation of an object. +Servers should convert recognized schemas to the latest internal value, and +may reject unrecognized values. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources ++optional */ + apiVersion?: string + /** CreationTimestamp is a timestamp representing the server time when this object was +created. It is not guaranteed to be set in happens-before order across separate operations. +Clients may not set this value. It is represented in RFC3339 form and is in UTC. + +Populated by the system. +Read-only. +Null for lists. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata ++optional */ + creationTimestamp?: string + /** Number of seconds allowed for this object to gracefully terminate before +it will be removed from the system. Only set when deletionTimestamp is also set. +May only be shortened. +Read-only. ++optional */ + deletionGracePeriodSeconds?: number + /** DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This +field is set by the server when a graceful deletion is requested by the user, and is not +directly settable by a client. The resource is expected to be deleted (no longer visible +from resource lists, and not reachable by name) after the time in this field, once the +finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. +Once the deletionTimestamp is set, this value may not be unset or be set further into the +future, although it may be shortened or the resource may be deleted prior to this time. +For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react +by sending a graceful termination signal to the containers in the pod. After that 30 seconds, +the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, +remove the pod from the API. In the presence of network partitions, this object may still +exist after this timestamp, until an administrator or automated process can determine the +resource is fully terminated. +If not set, graceful deletion of the object has not been requested. + +Populated by the system when a graceful deletion is requested. +Read-only. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata ++optional */ + deletionTimestamp?: string + /** Must be empty before the object is deleted from the registry. Each entry +is an identifier for the responsible component that will remove the entry +from the list. If the deletionTimestamp of the object is non-nil, entries +in this list can only be removed. +Finalizers may be processed and removed in any order. Order is NOT enforced +because it introduces significant risk of stuck finalizers. +finalizers is a shared field, any actor with permission can reorder it. +If the finalizer list is processed in order, then this can lead to a situation +in which the component responsible for the first finalizer in the list is +waiting for a signal (field value, external system, or other) produced by a +component responsible for a finalizer later in the list, resulting in a deadlock. +Without enforced ordering finalizers are free to order amongst themselves and +are not vulnerable to ordering changes in the list. ++optional ++patchStrategy=merge */ + finalizers?: string[] + /** GenerateName is an optional prefix, used by the server, to generate a unique +name ONLY IF the Name field has not been provided. +If this field is used, the name returned to the client will be different +than the name passed. This value will also be combined with a unique suffix. +The provided value has the same validation rules as the Name field, +and may be truncated by the length of the suffix required to make the value +unique on the server. + +If this field is specified and the generated name exists, the server will return a 409. + +Applied only if Name is not specified. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency ++optional */ + generateName?: string + /** A sequence number representing a specific generation of the desired state. +Populated by the system. Read-only. ++optional */ + generation?: number + /** Kind is a string value representing the REST resource this object represents. +Servers may infer this from the endpoint the client submits requests to. +Cannot be updated. +In CamelCase. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds ++optional */ + kind?: string + /** Map of string keys and values that can be used to organize and categorize +(scope and select) objects. May match selectors of replication controllers +and services. +More info: http://kubernetes.io/docs/user-guide/labels ++optional */ + labels?: V1alpha1WorkflowLabels + /** ManagedFields maps workflow-id and version to the set of fields +that are managed by that workflow. This is mostly for internal +housekeeping, and users typically shouldn't need to set or +understand this field. A workflow can be the user's name, a +controller's name, or the name of a specific apply path like +"ci-cd". The set of fields is always in the version that the +workflow used when modifying the object. + ++optional */ + managedFields?: V1ManagedFieldsEntry[] + /** Name must be unique within a namespace. Is required when creating resources, although +some resources may allow a client to request the generation of an appropriate name +automatically. Name is primarily intended for creation idempotence and configuration +definition. +Cannot be updated. +More info: http://kubernetes.io/docs/user-guide/identifiers#names ++optional */ + name?: string + /** Namespace defines the space within which each name must be unique. An empty namespace is +equivalent to the "default" namespace, but "default" is the canonical representation. +Not all objects are required to be scoped to a namespace - the value of this field for +those objects will be empty. + +Must be a DNS_LABEL. +Cannot be updated. +More info: http://kubernetes.io/docs/user-guide/namespaces ++optional */ + namespace?: string + /** List of objects depended by this object. If ALL objects in the list have +been deleted, this object will be garbage collected. If this object is managed by a controller, +then an entry in this list will point to this controller, with the controller field set to true. +There cannot be more than one managing controller. ++optional ++patchMergeKey=uid ++patchStrategy=merge */ + ownerReferences?: V1OwnerReference[] + /** An opaque value that represents the internal version of this object that can +be used by clients to determine when objects have changed. May be used for optimistic +concurrency, change detection, and the watch operation on a resource or set of resources. +Clients must treat these values as opaque and passed unmodified back to the server. +They may only be valid for a particular resource or set of resources. + +Populated by the system. +Read-only. +Value must be treated as opaque by clients and . +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency ++optional */ + resourceVersion?: string + /** Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. ++optional */ + selfLink?: string + spec?: V1alpha1WorkflowSpec + status?: V1alpha1WorkflowStatus + /** UID is the unique in time and space value for this object. It is typically generated by +the server on successful creation of a resource and is not allowed to change on PUT +operations. + +Populated by the system. +Read-only. +More info: http://kubernetes.io/docs/user-guide/identifiers#uids ++optional */ + uid?: string +} + +export interface V1alpha1VMSpec { + /** The name of the VM to be injected */ + 'vm-name'?: string +} + +export interface V1alpha1UserDefinedSpec { + /** The command to be executed when attack */ + attackCmd?: string + /** The command to be executed when recover */ + recoverCmd?: string +} + +export interface V1alpha1Timespec { + nsec?: number + sec?: number +} + +export interface V1alpha1TimeChaosSpec { + /** ClockIds defines all affected clock id +All available options are ["CLOCK_REALTIME","CLOCK_MONOTONIC","CLOCK_PROCESS_CPUTIME_ID","CLOCK_THREAD_CPUTIME_ID", +"CLOCK_MONOTONIC_RAW","CLOCK_REALTIME_COARSE","CLOCK_MONOTONIC_COARSE","CLOCK_BOOTTIME","CLOCK_REALTIME_ALARM", +"CLOCK_BOOTTIME_ALARM"] +Default value is ["CLOCK_REALTIME"] */ + clockIds?: string[] + /** ContainerNames indicates list of the name of affected container. +If not set, the first container will be injected ++optional */ + containerNames?: string[] + /** Duration represents the duration of the chaos action */ + duration?: string + /** Mode defines the mode to run chaos action. +Supported mode: one / all / fixed / fixed-percent / random-max-percent ++kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent */ + mode?: string + /** RemoteCluster represents the remote cluster where the chaos will be deployed ++optional */ + remoteCluster?: string + selector?: V1alpha1PodSelectorSpec + /** TimeOffset defines the delta time of injected program. It's a possibly signed sequence of decimal numbers, such as +"300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". */ + timeOffset?: string + /** Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. +If `FixedMode`, provide an integer of pods to do chaos action. +If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. +IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action ++optional */ + value?: string +} + +export interface V1alpha1Task { + container?: V1Container + /** Volumes is a list of volumes that can be mounted by containers in a template. ++patchStrategy=merge ++patchMergeKey=name */ + volumes?: V1Volume[] +} + +export interface V1alpha1Template { + /** AbortWithStatusCheck describe whether to abort the workflow when the failure threshold of StatusCheck is exceeded. +Only used when Type is TypeStatusCheck. ++optional */ + abortWithStatusCheck?: boolean + awsChaos?: V1alpha1AWSChaosSpec + azureChaos?: V1alpha1AzureChaosSpec + blockChaos?: V1alpha1BlockChaosSpec + /** Children describes the children steps of serial or parallel node. Only used when Type is TypeSerial or TypeParallel. ++optional */ + children?: string[] + /** ConditionalBranches describes the conditional branches of custom tasks. Only used when Type is TypeTask. ++optional */ + conditionalBranches?: V1alpha1ConditionalBranch[] + /** +optional */ + deadline?: string + dnsChaos?: V1alpha1DNSChaosSpec + gcpChaos?: V1alpha1GCPChaosSpec + httpChaos?: V1alpha1HTTPChaosSpec + ioChaos?: V1alpha1IOChaosSpec + jvmChaos?: V1alpha1JVMChaosSpec + kernelChaos?: V1alpha1KernelChaosSpec + name?: string + networkChaos?: V1alpha1NetworkChaosSpec + physicalmachineChaos?: V1alpha1PhysicalMachineChaosSpec + podChaos?: V1alpha1PodChaosSpec + schedule?: V1alpha1ChaosOnlyScheduleSpec + statusCheck?: V1alpha1StatusCheckSpec + stressChaos?: V1alpha1StressChaosSpec + task?: V1alpha1Task + templateType?: string + timeChaos?: V1alpha1TimeChaosSpec +} + +export interface V1alpha1Stressors { + cpu?: V1alpha1CPUStressor + memory?: V1alpha1MemoryStressor +} + +export interface V1alpha1StressMemorySpec { + /** extend stress-ng options */ + options?: string[] + /** specifies N bytes consumed per vm worker, default is the total available memory. +One can specify the size as % of total available memory or in units of B, KB/KiB, MB/MiB, GB/GiB, TB/TiB.. */ + size?: string +} + +export interface V1alpha1StressChaosSpec { + /** ContainerNames indicates list of the name of affected container. +If not set, the first container will be injected ++optional */ + containerNames?: string[] + /** Duration represents the duration of the chaos action ++optional */ + duration?: string + /** Mode defines the mode to run chaos action. +Supported mode: one / all / fixed / fixed-percent / random-max-percent ++kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent */ + mode?: string + /** RemoteCluster represents the remote cluster where the chaos will be deployed ++optional */ + remoteCluster?: string + selector?: V1alpha1PodSelectorSpec + /** StressngStressors defines plenty of stressors just like `Stressors` except that it's an experimental +feature and more powerful. You can define stressors in `stress-ng` (see also `man stress-ng`) dialect, +however not all of the supported stressors are well tested. It maybe retired in later releases. You +should always use `Stressors` to define the stressors and use this only when you want more stressors +unsupported by `Stressors`. When both `StressngStressors` and `Stressors` are defined, `StressngStressors` +wins. ++optional */ + stressngStressors?: string + stressors?: V1alpha1Stressors + /** Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. +If `FixedMode`, provide an integer of pods to do chaos action. +If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. +IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action ++optional */ + value?: string +} + +export interface V1alpha1StressCPUSpec { + /** specifies P percent loading per CPU worker. 0 is effectively a sleep (no load) and 100 is full loading. */ + load?: number + /** extend stress-ng options */ + options?: string[] + /** specifies N workers to apply the stressor. */ + workers?: number +} + +export interface V1alpha1StatusCheckTemplate { + /** Duration defines the duration of the whole status check if the +number of failed execution does not exceed the failure threshold. +Duration is available to both `Synchronous` and `Continuous` mode. +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". ++optional */ + duration?: string + /** FailureThreshold defines the minimum consecutive failure +for the status check to be considered failed. ++optional ++kubebuilder:default=3 ++kubebuilder:validation:Minimum=1 */ + failureThreshold?: number + http?: V1alpha1HTTPStatusCheck + /** IntervalSeconds defines how often (in seconds) to perform +an execution of status check. ++optional ++kubebuilder:default=10 ++kubebuilder:validation:Minimum=1 */ + intervalSeconds?: number + /** Mode defines the execution mode of the status check. +Support type: Synchronous / Continuous ++optional ++kubebuilder:validation:Enum=Synchronous;Continuous */ + mode?: string + /** RecordsHistoryLimit defines the number of record to retain. ++optional ++kubebuilder:default=100 ++kubebuilder:validation:Minimum=1 ++kubebuilder:validation:Maximum=1000 */ + recordsHistoryLimit?: number + /** SuccessThreshold defines the minimum consecutive successes +for the status check to be considered successful. +SuccessThreshold only works for `Synchronous` mode. ++optional ++kubebuilder:default=1 ++kubebuilder:validation:Minimum=1 */ + successThreshold?: number + /** TimeoutSeconds defines the number of seconds after which +an execution of status check times out. ++optional ++kubebuilder:default=1 ++kubebuilder:validation:Minimum=1 */ + timeoutSeconds?: number + /** Type defines the specific status check type. +Support type: HTTP ++kubebuilder:default=HTTP ++kubebuilder:validation:Enum=HTTP */ + type?: string +} + +export interface V1alpha1StatusCheckSpec { + /** Duration defines the duration of the whole status check if the +number of failed execution does not exceed the failure threshold. +Duration is available to both `Synchronous` and `Continuous` mode. +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". ++optional */ + duration?: string + /** FailureThreshold defines the minimum consecutive failure +for the status check to be considered failed. ++optional ++kubebuilder:default=3 ++kubebuilder:validation:Minimum=1 */ + failureThreshold?: number + http?: V1alpha1HTTPStatusCheck + /** IntervalSeconds defines how often (in seconds) to perform +an execution of status check. ++optional ++kubebuilder:default=10 ++kubebuilder:validation:Minimum=1 */ + intervalSeconds?: number + /** Mode defines the execution mode of the status check. +Support type: Synchronous / Continuous ++optional ++kubebuilder:validation:Enum=Synchronous;Continuous */ + mode?: string + /** RecordsHistoryLimit defines the number of record to retain. ++optional ++kubebuilder:default=100 ++kubebuilder:validation:Minimum=1 ++kubebuilder:validation:Maximum=1000 */ + recordsHistoryLimit?: number + /** SuccessThreshold defines the minimum consecutive successes +for the status check to be considered successful. +SuccessThreshold only works for `Synchronous` mode. ++optional ++kubebuilder:default=1 ++kubebuilder:validation:Minimum=1 */ + successThreshold?: number + /** TimeoutSeconds defines the number of seconds after which +an execution of status check times out. ++optional ++kubebuilder:default=1 ++kubebuilder:validation:Minimum=1 */ + timeoutSeconds?: number + /** Type defines the specific status check type. +Support type: HTTP ++kubebuilder:default=HTTP ++kubebuilder:validation:Enum=HTTP */ + type?: string +} + +export interface V1alpha1ScheduleStatus { + /** +optional */ + active?: V1ObjectReference[] + /** +optional ++nullable */ + time?: string +} + +export interface V1alpha1ScheduleSpec { + awsChaos?: V1alpha1AWSChaosSpec + azureChaos?: V1alpha1AzureChaosSpec + blockChaos?: V1alpha1BlockChaosSpec + /** +optional ++kubebuilder:default=Forbid ++kubebuilder:validation:Enum=Forbid;Allow */ + concurrencyPolicy?: string + dnsChaos?: V1alpha1DNSChaosSpec + gcpChaos?: V1alpha1GCPChaosSpec + /** +optional ++kubebuilder:validation:Minimum=1 */ + historyLimit?: number + httpChaos?: V1alpha1HTTPChaosSpec + ioChaos?: V1alpha1IOChaosSpec + jvmChaos?: V1alpha1JVMChaosSpec + kernelChaos?: V1alpha1KernelChaosSpec + networkChaos?: V1alpha1NetworkChaosSpec + physicalmachineChaos?: V1alpha1PhysicalMachineChaosSpec + podChaos?: V1alpha1PodChaosSpec + schedule?: string + /** +optional ++nullable ++kubebuilder:validation:Minimum=0 ++kubebuilder:validation:ExclusiveMinimum=true */ + startingDeadlineSeconds?: number + stressChaos?: V1alpha1StressChaosSpec + timeChaos?: V1alpha1TimeChaosSpec + /** TODO: use a custom type, as `TemplateType` contains other possible values */ + type?: string + workflow?: V1alpha1WorkflowSpec +} + +/** + * Map of string keys and values that can be used to organize and categorize +(scope and select) objects. May match selectors of replication controllers +and services. +More info: http://kubernetes.io/docs/user-guide/labels ++optional + */ +export type V1alpha1ScheduleLabels = { [key: string]: string } + +/** + * Annotations is an unstructured key value map stored with a resource that may be +set by external tools to store and retrieve arbitrary metadata. They are not +queryable and should be preserved when modifying objects. +More info: http://kubernetes.io/docs/user-guide/annotations ++optional + */ +export type V1alpha1ScheduleAnnotations = { [key: string]: string } + +export interface V1alpha1Schedule { + /** Annotations is an unstructured key value map stored with a resource that may be +set by external tools to store and retrieve arbitrary metadata. They are not +queryable and should be preserved when modifying objects. +More info: http://kubernetes.io/docs/user-guide/annotations ++optional */ + annotations?: V1alpha1ScheduleAnnotations + /** APIVersion defines the versioned schema of this representation of an object. +Servers should convert recognized schemas to the latest internal value, and +may reject unrecognized values. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources ++optional */ + apiVersion?: string + /** CreationTimestamp is a timestamp representing the server time when this object was +created. It is not guaranteed to be set in happens-before order across separate operations. +Clients may not set this value. It is represented in RFC3339 form and is in UTC. + +Populated by the system. +Read-only. +Null for lists. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata ++optional */ + creationTimestamp?: string + /** Number of seconds allowed for this object to gracefully terminate before +it will be removed from the system. Only set when deletionTimestamp is also set. +May only be shortened. +Read-only. ++optional */ + deletionGracePeriodSeconds?: number + /** DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This +field is set by the server when a graceful deletion is requested by the user, and is not +directly settable by a client. The resource is expected to be deleted (no longer visible +from resource lists, and not reachable by name) after the time in this field, once the +finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. +Once the deletionTimestamp is set, this value may not be unset or be set further into the +future, although it may be shortened or the resource may be deleted prior to this time. +For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react +by sending a graceful termination signal to the containers in the pod. After that 30 seconds, +the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, +remove the pod from the API. In the presence of network partitions, this object may still +exist after this timestamp, until an administrator or automated process can determine the +resource is fully terminated. +If not set, graceful deletion of the object has not been requested. + +Populated by the system when a graceful deletion is requested. +Read-only. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata ++optional */ + deletionTimestamp?: string + /** Must be empty before the object is deleted from the registry. Each entry +is an identifier for the responsible component that will remove the entry +from the list. If the deletionTimestamp of the object is non-nil, entries +in this list can only be removed. +Finalizers may be processed and removed in any order. Order is NOT enforced +because it introduces significant risk of stuck finalizers. +finalizers is a shared field, any actor with permission can reorder it. +If the finalizer list is processed in order, then this can lead to a situation +in which the component responsible for the first finalizer in the list is +waiting for a signal (field value, external system, or other) produced by a +component responsible for a finalizer later in the list, resulting in a deadlock. +Without enforced ordering finalizers are free to order amongst themselves and +are not vulnerable to ordering changes in the list. ++optional ++patchStrategy=merge */ + finalizers?: string[] + /** GenerateName is an optional prefix, used by the server, to generate a unique +name ONLY IF the Name field has not been provided. +If this field is used, the name returned to the client will be different +than the name passed. This value will also be combined with a unique suffix. +The provided value has the same validation rules as the Name field, +and may be truncated by the length of the suffix required to make the value +unique on the server. + +If this field is specified and the generated name exists, the server will return a 409. + +Applied only if Name is not specified. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency ++optional */ + generateName?: string + /** A sequence number representing a specific generation of the desired state. +Populated by the system. Read-only. ++optional */ + generation?: number + /** Kind is a string value representing the REST resource this object represents. +Servers may infer this from the endpoint the client submits requests to. +Cannot be updated. +In CamelCase. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds ++optional */ + kind?: string + /** Map of string keys and values that can be used to organize and categorize +(scope and select) objects. May match selectors of replication controllers +and services. +More info: http://kubernetes.io/docs/user-guide/labels ++optional */ + labels?: V1alpha1ScheduleLabels + /** ManagedFields maps workflow-id and version to the set of fields +that are managed by that workflow. This is mostly for internal +housekeeping, and users typically shouldn't need to set or +understand this field. A workflow can be the user's name, a +controller's name, or the name of a specific apply path like +"ci-cd". The set of fields is always in the version that the +workflow used when modifying the object. + ++optional */ + managedFields?: V1ManagedFieldsEntry[] + /** Name must be unique within a namespace. Is required when creating resources, although +some resources may allow a client to request the generation of an appropriate name +automatically. Name is primarily intended for creation idempotence and configuration +definition. +Cannot be updated. +More info: http://kubernetes.io/docs/user-guide/identifiers#names ++optional */ + name?: string + /** Namespace defines the space within which each name must be unique. An empty namespace is +equivalent to the "default" namespace, but "default" is the canonical representation. +Not all objects are required to be scoped to a namespace - the value of this field for +those objects will be empty. + +Must be a DNS_LABEL. +Cannot be updated. +More info: http://kubernetes.io/docs/user-guide/namespaces ++optional */ + namespace?: string + /** List of objects depended by this object. If ALL objects in the list have +been deleted, this object will be garbage collected. If this object is managed by a controller, +then an entry in this list will point to this controller, with the controller field set to true. +There cannot be more than one managing controller. ++optional ++patchMergeKey=uid ++patchStrategy=merge */ + ownerReferences?: V1OwnerReference[] + /** An opaque value that represents the internal version of this object that can +be used by clients to determine when objects have changed. May be used for optimistic +concurrency, change detection, and the watch operation on a resource or set of resources. +Clients must treat these values as opaque and passed unmodified back to the server. +They may only be valid for a particular resource or set of resources. + +Populated by the system. +Read-only. +Value must be treated as opaque by clients and . +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency ++optional */ + resourceVersion?: string + /** Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. ++optional */ + selfLink?: string + spec?: V1alpha1ScheduleSpec + status?: V1alpha1ScheduleStatus + /** UID is the unique in time and space value for this object. It is typically generated by +the server on successful creation of a resource and is not allowed to change on PUT +operations. + +Populated by the system. +Read-only. +More info: http://kubernetes.io/docs/user-guide/identifiers#uids ++optional */ + uid?: string +} + +export interface V1alpha1ReorderSpec { + /** +optional */ + correlation?: string + gap?: number + reorder?: string +} + +export interface V1alpha1RedisSentinelStopSpec { + /** The adress of Redis server */ + addr?: string + /** The path of Sentinel conf */ + conf?: string + /** The control flag determines whether to flush config */ + flushConfig?: boolean + /** The password of Redis server */ + password?: string + /** The path of `redis-server` command-line tool */ + redisPath?: boolean +} + +export interface V1alpha1RedisSentinelRestartSpec { + /** The adress of Redis server */ + addr?: string + /** The path of Sentinel conf */ + conf?: string + /** The control flag determines whether to flush config */ + flushConfig?: boolean + /** The password of Redis server */ + password?: string + /** The path of `redis-server` command-line tool */ + redisPath?: boolean +} + +export interface V1alpha1RedisPenetrationSpec { + /** The adress of Redis server */ + addr?: string + /** The password of Redis server */ + password?: string + /** The number of requests to be sent */ + requestNum?: number +} + +export interface V1alpha1RedisExpirationSpec { + /** The adress of Redis server */ + addr?: string + /** The expiration of the keys */ + expiration?: string + /** The keys to be expired */ + key?: string + /** Additional options for `expiration` */ + option?: string + /** The password of Redis server */ + password?: string +} + +export interface V1alpha1RedisCacheLimitSpec { + /** The adress of Redis server */ + addr?: string + /** The size of `maxmemory` */ + cacheSize?: string + /** The password of Redis server */ + password?: string + /** Specifies maxmemory as a percentage of the original value */ + percent?: string +} + +export interface V1alpha1ProcessSpec { + /** the process name or the process ID */ + process?: string + /** the command to be run when recovering experiment */ + recoverCmd?: string + /** the signal number to send */ + signal?: number +} + +/** + * Pods is a map of string keys and a set values that used to select pods. +The key defines the namespace which pods belong, +and the each values is a set of pod names. ++optional + */ +export type V1alpha1PodSelectorSpecPods = { [key: string]: string[] } + +/** + * Map of string keys and values that can be used to select nodes. +Selector which must match a node's labels, +and objects must belong to these selected nodes. ++optional + */ +export type V1alpha1PodSelectorSpecNodeSelectors = { [key: string]: string } + +/** + * Map of string keys and values that can be used to select objects. +A selector based on labels. ++optional + */ +export type V1alpha1PodSelectorSpecLabelSelectors = { [key: string]: string } + +/** + * Map of string keys and values that can be used to select objects. +A selector based on fields. ++optional + */ +export type V1alpha1PodSelectorSpecFieldSelectors = { [key: string]: string } + +/** + * Map of string keys and values that can be used to select objects. +A selector based on annotations. ++optional + */ +export type V1alpha1PodSelectorSpecAnnotationSelectors = { [key: string]: string } + +export interface V1alpha1PodSelectorSpec { + /** Map of string keys and values that can be used to select objects. +A selector based on annotations. ++optional */ + annotationSelectors?: V1alpha1PodSelectorSpecAnnotationSelectors + /** Map of string keys and values that can be used to select objects. +A selector based on fields. ++optional */ + fieldSelectors?: V1alpha1PodSelectorSpecFieldSelectors + /** Map of string keys and values that can be used to select objects. +A selector based on labels. ++optional */ + labelSelectors?: V1alpha1PodSelectorSpecLabelSelectors + /** Namespaces is a set of namespace to which objects belong. ++optional */ + namespaces?: string[] + /** Map of string keys and values that can be used to select nodes. +Selector which must match a node's labels, +and objects must belong to these selected nodes. ++optional */ + nodeSelectors?: V1alpha1PodSelectorSpecNodeSelectors + /** Nodes is a set of node name and objects must belong to these nodes. ++optional */ + nodes?: string[] + /** PodPhaseSelectors is a set of condition of a pod at the current time. +supported value: Pending / Running / Succeeded / Failed / Unknown ++optional */ + podPhaseSelectors?: string[] + /** Pods is a map of string keys and a set values that used to select pods. +The key defines the namespace which pods belong, +and the each values is a set of pod names. ++optional */ + pods?: V1alpha1PodSelectorSpecPods +} + +export interface V1alpha1PodSelector { + /** Mode defines the mode to run chaos action. +Supported mode: one / all / fixed / fixed-percent / random-max-percent ++kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent */ + mode?: string + selector?: V1alpha1PodSelectorSpec + /** Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. +If `FixedMode`, provide an integer of pods to do chaos action. +If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. +IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action ++optional */ + value?: string +} + +export interface V1alpha1PodHttpChaosTLS { + /** CAName represents the data name of ca file in secret, `ca.crt` for example ++optional */ + caName?: string + /** CertName represents the data name of cert file in secret, `tls.crt` for example */ + certName?: string + /** KeyName represents the data name of key file in secret, `tls.key` for example */ + keyName?: string + /** SecretName represents the name of required secret resource */ + secretName?: string + /** SecretNamespace represents the namespace of required secret resource */ + secretNamespace?: string +} + +/** + * Queries is a rule to replace uri queries in http request. +For example, with value `{ "foo": "unknown" }`, the `/?foo=bar` will be altered to `/?foo=unknown`, ++optional + */ +export type V1alpha1PodHttpChaosReplaceActionsQueries = { [key: string]: string } + +/** + * Headers is a rule to replace http headers of target. +The key-value pairs represent header name and header value pairs. ++optional + */ +export type V1alpha1PodHttpChaosReplaceActionsHeaders = { [key: string]: string } + +export interface V1alpha1PodHttpChaosReplaceActions { + /** Body is a rule to replace http message body in target. ++optional */ + body?: number[] + /** Code is a rule to replace http status code in response. ++optional */ + code?: number + /** Headers is a rule to replace http headers of target. +The key-value pairs represent header name and header value pairs. ++optional */ + headers?: V1alpha1PodHttpChaosReplaceActionsHeaders + /** Method is a rule to replace http method in request. ++optional */ + method?: string + /** Path is rule to to replace uri path in http request. ++optional */ + path?: string + /** Queries is a rule to replace uri queries in http request. +For example, with value `{ "foo": "unknown" }`, the `/?foo=bar` will be altered to `/?foo=unknown`, ++optional */ + queries?: V1alpha1PodHttpChaosReplaceActionsQueries +} + +export interface V1alpha1PodHttpChaosPatchBodyAction { + /** Type represents the patch type, only support `JSON` as [merge patch json](https://tools.ietf.org/html/rfc7396) currently. */ + type?: string + /** Value is the patch contents. */ + value?: string +} + +export interface V1alpha1PodHttpChaosPatchActions { + /** Body is a rule to patch message body of target. ++optional */ + body?: V1alpha1PodHttpChaosPatchBodyAction + /** Headers is a rule to append http headers of target. +For example: `[["Set-Cookie", ""], ["Set-Cookie", ""]]`. ++optional */ + headers?: string[][] + /** Queries is a rule to append uri queries of target(Request only). +For example: `[["foo", "bar"], ["foo", "unknown"]]`. ++optional */ + queries?: string[][] +} + +export interface V1alpha1PodChaosSpec { + /** Action defines the specific pod chaos action. +Supported action: pod-kill / pod-failure / container-kill +Default action: pod-kill ++kubebuilder:validation:Enum=pod-kill;pod-failure;container-kill */ + action?: string + /** ContainerNames indicates list of the name of affected container. +If not set, the first container will be injected ++optional */ + containerNames?: string[] + /** Duration represents the duration of the chaos action. +It is required when the action is `PodFailureAction`. +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". ++optional */ + duration?: string + /** GracePeriod is used in pod-kill action. It represents the duration in seconds before the pod should be deleted. +Value must be non-negative integer. The default value is zero that indicates delete immediately. ++optional ++kubebuilder:validation:Minimum=0 */ + gracePeriod?: number + /** Mode defines the mode to run chaos action. +Supported mode: one / all / fixed / fixed-percent / random-max-percent ++kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent */ + mode?: string + /** RemoteCluster represents the remote cluster where the chaos will be deployed ++optional */ + remoteCluster?: string + selector?: V1alpha1PodSelectorSpec + /** Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. +If `FixedMode`, provide an integer of pods to do chaos action. +If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. +IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action ++optional */ + value?: string +} + +/** + * PhysicalMachines is a map of string keys and a set values that used to select physical machines. +The key defines the namespace which physical machine belong, +and each value is a set of physical machine names. ++optional + */ +export type V1alpha1PhysicalMachineSelectorSpecPhysicalMachines = { [key: string]: string[] } + +/** + * Map of string keys and values that can be used to select objects. +A selector based on labels. ++optional + */ +export type V1alpha1PhysicalMachineSelectorSpecLabelSelectors = { [key: string]: string } + +/** + * Map of string keys and values that can be used to select objects. +A selector based on fields. ++optional + */ +export type V1alpha1PhysicalMachineSelectorSpecFieldSelectors = { [key: string]: string } + +/** + * Map of string keys and values that can be used to select objects. +A selector based on annotations. ++optional + */ +export type V1alpha1PhysicalMachineSelectorSpecAnnotationSelectors = { [key: string]: string } + +export interface V1alpha1PhysicalMachineSelectorSpec { + /** Map of string keys and values that can be used to select objects. +A selector based on annotations. ++optional */ + annotationSelectors?: V1alpha1PhysicalMachineSelectorSpecAnnotationSelectors + /** Map of string keys and values that can be used to select objects. +A selector based on fields. ++optional */ + fieldSelectors?: V1alpha1PhysicalMachineSelectorSpecFieldSelectors + /** Map of string keys and values that can be used to select objects. +A selector based on labels. ++optional */ + labelSelectors?: V1alpha1PhysicalMachineSelectorSpecLabelSelectors + /** Namespaces is a set of namespace to which objects belong. ++optional */ + namespaces?: string[] + /** PhysicalMachines is a map of string keys and a set values that used to select physical machines. +The key defines the namespace which physical machine belong, +and each value is a set of physical machine names. ++optional */ + physicalMachines?: V1alpha1PhysicalMachineSelectorSpecPhysicalMachines +} + +export interface V1alpha1PMJVMMySQLSpec { + /** the match database +default value is "", means match all database */ + database?: string + /** The exception which needs to throw for action `exception` +or the exception message needs to throw in action `mysql` */ + exception?: string + /** The latency duration for action 'latency' +or the latency duration in action `mysql` */ + latency?: number + /** the version of mysql-connector-java, only support 5.X.X(set to "5") and 8.X.X(set to "8") now */ + mysqlConnectorVersion?: string + /** the pid of Java process which needs to attach */ + pid?: number + /** +optional +the port of agent server, default 9277 */ + port?: number + /** the match sql type +default value is "", means match all SQL type. +The value can be 'select', 'insert', 'update', 'delete', 'replace'. */ + sqlType?: string + /** the match table +default value is "", means match all table */ + table?: string +} + +export interface V1alpha1NetworkPartitionSpec { + /** only the packet which match the tcp flag can be accepted, others will be dropped. +only set when the IPProtocol is tcp, used for partition. */ + 'accept-tcp-flags'?: string + /** the network interface to impact */ + device?: string + /** specifies the partition direction, values can be 'from', 'to'. +'from' means packets coming from the 'IPAddress' or 'Hostname' and going to your server, +'to' means packets originating from your server and going to the 'IPAddress' or 'Hostname'. */ + direction?: string + /** only impact traffic to these hostnames */ + hostname?: string + /** only impact egress traffic to these IP addresses */ + 'ip-address'?: string + /** only impact egress traffic to these IP addresses */ + 'ip-protocol'?: string +} + +export interface V1alpha1NetworkLossSpec { + /** correlation is percentage (10 is 10%) */ + correlation?: string + /** the network interface to impact */ + device?: string + /** only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. +it can only be used in conjunction with -p tcp or -p udp */ + 'egress-port'?: string + /** only impact traffic to these hostnames */ + hostname?: string + /** only impact egress traffic to these IP addresses */ + 'ip-address'?: string + /** only impact traffic using this IP protocol, supported: tcp, udp, icmp, all */ + 'ip-protocol'?: string + /** percentage of packets to loss (10 is 10%) */ + percent?: string + /** only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. +it can only be used in conjunction with -p tcp or -p udp */ + 'source-port'?: string +} + +export interface V1alpha1NetworkFloodSpec { + /** The number of seconds to run the iperf test */ + duration?: string + /** Generate traffic to this IP address */ + 'ip-address'?: string + /** The number of iperf parallel client threads to run */ + parallel?: number + /** Generate traffic to this port on the IP address */ + port?: string + /** The speed of network traffic, allows bps, kbps, mbps, gbps, tbps unit. bps means bytes per second */ + rate?: string +} + +export interface V1alpha1NetworkDuplicateSpec { + /** correlation is percentage (10 is 10%) */ + correlation?: string + /** the network interface to impact */ + device?: string + /** only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. +it can only be used in conjunction with -p tcp or -p udp */ + 'egress-port'?: string + /** only impact traffic to these hostnames */ + hostname?: string + /** only impact egress traffic to these IP addresses */ + 'ip-address'?: string + /** only impact traffic using this IP protocol, supported: tcp, udp, icmp, all */ + 'ip-protocol'?: string + /** percentage of packets to duplicate (10 is 10%) */ + percent?: string + /** only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. +it can only be used in conjunction with -p tcp or -p udp */ + 'source-port'?: string +} + +export interface V1alpha1NetworkDownSpec { + /** The network interface to impact */ + device?: string + /** NIC down time, time units: ns, us (or µs), ms, s, m, h. */ + duration?: string +} + +export interface V1alpha1NetworkDelaySpec { + /** only the packet which match the tcp flag can be accepted, others will be dropped. +only set when the IPProtocol is tcp, used for partition. */ + 'accept-tcp-flags'?: string + /** correlation is percentage (10 is 10%) */ + correlation?: string + /** the network interface to impact */ + device?: string + /** only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. +it can only be used in conjunction with -p tcp or -p udp */ + 'egress-port'?: string + /** only impact traffic to these hostnames */ + hostname?: string + /** only impact egress traffic to these IP addresses */ + 'ip-address'?: string + /** only impact traffic using this IP protocol, supported: tcp, udp, icmp, all */ + 'ip-protocol'?: string + /** jitter time, time units: ns, us (or µs), ms, s, m, h. */ + jitter?: string + /** delay egress time, time units: ns, us (or µs), ms, s, m, h. */ + latency?: string + /** only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. +it can only be used in conjunction with -p tcp or -p udp */ + 'source-port'?: string +} + +export interface V1alpha1NetworkDNSSpec { + /** map this host to specified IP */ + 'dns-domain-name'?: string + /** map specified host to this IP address */ + 'dns-ip'?: string + /** update the DNS server in /etc/resolv.conf with this value */ + 'dns-server'?: string +} + +export interface V1alpha1NetworkCorruptSpec { + /** correlation is percentage (10 is 10%) */ + correlation?: string + /** the network interface to impact */ + device?: string + /** only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. +it can only be used in conjunction with -p tcp or -p udp */ + 'egress-port'?: string + /** only impact traffic to these hostnames */ + hostname?: string + /** only impact egress traffic to these IP addresses */ + 'ip-address'?: string + /** only impact traffic using this IP protocol, supported: tcp, udp, icmp, all */ + 'ip-protocol'?: string + /** percentage of packets to corrupt (10 is 10%) */ + percent?: string + /** only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. +it can only be used in conjunction with -p tcp or -p udp */ + 'source-port'?: string +} + +export interface V1alpha1NetworkChaosSpec { + /** Action defines the specific network chaos action. +Supported action: partition, netem, delay, loss, duplicate, corrupt +Default action: delay ++kubebuilder:validation:Enum=netem;delay;loss;duplicate;corrupt;partition;bandwidth */ + action?: string + /** Bandwidth represents the detail about bandwidth control action ++ui:form:when=action=='bandwidth' ++optional */ + bandwidth?: V1alpha1BandwidthSpec + /** Corrupt represents the detail about corrupt action ++ui:form:when=action=='corrupt' ++optional */ + corrupt?: V1alpha1CorruptSpec + /** Delay represents the detail about delay action ++ui:form:when=action=='delay' ++optional */ + delay?: V1alpha1DelaySpec + /** Device represents the network device to be affected. ++optional */ + device?: string + /** Direction represents the direction, this applies on netem and network partition action ++optional ++kubebuilder:validation:Enum=to;from;both ++kubebuilder:default=to */ + direction?: string + /** DuplicateSpec represents the detail about loss action ++ui:form:when=action=='duplicate' ++optional */ + duplicate?: V1alpha1DuplicateSpec + /** Duration represents the duration of the chaos action */ + duration?: string + /** ExternalTargets represents network targets outside k8s ++optional */ + externalTargets?: string[] + /** Loss represents the detail about loss action ++ui:form:when=action=='loss' ++optional */ + loss?: V1alpha1LossSpec + /** Mode defines the mode to run chaos action. +Supported mode: one / all / fixed / fixed-percent / random-max-percent ++kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent */ + mode?: string + /** RemoteCluster represents the remote cluster where the chaos will be deployed ++optional */ + remoteCluster?: string + selector?: V1alpha1PodSelectorSpec + target?: V1alpha1PodSelector + /** TargetDevice represents the network device to be affected in target scope. ++optional */ + targetDevice?: string + /** Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. +If `FixedMode`, provide an integer of pods to do chaos action. +If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. +IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action ++optional */ + value?: string +} + +export interface V1alpha1NetworkBandwidthSpec { + /** +kubebuilder:validation:Minimum=1 */ + buffer?: number + device?: string + hostname?: string + 'ip-address'?: string + /** +kubebuilder:validation:Minimum=1 */ + limit?: number + minburst?: number + peakrate?: number + rate?: string +} + +export interface V1alpha1MistakeSpec { + /** Filling determines what is filled in the mistake data. ++optional ++kubebuilder:validation:Enum=zero;random */ + filling?: string + /** Max length of each wrong data segment in bytes ++optional ++kubebuilder:validation:Minimum=1 */ + maxLength?: number + /** There will be [1, MaxOccurrences] segments of wrong data. ++optional ++kubebuilder:validation:Minimum=1 */ + maxOccurrences?: number +} + +export interface V1alpha1MemoryStressor { + /** OOMScoreAdj sets the oom_score_adj of the stress process. See `man 5 proc` to know more +about this option. ++kubebuilder:validation:Minimum=-1000 ++kubebuilder:validation:Maximum=1000 ++kubebuilder:default=0 ++optional */ + oomScoreAdj?: number + /** extend stress-ng options ++optional */ + options?: string[] + /** Size specifies N bytes consumed per vm worker, default is the total available memory. +One can specify the size as % of total available memory or in units of B, KB/KiB, +MB/MiB, GB/GiB, TB/TiB. ++optional */ + size?: string + /** Workers specifies N workers to apply the stressor. +Maximum 8192 workers can run by stress-ng ++kubebuilder:validation:Maximum=8192 */ + workers?: number +} + +export interface V1alpha1LossSpec { + /** +optional */ + correlation?: string + loss?: string +} + +export interface V1alpha1KernelChaosSpec { + /** ContainerNames indicates list of the name of affected container. +If not set, the first container will be injected ++optional */ + containerNames?: string[] + /** Duration represents the duration of the chaos action */ + duration?: string + failKernRequest?: V1alpha1FailKernRequest + /** Mode defines the mode to run chaos action. +Supported mode: one / all / fixed / fixed-percent / random-max-percent ++kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent */ + mode?: string + /** RemoteCluster represents the remote cluster where the chaos will be deployed ++optional */ + remoteCluster?: string + selector?: V1alpha1PodSelectorSpec + /** Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. +If `FixedMode`, provide an integer of pods to do chaos action. +If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. +IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action ++optional */ + value?: string +} + +export interface V1alpha1KafkaIOSpec { + /** The path of server config */ + configFile?: string + /** Make kafka cluster non-readable */ + nonReadable?: boolean + /** Make kafka cluster non-writable */ + nonWritable?: boolean + /** The topic to attack */ + topic?: string +} + +export interface V1alpha1KafkaFloodSpec { + /** The host of kafka server */ + host?: string + /** The size of each message */ + messageSize?: number + /** The password of kafka client */ + password?: string + /** The port of kafka server */ + port?: number + /** The number of worker threads */ + threads?: number + /** The topic to attack */ + topic?: string + /** The username of kafka client */ + username?: string +} + +export interface V1alpha1KafkaFillSpec { + /** The host of kafka server */ + host?: string + /** The max bytes to fill */ + maxBytes?: number + /** The size of each message */ + messageSize?: number + /** The password of kafka client */ + password?: string + /** The port of kafka server */ + port?: number + /** The command to reload kafka config */ + reloadCommand?: string + /** The topic to attack */ + topic?: string + /** The username of kafka client */ + username?: string +} + +export interface V1alpha1JVMStressSpec { + /** the CPU core number need to use, only set it when action is stress */ + 'cpu-count'?: number + /** the memory type need to locate, only set it when action is stress, the value can be 'stack' or 'heap' */ + 'mem-type'?: string + /** the pid of Java process which needs to attach */ + pid?: number + /** +optional +the port of agent server, default 9277 */ + port?: number +} + +export interface V1alpha1JVMRuleDataSpec { + /** the pid of Java process which needs to attach */ + pid?: number + /** +optional +the port of agent server, default 9277 */ + port?: number + /** RuleData used to save the rule file's data, will use it when recover */ + 'rule-data'?: string +} + +export interface V1alpha1JVMReturnSpec { + /** +optional +Java class */ + class?: string + /** +optional +the method in Java class */ + method?: string + /** the pid of Java process which needs to attach */ + pid?: number + /** +optional +the port of agent server, default 9277 */ + port?: number + /** the return value for action 'return' */ + value?: string +} + +export interface V1alpha1JVMLatencySpec { + /** +optional +Java class */ + class?: string + /** the latency duration for action 'latency', unit ms */ + latency?: number + /** +optional +the method in Java class */ + method?: string + /** the pid of Java process which needs to attach */ + pid?: number + /** +optional +the port of agent server, default 9277 */ + port?: number +} + +export interface V1alpha1JVMGCSpec { + /** the pid of Java process which needs to attach */ + pid?: number + /** +optional +the port of agent server, default 9277 */ + port?: number +} + +export interface V1alpha1JVMExceptionSpec { + /** +optional +Java class */ + class?: string + /** the exception which needs to throw for action `exception` */ + exception?: string + /** +optional +the method in Java class */ + method?: string + /** the pid of Java process which needs to attach */ + pid?: number + /** +optional +the port of agent server, default 9277 */ + port?: number +} + +export interface V1alpha1PhysicalMachineChaosSpec { + /** +kubebuilder:validation:Enum=stress-cpu;stress-mem;disk-read-payload;disk-write-payload;disk-fill;network-corrupt;network-duplicate;network-loss;network-delay;network-partition;network-dns;network-bandwidth;network-flood;network-down;process;jvm-exception;jvm-gc;jvm-latency;jvm-return;jvm-stress;jvm-rule-data;jvm-mysql;clock;redis-expiration;redis-penetration;redis-cacheLimit;redis-restart;redis-stop;kafka-fill;kafka-flood;kafka-io;file-create;file-modify;file-delete;file-rename;file-append;file-replace;vm;user_defined */ + action?: string + /** DEPRECATED: Use Selector instead. +Only one of Address and Selector could be specified. ++optional */ + address?: string[] + /** +ui:form:when=action=='clock' ++optional */ + clock?: V1alpha1ClockSpec + /** +ui:form:when=action=='disk-fill' ++optional */ + 'disk-fill'?: V1alpha1DiskFillSpec + /** +ui:form:when=action=='disk-read-payload' ++optional */ + 'disk-read-payload'?: V1alpha1DiskPayloadSpec + /** +ui:form:when=action=='disk-write-payload' ++optional */ + 'disk-write-payload'?: V1alpha1DiskPayloadSpec + /** Duration represents the duration of the chaos action ++optional */ + duration?: string + /** +ui:form:when=action=='file-append' ++optional */ + 'file-append'?: V1alpha1FileAppendSpec + /** +ui:form:when=action=='file-create' ++optional */ + 'file-create'?: V1alpha1FileCreateSpec + /** +ui:form:when=action=='file-delete' ++optional */ + 'file-delete'?: V1alpha1FileDeleteSpec + /** +ui:form:when=action=='file-modify' ++optional */ + 'file-modify'?: V1alpha1FileModifyPrivilegeSpec + /** +ui:form:when=action=='file-create' ++optional */ + 'file-rename'?: V1alpha1FileRenameSpec + /** +ui:form:when=action=='file-replace' ++optional */ + 'file-replace'?: V1alpha1FileReplaceSpec + /** +ui:form:when=action=='http-abort' ++optional */ + 'http-abort'?: V1alpha1HTTPAbortSpec + /** +ui:form:when=action=='http-config' ++optional */ + 'http-config'?: V1alpha1HTTPConfigSpec + /** +ui:form:when=action=='http-delay' ++optional */ + 'http-delay'?: V1alpha1HTTPDelaySpec + /** +ui:form:when=action=='http-request' ++optional */ + 'http-request'?: V1alpha1HTTPRequestSpec + /** +ui:form:when=action=='jvm-exception' ++optional */ + 'jvm-exception'?: V1alpha1JVMExceptionSpec + /** +ui:form:when=action=='jvm-gc' ++optional */ + 'jvm-gc'?: V1alpha1JVMGCSpec + /** +ui:form:when=action=='jvm-latency' ++optional */ + 'jvm-latency'?: V1alpha1JVMLatencySpec + /** +ui:form:when=action=='jvm-mysql' ++optional */ + 'jvm-mysql'?: V1alpha1PMJVMMySQLSpec + /** +ui:form:when=action=='jvm-return' ++optional */ + 'jvm-return'?: V1alpha1JVMReturnSpec + /** +ui:form:when=action=='jvm-rule-data' ++optional */ + 'jvm-rule-data'?: V1alpha1JVMRuleDataSpec + /** +ui:form:when=action=='jvm-stress' ++optional */ + 'jvm-stress'?: V1alpha1JVMStressSpec + /** +ui:form:when=action=='kafka-fill' ++optional */ + 'kafka-fill'?: V1alpha1KafkaFillSpec + /** +ui:form:when=action=='kafka-flood' ++optional */ + 'kafka-flood'?: V1alpha1KafkaFloodSpec + /** +ui:form:when=action=='kafka-io' ++optional */ + 'kafka-io'?: V1alpha1KafkaIOSpec + /** Mode defines the mode to run chaos action. +Supported mode: one / all / fixed / fixed-percent / random-max-percent ++kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent */ + mode?: string + /** +ui:form:when=action=='network-bandwidth' ++optional */ + 'network-bandwidth'?: V1alpha1NetworkBandwidthSpec + /** +ui:form:when=action=='network-corrupt' ++optional */ + 'network-corrupt'?: V1alpha1NetworkCorruptSpec + /** +ui:form:when=action=='network-delay' ++optional */ + 'network-delay'?: V1alpha1NetworkDelaySpec + /** +ui:form:when=action=='network-dns' ++optional */ + 'network-dns'?: V1alpha1NetworkDNSSpec + /** +ui:form:when=action=='network-down' ++optional */ + 'network-down'?: V1alpha1NetworkDownSpec + /** +ui:form:when=action=='network-duplicate' ++optional */ + 'network-duplicate'?: V1alpha1NetworkDuplicateSpec + /** +ui:form:when=action=='network-flood' ++optional */ + 'network-flood'?: V1alpha1NetworkFloodSpec + /** +ui:form:when=action=='network-loss' ++optional */ + 'network-loss'?: V1alpha1NetworkLossSpec + /** +ui:form:when=action=='network-partition' ++optional */ + 'network-partition'?: V1alpha1NetworkPartitionSpec + /** +ui:form:when=action=='process' ++optional */ + process?: V1alpha1ProcessSpec + /** +ui:form:when=action=='redis-cacheLimit' ++optional */ + 'redis-cacheLimit'?: V1alpha1RedisCacheLimitSpec + /** +ui:form:when=action=='redis-expiration' ++optional */ + 'redis-expiration'?: V1alpha1RedisExpirationSpec + /** +ui:form:when=action=='redis-penetration' ++optional */ + 'redis-penetration'?: V1alpha1RedisPenetrationSpec + /** +ui:form:when=action=='redis-restart' ++optional */ + 'redis-restart'?: V1alpha1RedisSentinelRestartSpec + /** +ui:form:when=action=='redis-stop' ++optional */ + 'redis-stop'?: V1alpha1RedisSentinelStopSpec + /** RemoteCluster represents the remote cluster where the chaos will be deployed ++optional */ + remoteCluster?: string + selector?: V1alpha1PhysicalMachineSelectorSpec + /** +ui:form:when=action=='stress-cpu' ++optional */ + 'stress-cpu'?: V1alpha1StressCPUSpec + /** +ui:form:when=action=='stress-mem' ++optional */ + 'stress-mem'?: V1alpha1StressMemorySpec + /** +ui:form:when=action=='user_defined' ++optional */ + user_defined?: V1alpha1UserDefinedSpec + /** Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. +If `FixedMode`, provide an integer of physical machines to do chaos action. +If `FixedPercentMode`, provide a number from 0-100 to specify the percent of physical machines the server can do chaos action. +IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action ++optional */ + value?: string + /** +ui:form:when=action=='vm' ++optional */ + vm?: V1alpha1VMSpec +} + +export interface V1alpha1JVMChaosSpec { + /** Action defines the specific jvm chaos action. +Supported action: latency;return;exception;stress;gc;ruleData ++kubebuilder:validation:Enum=latency;return;exception;stress;gc;ruleData;mysql */ + action?: string + /** +optional +Java class */ + class?: string + /** ContainerNames indicates list of the name of affected container. +If not set, the first container will be injected ++optional */ + containerNames?: string[] + /** +optional +the CPU core number needs to use, only set it when action is stress */ + cpuCount?: number + /** the match database +default value is "", means match all database */ + database?: string + /** Duration represents the duration of the chaos action ++optional */ + duration?: string + /** +optional +the exception which needs to throw for action `exception` +or the exception message needs to throw in action `mysql` */ + exception?: string + /** +optional +the latency duration for action 'latency', unit ms +or the latency duration in action `mysql` */ + latency?: number + /** +optional +the memory type needs to locate, only set it when action is stress, the value can be 'stack' or 'heap' */ + memType?: string + /** +optional +the method in Java class */ + method?: string + /** Mode defines the mode to run chaos action. +Supported mode: one / all / fixed / fixed-percent / random-max-percent ++kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent */ + mode?: string + /** the version of mysql-connector-java, only support 5.X.X(set to "5") and 8.X.X(set to "8") now */ + mysqlConnectorVersion?: string + /** +optional +byteman rule name, should be unique, and will generate one if not set */ + name?: string + /** the pid of Java process which needs to attach */ + pid?: number + /** +optional +the port of agent server, default 9277 */ + port?: number + /** RemoteCluster represents the remote cluster where the chaos will be deployed ++optional */ + remoteCluster?: string + /** +optional +the byteman rule's data for action 'ruleData' */ + ruleData?: string + selector?: V1alpha1PodSelectorSpec + /** the match sql type +default value is "", means match all SQL type. +The value can be 'select', 'insert', 'update', 'delete', 'replace'. */ + sqlType?: string + /** the match table +default value is "", means match all table */ + table?: string + /** +optional +the return value for action 'return' */ + value?: string +} + +export interface V1alpha1IOChaosSpec { + /** Action defines the specific pod chaos action. +Supported action: latency / fault / attrOverride / mistake ++kubebuilder:validation:Enum=latency;fault;attrOverride;mistake */ + action?: string + /** Attr defines the overrided attribution ++ui:form:when=action=='attrOverride' ++optional */ + attr?: V1alpha1AttrOverrideSpec + /** ContainerNames indicates list of the name of affected container. +If not set, the first container will be injected ++optional */ + containerNames?: string[] + /** Delay defines the value of I/O chaos action delay. +A delay string is a possibly signed sequence of +decimal numbers, each with optional fraction and a unit suffix, +such as "300ms". +Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". ++ui:form:when=action=='latency' ++optional */ + delay?: string + /** Duration represents the duration of the chaos action. +It is required when the action is `PodFailureAction`. +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". ++optional */ + duration?: string + /** Errno defines the error code that returned by I/O action. +refer to: https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html ++ui:form:when=action=='fault' ++optional */ + errno?: number + /** Methods defines the I/O methods for injecting I/O chaos action. +default: all I/O methods. ++optional */ + methods?: string[] + /** Mistake defines what types of incorrectness are injected to IO operations ++ui:form:when=action=='mistake' ++optional */ + mistake?: V1alpha1MistakeSpec + /** Mode defines the mode to run chaos action. +Supported mode: one / all / fixed / fixed-percent / random-max-percent ++kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent */ + mode?: string + /** Path defines the path of files for injecting I/O chaos action. ++optional */ + path?: string + /** Percent defines the percentage of injection errors and provides a number from 0-100. +default: 100. ++optional ++kubebuilder:default=100 */ + percent?: number + /** RemoteCluster represents the remote cluster where the chaos will be deployed ++optional */ + remoteCluster?: string + selector?: V1alpha1PodSelectorSpec + /** Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. +If `FixedMode`, provide an integer of pods to do chaos action. +If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. +IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action ++optional */ + value?: string + /** VolumePath represents the mount path of injected volume */ + volumePath?: string +} + +export interface V1alpha1HTTPStatusCheck { + /** +optional */ + body?: string + criteria?: V1alpha1HTTPCriteria + headers?: HttpHeader + /** +optional ++kubebuilder:validation:Enum=GET;POST ++kubebuilder:default=GET */ + method?: string + url?: string +} + +export interface V1alpha1HTTPRequestSpec { + /** The number of requests to send */ + count?: number + /** Enable connection pool */ + 'enable-conn-pool'?: boolean + /** Request to send" */ + url?: string +} + +export interface V1alpha1HTTPDelaySpec { + /** Code is a rule to select target by http status code in response */ + code?: string + /** Delay represents the delay of the target request/response */ + delay?: string + /** HTTP method */ + method?: string + /** Match path of Uri with wildcard matches */ + path?: string + /** The TCP port that the target service listens on */ + port?: number + /** Composed with one of the port of HTTP connection, we will only attack HTTP connection with port inside proxy_ports */ + proxy_ports?: number[] + /** HTTP target: Request or Response */ + target?: string +} + +export interface V1alpha1HTTPCriteria { + /** StatusCode defines the expected http status code for the request. +A statusCode string could be a single code (e.g. 200), or +an inclusive range (e.g. 200-400, both `200` and `400` are included). */ + statusCode?: string +} + +export interface V1alpha1HTTPConfigSpec { + /** The config file path */ + file_path?: string +} + +/** + * ResponseHeaders is a rule to select target by http headers in response. +The key-value pairs represent header name and header value pairs. ++optional + */ +export type V1alpha1HTTPChaosSpecResponseHeaders = { [key: string]: string } + +/** + * RequestHeaders is a rule to select target by http headers in request. +The key-value pairs represent header name and header value pairs. ++optional + */ +export type V1alpha1HTTPChaosSpecRequestHeaders = { [key: string]: string } + +export interface V1alpha1HTTPChaosSpec { + /** Abort is a rule to abort a http session. ++optional */ + abort?: boolean + /** Code is a rule to select target by http status code in response. ++optional */ + code?: number + /** Delay represents the delay of the target request/response. +A duration string is a possibly unsigned sequence of +decimal numbers, each with optional fraction and a unit suffix, +such as "300ms", "2h45m". +Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". ++optional */ + delay?: string + /** Duration represents the duration of the chaos action. ++optional */ + duration?: string + /** Method is a rule to select target by http method in request. ++optional */ + method?: string + /** Mode defines the mode to run chaos action. +Supported mode: one / all / fixed / fixed-percent / random-max-percent ++kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent */ + mode?: string + /** Patch is a rule to patch some contents in target. ++optional */ + patch?: V1alpha1PodHttpChaosPatchActions + /** Path is a rule to select target by uri path in http request. ++optional */ + path?: string + /** Port represents the target port to be proxy of. */ + port?: number + /** RemoteCluster represents the remote cluster where the chaos will be deployed ++optional */ + remoteCluster?: string + /** Replace is a rule to replace some contents in target. ++optional */ + replace?: V1alpha1PodHttpChaosReplaceActions + /** RequestHeaders is a rule to select target by http headers in request. +The key-value pairs represent header name and header value pairs. ++optional */ + request_headers?: V1alpha1HTTPChaosSpecRequestHeaders + /** ResponseHeaders is a rule to select target by http headers in response. +The key-value pairs represent header name and header value pairs. ++optional */ + response_headers?: V1alpha1HTTPChaosSpecResponseHeaders + selector?: V1alpha1PodSelectorSpec + /** Target is the object to be selected and injected. ++kubebuilder:validation:Enum=Request;Response */ + target?: string + tls?: V1alpha1PodHttpChaosTLS + /** Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. +If `FixedMode`, provide an integer of pods to do chaos action. +If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. +IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action ++optional */ + value?: string +} + +export interface V1alpha1HTTPAbortSpec { + /** Code is a rule to select target by http status code in response */ + code?: string + /** HTTP method */ + method?: string + /** Match path of Uri with wildcard matches */ + path?: string + /** The TCP port that the target service listens on */ + port?: number + /** Composed with one of the port of HTTP connection, we will only attack HTTP connection with port inside proxy_ports */ + proxy_ports?: number[] + /** HTTP target: Request or Response */ + target?: string +} + +export interface V1alpha1GCPChaosSpec { + /** Action defines the specific gcp chaos action. +Supported action: node-stop / node-reset / disk-loss +Default action: node-stop ++kubebuilder:validation:Enum=node-stop;node-reset;disk-loss */ + action?: string + /** The device name of disks to detach. +Needed in disk-loss. ++ui:form:when=action=='disk-loss' ++optional */ + deviceNames?: string[] + /** Duration represents the duration of the chaos action. ++optional */ + duration?: string + /** Instance defines the name of the instance */ + instance?: string + /** Project defines the ID of gcp project. */ + project?: string + /** RemoteCluster represents the remote cluster where the chaos will be deployed ++optional */ + remoteCluster?: string + /** SecretName defines the name of kubernetes secret. It is used for GCP credentials. ++optional */ + secretName?: string + /** Zone defines the zone of gcp project. */ + zone?: string +} + +export interface V1alpha1Frame { + /** Funcname can be find from kernel source or `/proc/kallsyms`, such as `ext4_mount` */ + funcname?: string + /** Parameters is used with predicate, for example, if you want to inject slab error +in `d_alloc_parallel(struct dentry *parent, const struct qstr *name)` with a special +name `bananas`, you need to set it to `struct dentry *parent, const struct qstr *name` +otherwise omit it. */ + parameters?: string + /** Predicate will access the arguments of this Frame, example with Parameters's, you can +set it to `STRNCMP(name->name, "bananas", 8)` to make inject only with it, or omit it +to inject for all d_alloc_parallel call chain. */ + predicate?: string +} + +export interface V1alpha1FileReplaceSpec { + /** DestStr is the destination string of the file. */ + 'dest-string'?: string + /** FileName is the name of the file to be created, modified, deleted, renamed, or appended. */ + 'file-name'?: string + /** Line is the line number of the file to be replaced. */ + line?: number + /** OriginStr is the origin string of the file. */ + 'origin-string'?: string +} + +export interface V1alpha1FileRenameSpec { + /** DestFile is the name to be renamed. */ + 'dest-file'?: string + /** SourceFile is the name need to be renamed. */ + 'source-file'?: string +} + +export interface V1alpha1FileModifyPrivilegeSpec { + /** FileName is the name of the file to be created, modified, deleted, renamed, or appended. */ + 'file-name'?: string + /** Privilege is the file privilege to be set. */ + privilege?: number +} + +export interface V1alpha1FileDeleteSpec { + /** DirName is the directory name to create or delete. */ + 'dir-name'?: string + /** FileName is the name of the file to be created, modified, deleted, renamed, or appended. */ + 'file-name'?: string +} + +export interface V1alpha1FileCreateSpec { + /** DirName is the directory name to create or delete. */ + 'dir-name'?: string + /** FileName is the name of the file to be created, modified, deleted, renamed, or appended. */ + 'file-name'?: string +} + +export interface V1alpha1FileAppendSpec { + /** Count is the number of times to append the data. */ + count?: number + /** Data is the data for append. */ + data?: string + /** FileName is the name of the file to be created, modified, deleted, renamed, or appended. */ + 'file-name'?: string +} + +export interface V1alpha1FailKernRequest { + /** Callchain indicate a special call chain, such as: + ext4_mount + -> mount_subtree + -> ... + -> should_failslab +With an optional set of predicates and an optional set of +parameters, which used with predicates. You can read call chan +and predicate examples from https://github.com/chaos-mesh/bpfki/tree/develop/examples +to learn more. +If no special call chain, just keep Callchain empty, which means it will fail at any call chain +with slab alloc (eg: kmalloc). */ + callchain?: V1alpha1Frame[] + /** FailType indicates what to fail, can be set to '0' / '1' / '2' +If `0`, indicates slab to fail (should_failslab) +If `1`, indicates alloc_page to fail (should_fail_alloc_page) +If `2`, indicates bio to fail (should_fail_bio) +You can read: + 1. https://www.kernel.org/doc/html/latest/fault-injection/fault-injection.html + 2. http://github.com/iovisor/bcc/blob/master/tools/inject_example.txt +to learn more ++kubebuilder:validation:Maximum=2 ++kubebuilder:validation:Minimum=0 */ + failtype?: number + /** Headers indicates the appropriate kernel headers you need. +Eg: "linux/mmzone.h", "linux/blkdev.h" and so on */ + headers?: string[] + /** Probability indicates the fails with probability. +If you want 1%, please set this field with 1. ++kubebuilder:validation:Minimum=0 ++kubebuilder:validation:Maximum=100 */ + probability?: number + /** Times indicates the max times of fails. ++kubebuilder:validation:Minimum=0 */ + times?: number +} + +export interface V1alpha1DuplicateSpec { + /** +optional */ + correlation?: string + duplicate?: string +} + +export interface V1alpha1DiskPayloadSpec { + /** specifies the location to fill data in. if path not provided, +payload will read/write from/into a temp file, temp file will be deleted after writing */ + path?: string + /** specifies the number of process work on writing, default 1, only 1-255 is valid value */ + 'payload-process-num'?: number + /** specifies how many units of data will write into the file path. support unit: c=1, w=2, b=512, kB=1000, +K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 BYTES. example : 1M | 512kB */ + size?: string +} + +export interface V1alpha1DiskFillSpec { + /** fill disk by fallocate */ + 'fill-by-fallocate'?: boolean + /** specifies the location to fill data in. if path not provided, +payload will read/write from/into a temp file, temp file will be deleted after writing */ + path?: string + /** specifies how many units of data will write into the file path. support unit: c=1, w=2, b=512, kB=1000, +K=1024, MB=1000*1000, M=1024*1024, GB=1000*1000*1000, G=1024*1024*1024 BYTES. example : 1M | 512kB */ + size?: string +} + +export interface V1alpha1DelaySpec { + /** +optional */ + correlation?: string + /** +optional */ + jitter?: string + latency?: string + reorder?: V1alpha1ReorderSpec +} + +export interface V1alpha1DNSChaosSpec { + /** Action defines the specific DNS chaos action. +Supported action: error, random +Default action: error ++kubebuilder:validation:Enum=error;random */ + action?: string + /** ContainerNames indicates list of the name of affected container. +If not set, the first container will be injected ++optional */ + containerNames?: string[] + /** Duration represents the duration of the chaos action */ + duration?: string + /** Mode defines the mode to run chaos action. +Supported mode: one / all / fixed / fixed-percent / random-max-percent ++kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent */ + mode?: string + /** Choose which domain names to take effect, support the placeholder ? and wildcard *, or the Specified domain name. +Note: + 1. The wildcard * must be at the end of the string. For example, chaos-*.org is invalid. + 2. if the patterns is empty, will take effect on all the domain names. +For example: + The value is ["google.com", "github.*", "chaos-mes?.org"], + will take effect on "google.com", "github.com" and "chaos-mesh.org" ++optional */ + patterns?: string[] + /** RemoteCluster represents the remote cluster where the chaos will be deployed ++optional */ + remoteCluster?: string + selector?: V1alpha1PodSelectorSpec + /** Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. +If `FixedMode`, provide an integer of pods to do chaos action. +If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. +IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action ++optional */ + value?: string +} + +export interface V1alpha1CorruptSpec { + /** +optional */ + correlation?: string + corrupt?: string +} + +export interface V1alpha1ConditionalBranch { + /** Expression is the expression for this conditional branch, expected type of result is boolean. If expression is empty, this branch will always be selected/the template will be spawned. ++optional */ + expression?: string + /** Target is the name of other template, if expression is evaluated as true, this template will be spawned. */ + target?: string +} + +export interface V1alpha1ClockSpec { + /** the identifier of the particular clock on which to act. +More clock description in linux kernel can be found in man page of clock_getres, clock_gettime, clock_settime. +Muti clock ids should be split with "," */ + 'clock-ids-slice'?: string + /** the pid of target program. */ + pid?: number + /** specifies the length of time offset. */ + 'time-offset'?: string +} + +export interface V1alpha1ChaosOnlyScheduleSpec { + awsChaos?: V1alpha1AWSChaosSpec + azureChaos?: V1alpha1AzureChaosSpec + blockChaos?: V1alpha1BlockChaosSpec + /** +optional ++kubebuilder:validation:Enum=Forbid;Allow */ + concurrencyPolicy?: string + dnsChaos?: V1alpha1DNSChaosSpec + gcpChaos?: V1alpha1GCPChaosSpec + /** +optional ++kubebuilder:validation:Minimum=1 */ + historyLimit?: number + httpChaos?: V1alpha1HTTPChaosSpec + ioChaos?: V1alpha1IOChaosSpec + jvmChaos?: V1alpha1JVMChaosSpec + kernelChaos?: V1alpha1KernelChaosSpec + networkChaos?: V1alpha1NetworkChaosSpec + physicalmachineChaos?: V1alpha1PhysicalMachineChaosSpec + podChaos?: V1alpha1PodChaosSpec + schedule?: string + /** +optional ++nullable ++kubebuilder:validation:Minimum=0 */ + startingDeadlineSeconds?: number + stressChaos?: V1alpha1StressChaosSpec + timeChaos?: V1alpha1TimeChaosSpec + /** TODO: use a custom type, as `TemplateType` contains other possible values */ + type?: string +} + +export interface V1alpha1CPUStressor { + /** Load specifies P percent loading per CPU worker. 0 is effectively a sleep (no load) and 100 +is full loading. ++kubebuilder:validation:Minimum=0 ++kubebuilder:validation:Maximum=100 ++optional */ + load?: number + /** extend stress-ng options ++optional */ + options?: string[] + /** Workers specifies N workers to apply the stressor. +Maximum 8192 workers can run by stress-ng ++kubebuilder:validation:Maximum=8192 */ + workers?: number +} + +export interface V1alpha1BlockDelaySpec { + /** +optional */ + correlation?: string + /** +optional */ + jitter?: string + /** Latency defines the latency of every io request. */ + latency?: string +} + +export interface V1alpha1BlockChaosSpec { + /** Action defines the specific block chaos action. +Supported action: delay ++kubebuilder:validation:Enum=delay */ + action?: string + /** ContainerNames indicates list of the name of affected container. +If not set, the first container will be injected ++optional */ + containerNames?: string[] + delay?: V1alpha1BlockDelaySpec + /** Duration represents the duration of the chaos action. ++optional */ + duration?: string + /** Mode defines the mode to run chaos action. +Supported mode: one / all / fixed / fixed-percent / random-max-percent ++kubebuilder:validation:Enum=one;all;fixed;fixed-percent;random-max-percent */ + mode?: string + /** RemoteCluster represents the remote cluster where the chaos will be deployed ++optional */ + remoteCluster?: string + selector?: V1alpha1PodSelectorSpec + /** Value is required when the mode is set to `FixedMode` / `FixedPercentMode` / `RandomMaxPercentMode`. +If `FixedMode`, provide an integer of pods to do chaos action. +If `FixedPercentMode`, provide a number from 0-100 to specify the percent of pods the server can do chaos action. +IF `RandomMaxPercentMode`, provide a number from 0-100 to specify the max percent of pods to do chaos action ++optional */ + value?: string + volumeName?: string +} + +export interface V1alpha1BandwidthSpec { + /** Buffer is the maximum amount of bytes that tokens can be available for instantaneously. ++kubebuilder:validation:Minimum=1 */ + buffer?: number + /** Limit is the number of bytes that can be queued waiting for tokens to become available. ++kubebuilder:validation:Minimum=1 */ + limit?: number + /** Minburst specifies the size of the peakrate bucket. For perfect +accuracy, should be set to the MTU of the interface. If a +peakrate is needed, but some burstiness is acceptable, this +size can be raised. A 3000 byte minburst allows around 3mbit/s +of peakrate, given 1000 byte packets. ++optional ++kubebuilder:validation:Minimum=0 */ + minburst?: number + /** Peakrate is the maximum depletion rate of the bucket. +The peakrate does not need to be set, it is only necessary +if perfect millisecond timescale shaping is required. ++optional ++kubebuilder:validation:Minimum=0 */ + peakrate?: number + /** Rate is the speed knob. Allows bps, kbps, mbps, gbps, tbps unit. bps means bytes per second. */ + rate?: string +} + +export interface V1alpha1AzureChaosSpec { + /** Action defines the specific azure chaos action. +Supported action: vm-stop / vm-restart / disk-detach +Default action: vm-stop ++kubebuilder:validation:Enum=vm-stop;vm-restart;disk-detach */ + action?: string + /** DiskName indicates the name of the disk. +Needed in disk-detach. ++optional */ + diskName?: string + /** Duration represents the duration of the chaos action. ++optional */ + duration?: string + /** LUN indicates the Logical Unit Number of the data disk. +Needed in disk-detach. ++optional */ + lun?: number + /** RemoteCluster represents the remote cluster where the chaos will be deployed ++optional */ + remoteCluster?: string + /** ResourceGroupName defines the name of ResourceGroup */ + resourceGroupName?: string + /** SecretName defines the name of kubernetes secret. It is used for Azure credentials. ++optional */ + secretName?: string + /** SubscriptionID defines the id of Azure subscription. */ + subscriptionID?: string + /** VMName defines the name of Virtual Machine */ + vmName?: string +} + +export interface V1alpha1AttrOverrideSpec { + atime?: V1alpha1Timespec + /** +optional */ + blocks?: number + ctime?: V1alpha1Timespec + /** +optional */ + gid?: number + /** +optional */ + ino?: number + /** +optional */ + kind?: string + mtime?: V1alpha1Timespec + /** +optional */ + nlink?: number + /** +optional */ + perm?: number + /** +optional */ + rdev?: number + /** +optional */ + size?: number + /** +optional */ + uid?: number +} + +export interface V1alpha1AWSChaosSpec { + /** Action defines the specific aws chaos action. +Supported action: ec2-stop / ec2-restart / detach-volume +Default action: ec2-stop ++kubebuilder:validation:Enum=ec2-stop;ec2-restart;detach-volume */ + action?: string + /** AWSRegion defines the region of aws. */ + awsRegion?: string + /** DeviceName indicates the name of the device. +Needed in detach-volume. ++ui:form:when=action=='detach-volume' ++optional */ + deviceName?: string + /** Duration represents the duration of the chaos action. ++optional */ + duration?: string + /** Ec2Instance indicates the ID of the ec2 instance. */ + ec2Instance?: string + /** Endpoint indicates the endpoint of the aws server. Just used it in test now. ++ui:form:ignore ++optional */ + endpoint?: string + /** RemoteCluster represents the remote cluster where the chaos will be deployed ++optional */ + remoteCluster?: string + /** SecretName defines the name of kubernetes secret. ++optional */ + secretName?: string + /** EbsVolume indicates the ID of the EBS volume. +Needed in detach-volume. ++ui:form:when=action=='detach-volume' ++optional */ + volumeID?: string +} + +export interface V1WindowsSecurityContextOptions { + /** GMSACredentialSpec is where the GMSA admission webhook +(https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the +GMSA credential spec named by the GMSACredentialSpecName field. ++optional */ + gmsaCredentialSpec?: string + /** GMSACredentialSpecName is the name of the GMSA credential spec to use. ++optional */ + gmsaCredentialSpecName?: string + /** HostProcess determines if a container should be run as a 'Host Process' container. +This field is alpha-level and will only be honored by components that enable the +WindowsHostProcessContainers feature flag. Setting this field without the feature +flag will result in errors when validating the Pod. All of a Pod's containers must +have the same effective HostProcess value (it is not allowed to have a mix of HostProcess +containers and non-HostProcess containers). In addition, if HostProcess is true +then HostNetwork must also be set to true. ++optional */ + hostProcess?: boolean + /** The UserName in Windows to run the entrypoint of the container process. +Defaults to the user specified in image metadata if unspecified. +May also be set in PodSecurityContext. If set in both SecurityContext and +PodSecurityContext, the value specified in SecurityContext takes precedence. ++optional */ + runAsUserName?: string +} + +export interface V1VsphereVirtualDiskVolumeSource { + /** fsType is filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. ++optional */ + fsType?: string + /** storagePolicyID is the storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName. ++optional */ + storagePolicyID?: string + /** storagePolicyName is the storage Policy Based Management (SPBM) profile name. ++optional */ + storagePolicyName?: string + /** volumePath is the path that identifies vSphere volume vmdk */ + volumePath?: string +} + +export interface V1VolumeProjection { + configMap?: V1ConfigMapProjection + downwardAPI?: V1DownwardAPIProjection + secret?: V1SecretProjection + serviceAccountToken?: V1ServiceAccountTokenProjection +} + +export interface V1VolumeMount { + /** Path within the container at which the volume should be mounted. Must +not contain ':'. */ + mountPath?: string + /** mountPropagation determines how mounts are propagated from the host +to container and the other way around. +When not set, MountPropagationNone is used. +This field is beta in 1.10. ++optional */ + mountPropagation?: string + /** This must match the Name of a Volume. */ + name?: string + /** Mounted read-only if true, read-write otherwise (false or unspecified). +Defaults to false. ++optional */ + readOnly?: boolean + /** Path within the volume from which the container's volume should be mounted. +Defaults to "" (volume's root). ++optional */ + subPath?: string + /** Expanded path within the volume from which the container's volume should be mounted. +Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. +Defaults to "" (volume's root). +SubPathExpr and SubPath are mutually exclusive. ++optional */ + subPathExpr?: string +} + +export interface V1VolumeDevice { + /** devicePath is the path inside of the container that the device will be mapped to. */ + devicePath?: string + /** name must match the name of a persistentVolumeClaim in the pod */ + name?: string +} + +export interface V1Volume { + awsElasticBlockStore?: V1AWSElasticBlockStoreVolumeSource + azureDisk?: V1AzureDiskVolumeSource + azureFile?: V1AzureFileVolumeSource + cephfs?: V1CephFSVolumeSource + cinder?: V1CinderVolumeSource + configMap?: V1ConfigMapVolumeSource + csi?: V1CSIVolumeSource + downwardAPI?: V1DownwardAPIVolumeSource + emptyDir?: V1EmptyDirVolumeSource + ephemeral?: V1EphemeralVolumeSource + fc?: V1FCVolumeSource + flexVolume?: V1FlexVolumeSource + flocker?: V1FlockerVolumeSource + gcePersistentDisk?: V1GCEPersistentDiskVolumeSource + gitRepo?: V1GitRepoVolumeSource + glusterfs?: V1GlusterfsVolumeSource + hostPath?: V1HostPathVolumeSource + iscsi?: V1ISCSIVolumeSource + /** name of the volume. +Must be a DNS_LABEL and unique within the pod. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names */ + name?: string + nfs?: V1NFSVolumeSource + persistentVolumeClaim?: V1PersistentVolumeClaimVolumeSource + photonPersistentDisk?: V1PhotonPersistentDiskVolumeSource + portworxVolume?: V1PortworxVolumeSource + projected?: V1ProjectedVolumeSource + quobyte?: V1QuobyteVolumeSource + rbd?: V1RBDVolumeSource + scaleIO?: V1ScaleIOVolumeSource + secret?: V1SecretVolumeSource + storageos?: V1StorageOSVolumeSource + vsphereVolume?: V1VsphereVirtualDiskVolumeSource +} + +export interface V1TypedObjectReference { + /** APIGroup is the group for the resource being referenced. +If APIGroup is not specified, the specified Kind must be in the core API group. +For any other third-party types, APIGroup is required. ++optional */ + apiGroup?: string + /** Kind is the type of resource being referenced */ + kind?: string + /** Name is the name of resource being referenced */ + name?: string + /** Namespace is the namespace of resource being referenced +Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. +(Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. ++featureGate=CrossNamespaceVolumeDataSource ++optional */ + namespace?: string +} + +export interface V1TypedLocalObjectReference { + /** APIGroup is the group for the resource being referenced. +If APIGroup is not specified, the specified Kind must be in the core API group. +For any other third-party types, APIGroup is required. ++optional */ + apiGroup?: string + /** Kind is the type of resource being referenced */ + kind?: string + /** Name is the name of resource being referenced */ + name?: string +} + +export interface V1TCPSocketAction { + /** Optional: Host name to connect to, defaults to the pod IP. ++optional */ + host?: string + port?: IntstrIntOrString +} + +export interface V1StorageOSVolumeSource { + /** fsType is the filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. ++optional */ + fsType?: string + /** readOnly defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. ++optional */ + readOnly?: boolean + secretRef?: V1LocalObjectReference + /** volumeName is the human-readable name of the StorageOS volume. Volume +names are only unique within a namespace. */ + volumeName?: string + /** volumeNamespace specifies the scope of the volume within StorageOS. If no +namespace is specified then the Pod's namespace will be used. This allows the +Kubernetes name scoping to be mirrored within StorageOS for tighter integration. +Set VolumeName to any name to override the default behaviour. +Set to "default" if you are not using namespaces within StorageOS. +Namespaces that do not pre-exist within StorageOS will be created. ++optional */ + volumeNamespace?: string +} + +export interface V1ServiceAccountTokenProjection { + /** audience is the intended audience of the token. A recipient of a token +must identify itself with an identifier specified in the audience of the +token, and otherwise should reject the token. The audience defaults to the +identifier of the apiserver. ++optional */ + audience?: string + /** expirationSeconds is the requested duration of validity of the service +account token. As the token approaches expiration, the kubelet volume +plugin will proactively rotate the service account token. The kubelet will +start trying to rotate the token if the token is older than 80 percent of +its time to live or if the token is older than 24 hours.Defaults to 1 hour +and must be at least 10 minutes. ++optional */ + expirationSeconds?: number + /** path is the path relative to the mount point of the file to project the +token into. */ + path?: string +} + +export interface V1SecurityContext { + /** AllowPrivilegeEscalation controls whether a process can gain more +privileges than its parent process. This bool directly controls if +the no_new_privs flag will be set on the container process. +AllowPrivilegeEscalation is true always when the container is: +1) run as Privileged +2) has CAP_SYS_ADMIN +Note that this field cannot be set when spec.os.name is windows. ++optional */ + allowPrivilegeEscalation?: boolean + capabilities?: V1Capabilities + /** Run container in privileged mode. +Processes in privileged containers are essentially equivalent to root on the host. +Defaults to false. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + privileged?: boolean + /** procMount denotes the type of proc mount to use for the containers. +The default is DefaultProcMount which uses the container runtime defaults for +readonly paths and masked paths. +This requires the ProcMountType feature flag to be enabled. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + procMount?: string + /** Whether this container has a read-only root filesystem. +Default is false. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + readOnlyRootFilesystem?: boolean + /** The GID to run the entrypoint of the container process. +Uses runtime default if unset. +May also be set in PodSecurityContext. If set in both SecurityContext and +PodSecurityContext, the value specified in SecurityContext takes precedence. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + runAsGroup?: number + /** Indicates that the container must run as a non-root user. +If true, the Kubelet will validate the image at runtime to ensure that it +does not run as UID 0 (root) and fail to start the container if it does. +If unset or false, no such validation will be performed. +May also be set in PodSecurityContext. If set in both SecurityContext and +PodSecurityContext, the value specified in SecurityContext takes precedence. ++optional */ + runAsNonRoot?: boolean + /** The UID to run the entrypoint of the container process. +Defaults to user specified in image metadata if unspecified. +May also be set in PodSecurityContext. If set in both SecurityContext and +PodSecurityContext, the value specified in SecurityContext takes precedence. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + runAsUser?: number + seLinuxOptions?: V1SELinuxOptions + seccompProfile?: V1SeccompProfile + windowsOptions?: V1WindowsSecurityContextOptions +} + +export interface V1SecretVolumeSource { + /** defaultMode is Optional: mode bits used to set permissions on created files by default. +Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. +YAML accepts both octal and decimal values, JSON requires decimal values +for mode bits. Defaults to 0644. +Directories within the path are not affected by this setting. +This might be in conflict with other options that affect the file +mode, like fsGroup, and the result can be other mode bits set. ++optional */ + defaultMode?: number + /** items If unspecified, each key-value pair in the Data field of the referenced +Secret will be projected into the volume as a file whose name is the +key and content is the value. If specified, the listed keys will be +projected into the specified paths, and unlisted keys will not be +present. If a key is specified which is not present in the Secret, +the volume setup will error unless it is marked optional. Paths must be +relative and may not contain the '..' path or start with '..'. ++optional */ + items?: V1KeyToPath[] + /** optional field specify whether the Secret or its keys must be defined ++optional */ + optional?: boolean + /** secretName is the name of the secret in the pod's namespace to use. +More info: https://kubernetes.io/docs/concepts/storage/volumes#secret ++optional */ + secretName?: string +} + +export interface V1SecretProjection { + /** items if unspecified, each key-value pair in the Data field of the referenced +Secret will be projected into the volume as a file whose name is the +key and content is the value. If specified, the listed keys will be +projected into the specified paths, and unlisted keys will not be +present. If a key is specified which is not present in the Secret, +the volume setup will error unless it is marked optional. Paths must be +relative and may not contain the '..' path or start with '..'. ++optional */ + items?: V1KeyToPath[] + /** Name of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names +TODO: Add other useful fields. apiVersion, kind, uid? ++optional */ + name?: string + /** optional field specify whether the Secret or its key must be defined ++optional */ + optional?: boolean +} + +export interface V1SecretKeySelector { + /** The key of the secret to select from. Must be a valid secret key. */ + key?: string + /** Name of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names +TODO: Add other useful fields. apiVersion, kind, uid? ++optional */ + name?: string + /** Specify whether the Secret or its key must be defined ++optional */ + optional?: boolean +} + +export interface V1SecretEnvSource { + /** Name of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names +TODO: Add other useful fields. apiVersion, kind, uid? ++optional */ + name?: string + /** Specify whether the Secret must be defined ++optional */ + optional?: boolean +} + +export interface V1SeccompProfile { + /** localhostProfile indicates a profile defined in a file on the node should be used. +The profile must be preconfigured on the node to work. +Must be a descending path, relative to the kubelet's configured seccomp profile location. +Must only be set if type is "Localhost". ++optional */ + localhostProfile?: string + /** type indicates which kind of seccomp profile will be applied. +Valid options are: + +Localhost - a profile defined in a file on the node should be used. +RuntimeDefault - the container runtime default profile should be used. +Unconfined - no profile should be applied. ++unionDiscriminator */ + type?: string +} + +export interface V1ScaleIOVolumeSource { + /** fsType is the filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs", "ntfs". +Default is "xfs". ++optional */ + fsType?: string + /** gateway is the host address of the ScaleIO API Gateway. */ + gateway?: string + /** protectionDomain is the name of the ScaleIO Protection Domain for the configured storage. ++optional */ + protectionDomain?: string + /** readOnly Defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. ++optional */ + readOnly?: boolean + secretRef?: V1LocalObjectReference + /** sslEnabled Flag enable/disable SSL communication with Gateway, default false ++optional */ + sslEnabled?: boolean + /** storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. +Default is ThinProvisioned. ++optional */ + storageMode?: string + /** storagePool is the ScaleIO Storage Pool associated with the protection domain. ++optional */ + storagePool?: string + /** system is the name of the storage system as configured in ScaleIO. */ + system?: string + /** volumeName is the name of a volume already created in the ScaleIO system +that is associated with this volume source. */ + volumeName?: string +} + +export interface V1SELinuxOptions { + /** Level is SELinux level label that applies to the container. ++optional */ + level?: string + /** Role is a SELinux role label that applies to the container. ++optional */ + role?: string + /** Type is a SELinux type label that applies to the container. ++optional */ + type?: string + /** User is a SELinux user label that applies to the container. ++optional */ + user?: string +} + +export interface V1ResourceList { + [key: string]: ResourceQuantity +} + +export interface V1ResourceRequirements { + /** Claims lists the names of resources, defined in spec.resourceClaims, +that are used by this container. + +This is an alpha field and requires enabling the +DynamicResourceAllocation feature gate. + +This field is immutable. + ++listType=map ++listMapKey=name ++featureGate=DynamicResourceAllocation ++optional */ + claims?: V1ResourceClaim[] + limits?: V1ResourceList + requests?: V1ResourceList +} + +export interface V1ResourceFieldSelector { + /** Container name: required for volumes, optional for env vars ++optional */ + containerName?: string + divisor?: ResourceQuantity + /** Required: resource to select */ + resource?: string +} + +export interface V1ResourceClaim { + /** Name must match the name of one entry in pod.spec.resourceClaims of +the Pod where this field is used. It makes that resource available +inside a container. */ + name?: string +} + +export interface V1RBDVolumeSource { + /** fsType is the filesystem type of the volume that you want to mount. +Tip: Ensure that the filesystem type is supported by the host operating system. +Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. +More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd +TODO: how do we prevent errors in the filesystem from compromising the machine ++optional */ + fsType?: string + /** image is the rados image name. +More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it */ + image?: string + /** keyring is the path to key ring for RBDUser. +Default is /etc/ceph/keyring. +More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it ++optional */ + keyring?: string + /** monitors is a collection of Ceph monitors. +More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it */ + monitors?: string[] + /** pool is the rados pool name. +Default is rbd. +More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it ++optional */ + pool?: string + /** readOnly here will force the ReadOnly setting in VolumeMounts. +Defaults to false. +More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it ++optional */ + readOnly?: boolean + secretRef?: V1LocalObjectReference + /** user is the rados user name. +Default is admin. +More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it ++optional */ + user?: string +} + +export interface V1QuobyteVolumeSource { + /** group to map volume access to +Default is no group ++optional */ + group?: string + /** readOnly here will force the Quobyte volume to be mounted with read-only permissions. +Defaults to false. ++optional */ + readOnly?: boolean + /** registry represents a single or multiple Quobyte Registry services +specified as a string as host:port pair (multiple entries are separated with commas) +which acts as the central registry for volumes */ + registry?: string + /** tenant owning the given Quobyte volume in the Backend +Used with dynamically provisioned Quobyte volumes, value is set by the plugin ++optional */ + tenant?: string + /** user to map volume access to +Defaults to serivceaccount user ++optional */ + user?: string + /** volume is a string that references an already created Quobyte volume by name. */ + volume?: string +} + +export interface V1ProjectedVolumeSource { + /** defaultMode are the mode bits used to set permissions on created files by default. +Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. +YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. +Directories within the path are not affected by this setting. +This might be in conflict with other options that affect the file +mode, like fsGroup, and the result can be other mode bits set. ++optional */ + defaultMode?: number + /** sources is the list of volume projections ++optional */ + sources?: V1VolumeProjection[] +} + +export interface V1Probe { + exec?: V1ExecAction + /** Minimum consecutive failures for the probe to be considered failed after having succeeded. +Defaults to 3. Minimum value is 1. ++optional */ + failureThreshold?: number + grpc?: V1GRPCAction + httpGet?: V1HTTPGetAction + /** Number of seconds after the container has started before liveness probes are initiated. +More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes ++optional */ + initialDelaySeconds?: number + /** How often (in seconds) to perform the probe. +Default to 10 seconds. Minimum value is 1. ++optional */ + periodSeconds?: number + /** Minimum consecutive successes for the probe to be considered successful after having failed. +Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. ++optional */ + successThreshold?: number + tcpSocket?: V1TCPSocketAction + /** Optional duration in seconds the pod needs to terminate gracefully upon probe failure. +The grace period is the duration in seconds after the processes running in the pod are sent +a termination signal and the time when the processes are forcibly halted with a kill signal. +Set this value longer than the expected cleanup time for your process. +If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this +value overrides the value provided by the pod spec. +Value must be non-negative integer. The value zero indicates stop immediately via +the kill signal (no opportunity to shut down). +This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. +Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. ++optional */ + terminationGracePeriodSeconds?: number + /** Number of seconds after which the probe times out. +Defaults to 1 second. Minimum value is 1. +More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes ++optional */ + timeoutSeconds?: number +} + +export interface V1PortworxVolumeSource { + /** fSType represents the filesystem type to mount +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. */ + fsType?: string + /** readOnly defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. ++optional */ + readOnly?: boolean + /** volumeID uniquely identifies a Portworx volume */ + volumeID?: string +} + +export interface V1PhotonPersistentDiskVolumeSource { + /** fsType is the filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. */ + fsType?: string + /** pdID is the ID that identifies Photon Controller persistent disk */ + pdID?: string +} + +export interface V1PersistentVolumeClaimVolumeSource { + /** claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. +More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims */ + claimName?: string + /** readOnly Will force the ReadOnly setting in VolumeMounts. +Default false. ++optional */ + readOnly?: boolean +} + +/** + * Map of string keys and values that can be used to organize and categorize +(scope and select) objects. May match selectors of replication controllers +and services. +More info: http://kubernetes.io/docs/user-guide/labels ++optional + */ +export type V1PersistentVolumeClaimTemplateLabels = { [key: string]: string } + +/** + * Annotations is an unstructured key value map stored with a resource that may be +set by external tools to store and retrieve arbitrary metadata. They are not +queryable and should be preserved when modifying objects. +More info: http://kubernetes.io/docs/user-guide/annotations ++optional + */ +export type V1PersistentVolumeClaimTemplateAnnotations = { [key: string]: string } + +export interface V1PersistentVolumeClaimSpec { + /** accessModes contains the desired access modes the volume should have. +More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 ++optional */ + accessModes?: string[] + dataSource?: V1TypedLocalObjectReference + dataSourceRef?: V1TypedObjectReference + resources?: V1ResourceRequirements + selector?: V1LabelSelector + /** storageClassName is the name of the StorageClass required by the claim. +More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 ++optional */ + storageClassName?: string + /** volumeMode defines what type of volume is required by the claim. +Value of Filesystem is implied when not included in claim spec. ++optional */ + volumeMode?: string + /** volumeName is the binding reference to the PersistentVolume backing this claim. ++optional */ + volumeName?: string +} + +export interface V1OwnerReference { + /** API version of the referent. */ + apiVersion?: string + /** If true, AND if the owner has the "foregroundDeletion" finalizer, then +the owner cannot be deleted from the key-value store until this +reference is removed. +See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion +for how the garbage collector interacts with this field and enforces the foreground deletion. +Defaults to false. +To set this field, a user needs "delete" permission of the owner, +otherwise 422 (Unprocessable Entity) will be returned. ++optional */ + blockOwnerDeletion?: boolean + /** If true, this reference points to the managing controller. ++optional */ + controller?: boolean + /** Kind of the referent. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string + /** Name of the referent. +More info: http://kubernetes.io/docs/user-guide/identifiers#names */ + name?: string + /** UID of the referent. +More info: http://kubernetes.io/docs/user-guide/identifiers#uids */ + uid?: string +} + +export interface V1PersistentVolumeClaimTemplate { + /** Annotations is an unstructured key value map stored with a resource that may be +set by external tools to store and retrieve arbitrary metadata. They are not +queryable and should be preserved when modifying objects. +More info: http://kubernetes.io/docs/user-guide/annotations ++optional */ + annotations?: V1PersistentVolumeClaimTemplateAnnotations + /** CreationTimestamp is a timestamp representing the server time when this object was +created. It is not guaranteed to be set in happens-before order across separate operations. +Clients may not set this value. It is represented in RFC3339 form and is in UTC. + +Populated by the system. +Read-only. +Null for lists. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata ++optional */ + creationTimestamp?: string + /** Number of seconds allowed for this object to gracefully terminate before +it will be removed from the system. Only set when deletionTimestamp is also set. +May only be shortened. +Read-only. ++optional */ + deletionGracePeriodSeconds?: number + /** DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This +field is set by the server when a graceful deletion is requested by the user, and is not +directly settable by a client. The resource is expected to be deleted (no longer visible +from resource lists, and not reachable by name) after the time in this field, once the +finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. +Once the deletionTimestamp is set, this value may not be unset or be set further into the +future, although it may be shortened or the resource may be deleted prior to this time. +For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react +by sending a graceful termination signal to the containers in the pod. After that 30 seconds, +the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, +remove the pod from the API. In the presence of network partitions, this object may still +exist after this timestamp, until an administrator or automated process can determine the +resource is fully terminated. +If not set, graceful deletion of the object has not been requested. + +Populated by the system when a graceful deletion is requested. +Read-only. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata ++optional */ + deletionTimestamp?: string + /** Must be empty before the object is deleted from the registry. Each entry +is an identifier for the responsible component that will remove the entry +from the list. If the deletionTimestamp of the object is non-nil, entries +in this list can only be removed. +Finalizers may be processed and removed in any order. Order is NOT enforced +because it introduces significant risk of stuck finalizers. +finalizers is a shared field, any actor with permission can reorder it. +If the finalizer list is processed in order, then this can lead to a situation +in which the component responsible for the first finalizer in the list is +waiting for a signal (field value, external system, or other) produced by a +component responsible for a finalizer later in the list, resulting in a deadlock. +Without enforced ordering finalizers are free to order amongst themselves and +are not vulnerable to ordering changes in the list. ++optional ++patchStrategy=merge */ + finalizers?: string[] + /** GenerateName is an optional prefix, used by the server, to generate a unique +name ONLY IF the Name field has not been provided. +If this field is used, the name returned to the client will be different +than the name passed. This value will also be combined with a unique suffix. +The provided value has the same validation rules as the Name field, +and may be truncated by the length of the suffix required to make the value +unique on the server. + +If this field is specified and the generated name exists, the server will return a 409. + +Applied only if Name is not specified. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency ++optional */ + generateName?: string + /** A sequence number representing a specific generation of the desired state. +Populated by the system. Read-only. ++optional */ + generation?: number + /** Map of string keys and values that can be used to organize and categorize +(scope and select) objects. May match selectors of replication controllers +and services. +More info: http://kubernetes.io/docs/user-guide/labels ++optional */ + labels?: V1PersistentVolumeClaimTemplateLabels + /** ManagedFields maps workflow-id and version to the set of fields +that are managed by that workflow. This is mostly for internal +housekeeping, and users typically shouldn't need to set or +understand this field. A workflow can be the user's name, a +controller's name, or the name of a specific apply path like +"ci-cd". The set of fields is always in the version that the +workflow used when modifying the object. + ++optional */ + managedFields?: V1ManagedFieldsEntry[] + /** Name must be unique within a namespace. Is required when creating resources, although +some resources may allow a client to request the generation of an appropriate name +automatically. Name is primarily intended for creation idempotence and configuration +definition. +Cannot be updated. +More info: http://kubernetes.io/docs/user-guide/identifiers#names ++optional */ + name?: string + /** Namespace defines the space within which each name must be unique. An empty namespace is +equivalent to the "default" namespace, but "default" is the canonical representation. +Not all objects are required to be scoped to a namespace - the value of this field for +those objects will be empty. + +Must be a DNS_LABEL. +Cannot be updated. +More info: http://kubernetes.io/docs/user-guide/namespaces ++optional */ + namespace?: string + /** List of objects depended by this object. If ALL objects in the list have +been deleted, this object will be garbage collected. If this object is managed by a controller, +then an entry in this list will point to this controller, with the controller field set to true. +There cannot be more than one managing controller. ++optional ++patchMergeKey=uid ++patchStrategy=merge */ + ownerReferences?: V1OwnerReference[] + /** An opaque value that represents the internal version of this object that can +be used by clients to determine when objects have changed. May be used for optimistic +concurrency, change detection, and the watch operation on a resource or set of resources. +Clients must treat these values as opaque and passed unmodified back to the server. +They may only be valid for a particular resource or set of resources. + +Populated by the system. +Read-only. +Value must be treated as opaque by clients and . +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency ++optional */ + resourceVersion?: string + /** Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. ++optional */ + selfLink?: string + spec?: V1PersistentVolumeClaimSpec + /** UID is the unique in time and space value for this object. It is typically generated by +the server on successful creation of a resource and is not allowed to change on PUT +operations. + +Populated by the system. +Read-only. +More info: http://kubernetes.io/docs/user-guide/identifiers#uids ++optional */ + uid?: string +} + +export interface V1ObjectReference { + /** API version of the referent. ++optional */ + apiVersion?: string + /** If referring to a piece of an object instead of an entire object, this string +should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. +For example, if the object reference is to a container within a pod, this would take on a value like: +"spec.containers{name}" (where "name" refers to the name of the container that triggered +the event) or if no container name is specified "spec.containers[2]" (container with +index 2 in this pod). This syntax is chosen only to have some well-defined way of +referencing a part of an object. +TODO: this design is not final and this field is subject to change in the future. ++optional */ + fieldPath?: string + /** Kind of the referent. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds ++optional */ + kind?: string + /** Name of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names ++optional */ + name?: string + /** Namespace of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ ++optional */ + namespace?: string + /** Specific resourceVersion to which this reference is made, if any. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency ++optional */ + resourceVersion?: string + /** UID of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids ++optional */ + uid?: string +} + +export interface V1ObjectFieldSelector { + /** Version of the schema the FieldPath is written in terms of, defaults to "v1". ++optional */ + apiVersion?: string + /** Path of the field to select in the specified API version. */ + fieldPath?: string +} + +export interface V1NFSVolumeSource { + /** path that is exported by the NFS server. +More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs */ + path?: string + /** readOnly here will force the NFS export to be mounted with read-only permissions. +Defaults to false. +More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs ++optional */ + readOnly?: boolean + /** server is the hostname or IP address of the NFS server. +More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs */ + server?: string +} + +export interface V1ManagedFieldsEntry { + /** APIVersion defines the version of this resource that this field set +applies to. The format is "group/version" just like the top-level +APIVersion field. It is necessary to track the version of a field +set because it cannot be automatically converted. */ + apiVersion?: string + /** FieldsType is the discriminator for the different fields format and version. +There is currently only one possible value: "FieldsV1" */ + fieldsType?: string + fieldsV1?: V1FieldsV1 + /** Manager is an identifier of the workflow managing these fields. */ + manager?: string + /** Operation is the type of operation which lead to this ManagedFieldsEntry being created. +The only valid values for this field are 'Apply' and 'Update'. */ + operation?: string + /** Subresource is the name of the subresource used to update that object, or +empty string if the object was updated through the main resource. The +value of this field is used to distinguish between managers, even if they +share the same name. For example, a status update will be distinct from a +regular update using the same manager name. +Note that the APIVersion field is not related to the Subresource field and +it always corresponds to the version of the main resource. */ + subresource?: string + /** Time is the timestamp of when the ManagedFields entry was added. The +timestamp will also be updated if a field is added, the manager +changes any of the owned fields value or removes a field. The +timestamp does not update when a field is removed from the entry +because another manager took it over. ++optional */ + time?: string +} + +export interface V1LocalObjectReference { + /** Name of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names +TODO: Add other useful fields. apiVersion, kind, uid? ++optional */ + name?: string +} + +export interface V1LifecycleHandler { + exec?: V1ExecAction + httpGet?: V1HTTPGetAction + tcpSocket?: V1TCPSocketAction +} + +export interface V1Lifecycle { + postStart?: V1LifecycleHandler + preStop?: V1LifecycleHandler +} + +export interface V1LabelSelectorRequirement { + /** key is the label key that the selector applies to. ++patchMergeKey=key ++patchStrategy=merge */ + key?: string + /** operator represents a key's relationship to a set of values. +Valid operators are In, NotIn, Exists and DoesNotExist. */ + operator?: string + /** values is an array of string values. If the operator is In or NotIn, +the values array must be non-empty. If the operator is Exists or DoesNotExist, +the values array must be empty. This array is replaced during a strategic +merge patch. ++optional */ + values?: string[] +} + +/** + * matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels +map is equivalent to an element of matchExpressions, whose key field is "key", the +operator is "In", and the values array contains only "value". The requirements are ANDed. ++optional + */ +export type V1LabelSelectorMatchLabels = { [key: string]: string } + +export interface V1LabelSelector { + /** matchExpressions is a list of label selector requirements. The requirements are ANDed. ++optional */ + matchExpressions?: V1LabelSelectorRequirement[] + /** matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels +map is equivalent to an element of matchExpressions, whose key field is "key", the +operator is "In", and the values array contains only "value". The requirements are ANDed. ++optional */ + matchLabels?: V1LabelSelectorMatchLabels +} + +export interface V1KeyToPath { + /** key is the key to project. */ + key?: string + /** mode is Optional: mode bits used to set permissions on this file. +Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. +YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. +If not specified, the volume defaultMode will be used. +This might be in conflict with other options that affect the file +mode, like fsGroup, and the result can be other mode bits set. ++optional */ + mode?: number + /** path is the relative path of the file to map the key to. +May not be an absolute path. +May not contain the path element '..'. +May not start with the string '..'. */ + path?: string +} + +export interface V1ISCSIVolumeSource { + /** chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication ++optional */ + chapAuthDiscovery?: boolean + /** chapAuthSession defines whether support iSCSI Session CHAP authentication ++optional */ + chapAuthSession?: boolean + /** fsType is the filesystem type of the volume that you want to mount. +Tip: Ensure that the filesystem type is supported by the host operating system. +Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. +More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi +TODO: how do we prevent errors in the filesystem from compromising the machine ++optional */ + fsType?: string + /** initiatorName is the custom iSCSI Initiator Name. +If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface +: will be created for the connection. ++optional */ + initiatorName?: string + /** iqn is the target iSCSI Qualified Name. */ + iqn?: string + /** iscsiInterface is the interface Name that uses an iSCSI transport. +Defaults to 'default' (tcp). ++optional */ + iscsiInterface?: string + /** lun represents iSCSI Target Lun number. */ + lun?: number + /** portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port +is other than default (typically TCP ports 860 and 3260). ++optional */ + portals?: string[] + /** readOnly here will force the ReadOnly setting in VolumeMounts. +Defaults to false. ++optional */ + readOnly?: boolean + secretRef?: V1LocalObjectReference + /** targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port +is other than default (typically TCP ports 860 and 3260). */ + targetPortal?: string +} + +export interface V1HostPathVolumeSource { + /** path of the directory on the host. +If the path is a symlink, it will follow the link to the real path. +More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath */ + path?: string + /** type for HostPath Volume +Defaults to "" +More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath ++optional */ + type?: string +} + +export interface V1HTTPHeader { + /** The header field name */ + name?: string + /** The header field value */ + value?: string +} + +export interface V1HTTPGetAction { + /** Host name to connect to, defaults to the pod IP. You probably want to set +"Host" in httpHeaders instead. ++optional */ + host?: string + /** Custom headers to set in the request. HTTP allows repeated headers. ++optional */ + httpHeaders?: V1HTTPHeader[] + /** Path to access on the HTTP server. ++optional */ + path?: string + port?: IntstrIntOrString + /** Scheme to use for connecting to the host. +Defaults to HTTP. ++optional */ + scheme?: string +} + +export interface V1GlusterfsVolumeSource { + /** endpoints is the endpoint name that details Glusterfs topology. +More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod */ + endpoints?: string + /** path is the Glusterfs volume path. +More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod */ + path?: string + /** readOnly here will force the Glusterfs volume to be mounted with read-only permissions. +Defaults to false. +More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod ++optional */ + readOnly?: boolean +} + +export interface V1GitRepoVolumeSource { + /** directory is the target directory name. +Must not contain or start with '..'. If '.' is supplied, the volume directory will be the +git repository. Otherwise, if specified, the volume will contain the git repository in +the subdirectory with the given name. ++optional */ + directory?: string + /** repository is the URL */ + repository?: string + /** revision is the commit hash for the specified revision. ++optional */ + revision?: string +} + +export interface V1GRPCAction { + /** Port number of the gRPC service. Number must be in the range 1 to 65535. */ + port?: number + /** Service is the name of the service to place in the gRPC HealthCheckRequest +(see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + +If this is not specified, the default behavior is defined by gRPC. ++optional ++default="" */ + service?: string +} + +export interface V1GCEPersistentDiskVolumeSource { + /** fsType is filesystem type of the volume that you want to mount. +Tip: Ensure that the filesystem type is supported by the host operating system. +Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. +More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk +TODO: how do we prevent errors in the filesystem from compromising the machine ++optional */ + fsType?: string + /** partition is the partition in the volume that you want to mount. +If omitted, the default is to mount by volume name. +Examples: For volume /dev/sda1, you specify the partition as "1". +Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). +More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk ++optional */ + partition?: number + /** pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. +More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk */ + pdName?: string + /** readOnly here will force the ReadOnly setting in VolumeMounts. +Defaults to false. +More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk ++optional */ + readOnly?: boolean +} + +export interface V1FlockerVolumeSource { + /** datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker +should be considered as deprecated ++optional */ + datasetName?: string + /** datasetUUID is the UUID of the dataset. This is unique identifier of a Flocker dataset ++optional */ + datasetUUID?: string +} + +/** + * options is Optional: this field holds extra command options if any. ++optional + */ +export type V1FlexVolumeSourceOptions = { [key: string]: string } + +export interface V1FlexVolumeSource { + /** driver is the name of the driver to use for this volume. */ + driver?: string + /** fsType is the filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. ++optional */ + fsType?: string + /** options is Optional: this field holds extra command options if any. ++optional */ + options?: V1FlexVolumeSourceOptions + /** readOnly is Optional: defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. ++optional */ + readOnly?: boolean + secretRef?: V1LocalObjectReference +} + +export interface V1FieldsV1 { + [key: string]: any +} + +export interface V1FCVolumeSource { + /** fsType is the filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. +TODO: how do we prevent errors in the filesystem from compromising the machine ++optional */ + fsType?: string + /** lun is Optional: FC target lun number ++optional */ + lun?: number + /** readOnly is Optional: Defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. ++optional */ + readOnly?: boolean + /** targetWWNs is Optional: FC target worldwide names (WWNs) ++optional */ + targetWWNs?: string[] + /** wwids Optional: FC volume world wide identifiers (wwids) +Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. ++optional */ + wwids?: string[] +} + +export interface V1ExecAction { + /** Command is the command line to execute inside the container, the working directory for the +command is root ('/') in the container's filesystem. The command is simply exec'd, it is +not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use +a shell, you need to explicitly call out to that shell. +Exit status of 0 is treated as live/healthy and non-zero is unhealthy. ++optional */ + command?: string[] +} + +export interface V1EphemeralVolumeSource { + volumeClaimTemplate?: V1PersistentVolumeClaimTemplate +} + +export interface V1EnvVarSource { + configMapKeyRef?: V1ConfigMapKeySelector + fieldRef?: V1ObjectFieldSelector + resourceFieldRef?: V1ResourceFieldSelector + secretKeyRef?: V1SecretKeySelector +} + +export interface V1EnvVar { + /** Name of the environment variable. Must be a C_IDENTIFIER. */ + name?: string + /** Variable references $(VAR_NAME) are expanded +using the previously defined environment variables in the container and +any service environment variables. If a variable cannot be resolved, +the reference in the input string will be unchanged. Double $$ are reduced +to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. +"$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". +Escaped references will never be expanded, regardless of whether the variable +exists or not. +Defaults to "". ++optional */ + value?: string + valueFrom?: V1EnvVarSource +} + +export interface V1EnvFromSource { + configMapRef?: V1ConfigMapEnvSource + /** An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. ++optional */ + prefix?: string + secretRef?: V1SecretEnvSource +} + +export interface V1EmptyDirVolumeSource { + /** medium represents what type of storage medium should back this directory. +The default is "" which means to use the node's default medium. +Must be an empty string (default) or Memory. +More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir ++optional */ + medium?: string + sizeLimit?: ResourceQuantity +} + +export interface V1DownwardAPIVolumeFile { + fieldRef?: V1ObjectFieldSelector + /** Optional: mode bits used to set permissions on this file, must be an octal value +between 0000 and 0777 or a decimal value between 0 and 511. +YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. +If not specified, the volume defaultMode will be used. +This might be in conflict with other options that affect the file +mode, like fsGroup, and the result can be other mode bits set. ++optional */ + mode?: number + /** Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..' */ + path?: string + resourceFieldRef?: V1ResourceFieldSelector +} + +export interface V1DownwardAPIVolumeSource { + /** Optional: mode bits to use on created files by default. Must be a +Optional: mode bits used to set permissions on created files by default. +Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. +YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. +Defaults to 0644. +Directories within the path are not affected by this setting. +This might be in conflict with other options that affect the file +mode, like fsGroup, and the result can be other mode bits set. ++optional */ + defaultMode?: number + /** Items is a list of downward API volume file ++optional */ + items?: V1DownwardAPIVolumeFile[] +} + +export interface V1DownwardAPIProjection { + /** Items is a list of DownwardAPIVolume file ++optional */ + items?: V1DownwardAPIVolumeFile[] +} + +export interface V1ContainerPort { + /** Number of port to expose on the pod's IP address. +This must be a valid port number, 0 < x < 65536. */ + containerPort?: number + /** What host IP to bind the external port to. ++optional */ + hostIP?: string + /** Number of port to expose on the host. +If specified, this must be a valid port number, 0 < x < 65536. +If HostNetwork is specified, this must match ContainerPort. +Most containers do not need this. ++optional */ + hostPort?: number + /** If specified, this must be an IANA_SVC_NAME and unique within the pod. Each +named port in a pod must have a unique name. Name for the port that can be +referred to by services. ++optional */ + name?: string + /** Protocol for port. Must be UDP, TCP, or SCTP. +Defaults to "TCP". ++optional ++default="TCP" */ + protocol?: string +} + +export interface V1Container { + /** Arguments to the entrypoint. +The container image's CMD is used if this is not provided. +Variable references $(VAR_NAME) are expanded using the container's environment. If a variable +cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced +to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will +produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless +of whether the variable exists or not. Cannot be updated. +More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell ++optional */ + args?: string[] + /** Entrypoint array. Not executed within a shell. +The container image's ENTRYPOINT is used if this is not provided. +Variable references $(VAR_NAME) are expanded using the container's environment. If a variable +cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced +to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will +produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless +of whether the variable exists or not. Cannot be updated. +More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell ++optional */ + command?: string[] + /** List of environment variables to set in the container. +Cannot be updated. ++optional ++patchMergeKey=name ++patchStrategy=merge */ + env?: V1EnvVar[] + /** List of sources to populate environment variables in the container. +The keys defined within a source must be a C_IDENTIFIER. All invalid keys +will be reported as an event when the container is starting. When a key exists in multiple +sources, the value associated with the last source will take precedence. +Values defined by an Env with a duplicate key will take precedence. +Cannot be updated. ++optional */ + envFrom?: V1EnvFromSource[] + /** Container image name. +More info: https://kubernetes.io/docs/concepts/containers/images +This field is optional to allow higher level config management to default or override +container images in workload controllers like Deployments and StatefulSets. ++optional */ + image?: string + /** Image pull policy. +One of Always, Never, IfNotPresent. +Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. +Cannot be updated. +More info: https://kubernetes.io/docs/concepts/containers/images#updating-images ++optional */ + imagePullPolicy?: string + lifecycle?: V1Lifecycle + livenessProbe?: V1Probe + /** Name of the container specified as a DNS_LABEL. +Each container in a pod must have a unique name (DNS_LABEL). +Cannot be updated. */ + name?: string + /** List of ports to expose from the container. Not specifying a port here +DOES NOT prevent that port from being exposed. Any port which is +listening on the default "0.0.0.0" address inside a container will be +accessible from the network. +Modifying this array with strategic merge patch may corrupt the data. +For more information See https://github.com/kubernetes/kubernetes/issues/108255. +Cannot be updated. ++optional ++patchMergeKey=containerPort ++patchStrategy=merge ++listType=map ++listMapKey=containerPort ++listMapKey=protocol */ + ports?: V1ContainerPort[] + readinessProbe?: V1Probe + resources?: V1ResourceRequirements + securityContext?: V1SecurityContext + startupProbe?: V1Probe + /** Whether this container should allocate a buffer for stdin in the container runtime. If this +is not set, reads from stdin in the container will always result in EOF. +Default is false. ++optional */ + stdin?: boolean + /** Whether the container runtime should close the stdin channel after it has been opened by +a single attach. When stdin is true the stdin stream will remain open across multiple attach +sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the +first client attaches to stdin, and then remains open and accepts data until the client disconnects, +at which time stdin is closed and remains closed until the container is restarted. If this +flag is false, a container processes that reads from stdin will never receive an EOF. +Default is false ++optional */ + stdinOnce?: boolean + /** Optional: Path at which the file to which the container's termination message +will be written is mounted into the container's filesystem. +Message written is intended to be brief final status, such as an assertion failure message. +Will be truncated by the node if greater than 4096 bytes. The total message length across +all containers will be limited to 12kb. +Defaults to /dev/termination-log. +Cannot be updated. ++optional */ + terminationMessagePath?: string + /** Indicate how the termination message should be populated. File will use the contents of +terminationMessagePath to populate the container status message on both success and failure. +FallbackToLogsOnError will use the last chunk of container log output if the termination +message file is empty and the container exited with an error. +The log output is limited to 2048 bytes or 80 lines, whichever is smaller. +Defaults to File. +Cannot be updated. ++optional */ + terminationMessagePolicy?: string + /** Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. +Default is false. ++optional */ + tty?: boolean + /** volumeDevices is the list of block devices to be used by the container. ++patchMergeKey=devicePath ++patchStrategy=merge ++optional */ + volumeDevices?: V1VolumeDevice[] + /** Pod volumes to mount into the container's filesystem. +Cannot be updated. ++optional ++patchMergeKey=mountPath ++patchStrategy=merge */ + volumeMounts?: V1VolumeMount[] + /** Container's working directory. +If not specified, the container runtime's default will be used, which +might be configured in the container image. +Cannot be updated. ++optional */ + workingDir?: string +} + +export interface V1ConfigMapVolumeSource { + /** defaultMode is optional: mode bits used to set permissions on created files by default. +Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. +YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. +Defaults to 0644. +Directories within the path are not affected by this setting. +This might be in conflict with other options that affect the file +mode, like fsGroup, and the result can be other mode bits set. ++optional */ + defaultMode?: number + /** items if unspecified, each key-value pair in the Data field of the referenced +ConfigMap will be projected into the volume as a file whose name is the +key and content is the value. If specified, the listed keys will be +projected into the specified paths, and unlisted keys will not be +present. If a key is specified which is not present in the ConfigMap, +the volume setup will error unless it is marked optional. Paths must be +relative and may not contain the '..' path or start with '..'. ++optional */ + items?: V1KeyToPath[] + /** Name of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names +TODO: Add other useful fields. apiVersion, kind, uid? ++optional */ + name?: string + /** optional specify whether the ConfigMap or its keys must be defined ++optional */ + optional?: boolean +} + +export interface V1ConfigMapProjection { + /** items if unspecified, each key-value pair in the Data field of the referenced +ConfigMap will be projected into the volume as a file whose name is the +key and content is the value. If specified, the listed keys will be +projected into the specified paths, and unlisted keys will not be +present. If a key is specified which is not present in the ConfigMap, +the volume setup will error unless it is marked optional. Paths must be +relative and may not contain the '..' path or start with '..'. ++optional */ + items?: V1KeyToPath[] + /** Name of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names +TODO: Add other useful fields. apiVersion, kind, uid? ++optional */ + name?: string + /** optional specify whether the ConfigMap or its keys must be defined ++optional */ + optional?: boolean +} + +export interface V1ConfigMapKeySelector { + /** The key to select. */ + key?: string + /** Name of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names +TODO: Add other useful fields. apiVersion, kind, uid? ++optional */ + name?: string + /** Specify whether the ConfigMap or its key must be defined ++optional */ + optional?: boolean +} + +export interface V1ConfigMapEnvSource { + /** Name of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names +TODO: Add other useful fields. apiVersion, kind, uid? ++optional */ + name?: string + /** Specify whether the ConfigMap must be defined ++optional */ + optional?: boolean +} + +export interface V1CinderVolumeSource { + /** fsType is the filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. +More info: https://examples.k8s.io/mysql-cinder-pd/README.md ++optional */ + fsType?: string + /** readOnly defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. +More info: https://examples.k8s.io/mysql-cinder-pd/README.md ++optional */ + readOnly?: boolean + secretRef?: V1LocalObjectReference + /** volumeID used to identify the volume in cinder. +More info: https://examples.k8s.io/mysql-cinder-pd/README.md */ + volumeID?: string +} + +export interface V1CephFSVolumeSource { + /** monitors is Required: Monitors is a collection of Ceph monitors +More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it */ + monitors?: string[] + /** path is Optional: Used as the mounted root, rather than the full Ceph tree, default is / ++optional */ + path?: string + /** readOnly is Optional: Defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. +More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it ++optional */ + readOnly?: boolean + /** secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret +More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it ++optional */ + secretFile?: string + secretRef?: V1LocalObjectReference + /** user is optional: User is the rados user name, default is admin +More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it ++optional */ + user?: string +} + +export interface V1Capabilities { + /** Added capabilities ++optional */ + add?: string[] + /** Removed capabilities ++optional */ + drop?: string[] +} + +/** + * volumeAttributes stores driver-specific properties that are passed to the CSI +driver. Consult your driver's documentation for supported values. ++optional + */ +export type V1CSIVolumeSourceVolumeAttributes = { [key: string]: string } + +export interface V1CSIVolumeSource { + /** driver is the name of the CSI driver that handles this volume. +Consult with your admin for the correct name as registered in the cluster. */ + driver?: string + /** fsType to mount. Ex. "ext4", "xfs", "ntfs". +If not provided, the empty value is passed to the associated CSI driver +which will determine the default filesystem to apply. ++optional */ + fsType?: string + nodePublishSecretRef?: V1LocalObjectReference + /** readOnly specifies a read-only configuration for the volume. +Defaults to false (read/write). ++optional */ + readOnly?: boolean + /** volumeAttributes stores driver-specific properties that are passed to the CSI +driver. Consult your driver's documentation for supported values. ++optional */ + volumeAttributes?: V1CSIVolumeSourceVolumeAttributes +} + +export interface V1AzureFileVolumeSource { + /** readOnly defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. ++optional */ + readOnly?: boolean + /** secretName is the name of secret that contains Azure Storage Account Name and Key */ + secretName?: string + /** shareName is the azure share Name */ + shareName?: string +} + +export interface V1AzureDiskVolumeSource { + /** cachingMode is the Host Caching mode: None, Read Only, Read Write. ++optional */ + cachingMode?: string + /** diskName is the Name of the data disk in the blob storage */ + diskName?: string + /** diskURI is the URI of data disk in the blob storage */ + diskURI?: string + /** fsType is Filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. ++optional */ + fsType?: string + /** kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared */ + kind?: string + /** readOnly Defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. ++optional */ + readOnly?: boolean +} + +export interface V1AWSElasticBlockStoreVolumeSource { + /** fsType is the filesystem type of the volume that you want to mount. +Tip: Ensure that the filesystem type is supported by the host operating system. +Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. +More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore +TODO: how do we prevent errors in the filesystem from compromising the machine ++optional */ + fsType?: string + /** partition is the partition in the volume that you want to mount. +If omitted, the default is to mount by volume name. +Examples: For volume /dev/sda1, you specify the partition as "1". +Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). ++optional */ + partition?: number + /** readOnly value true will force the readOnly setting in VolumeMounts. +More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore ++optional */ + readOnly?: boolean + /** volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). +More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore */ + volumeID?: string +} + +export interface UtilsResponse { + status?: string +} + +export interface UtilsMapStringSliceResponse { + [key: string]: string[] +} + +export interface UtilsAPIError { + code?: number + full_text?: string + message?: string + type?: string +} + +export interface TypesStatusCheckTemplateDetail { + created_at?: string + description?: string + name?: string + namespace?: string + spec?: V1alpha1StatusCheckTemplate + uid?: string +} + +export interface TypesStatusCheckTemplateBase { + created_at?: string + description?: string + name?: string + namespace?: string + uid?: string +} + +export interface TypesStatusCheckTemplate { + description?: string + name?: string + namespace?: string + spec?: V1alpha1StatusCheckTemplate +} + +export interface TypesScheduleDetail { + created_at?: string + experiment_uids?: string[] + kind?: string + kube_object?: CoreKubeObjectDesc + name?: string + namespace?: string + status?: string + uid?: string +} + +export interface TypesSchedule { + created_at?: string + kind?: string + name?: string + namespace?: string + status?: string + uid?: string +} + +export interface TypesPod { + ip?: string + name?: string + namespace?: string + state?: string +} + +export interface TypesPhysicalMachine { + address?: string + name?: string + namespace?: string +} + +export interface TypesExperimentDetail { + created_at?: string + failed_message?: string + kind?: string + kube_object?: CoreKubeObjectDesc + name?: string + namespace?: string + status?: string + uid?: string +} + +export interface TypesExperiment { + created_at?: string + failed_message?: string + kind?: string + name?: string + namespace?: string + status?: string + uid?: string +} + +export interface TypesArchiveDetail { + created_at?: string + kind?: string + kube_object?: CoreKubeObjectDesc + name?: string + namespace?: string + uid?: string +} + +export interface TypesArchive { + created_at?: string + kind?: string + name?: string + namespace?: string + uid?: string +} + +export interface StatusAllChaosStatus { + deleting?: number + finished?: number + injecting?: number + paused?: number + running?: number +} + +export interface ResourceQuantity { + Format?: string +} + +export interface IntstrIntOrString { + intVal?: number + strVal?: string + type?: number +} + +export interface HttpHeader { + [key: string]: string[] +} + +export interface CurlHeader { + [key: string]: string[] +} + +export interface CurlRequestForm { + body?: string + followLocation?: boolean + header?: CurlHeader + jsonContent?: boolean + method?: string + name?: string + url?: string +} + +export interface CoreWorkflowMeta { + created_at?: string + /** EndTime represents the time when the workflow completed all steps. */ + end_time?: string + /** the entry node name */ + entry?: string + /** FinishTime represents the time when the workflow was deleted from Kubernetes. */ + finish_time?: string + id?: number + name?: string + namespace?: string + status?: string + uid?: string +} + +export interface CoreNodeNameWithTemplate { + name?: string + template?: string +} + +export interface CoreNode { + conditional_branches?: CoreConditionalBranch[] + name?: string + parallel?: CoreNodeNameWithTemplate[] + serial?: CoreNodeNameWithTemplate[] + state?: string + template?: string + type?: string + uid?: string +} + +export interface CoreTopology { + nodes?: CoreNode[] +} + +export interface CoreWorkflowDetail { + created_at?: string + /** EndTime represents the time when the workflow completed all steps. */ + end_time?: string + /** the entry node name */ + entry?: string + /** FinishTime represents the time when the workflow was deleted from Kubernetes. */ + finish_time?: string + id?: number + kube_object?: CoreKubeObjectDesc + name?: string + namespace?: string + status?: string + topology?: CoreTopology + uid?: string +} + +export type CoreKubeObjectMetaLabels = { [key: string]: string } + +export type CoreKubeObjectMetaAnnotations = { [key: string]: string } + +export interface CoreKubeObjectMeta { + annotations?: CoreKubeObjectMetaAnnotations + labels?: CoreKubeObjectMetaLabels + name?: string + namespace?: string +} + +export interface CoreKubeObjectDesc { + /** APIVersion defines the versioned schema of this representation of an object. +Servers should convert recognized schemas to the latest internal value, and +may reject unrecognized values. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources ++optional */ + apiVersion?: string + /** Kind is a string value representing the REST resource this object represents. +Servers may infer this from the endpoint the client submits requests to. +Cannot be updated. +In CamelCase. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds ++optional */ + kind?: string + metadata?: CoreKubeObjectMeta + spec?: unknown +} + +export interface CoreEvent { + created_at?: string + id?: number + kind?: string + message?: string + name?: string + namespace?: string + object_id?: string + reason?: string + type?: string +} + +export interface CoreConditionalBranch { + expression?: string + name?: string + template?: string +} + +export interface ConfigChaosDashboardConfig { + /** The Burst config for kubernetes client */ + burst?: number + /** ClusterScoped means control Chaos Object in cluster level(all namespace). */ + cluster_mode?: boolean + dns_server_create?: boolean + /** EnableFilterNamespace will filter namespace with annotation. Only the pods/containers in namespace +annotated with `chaos-mesh.org/inject=enabled` will be injected. */ + enableFilterNamespace?: boolean + /** enableProfiling is a flag to enable pprof in controller-manager and chaos-daemon */ + enableProfiling?: boolean + /** GcpSecurityMode will use the gcloud authentication to login to GKE user */ + gcp_security_mode?: boolean + listen_host?: string + listen_port?: number + /** The QPS config for kubernetes client */ + qps?: number + root_path?: string + /** SecurityMode will use the token login by the user if set to true */ + security_mode?: boolean + /** TargetNamespace is the target namespace to injecting chaos. +It only works with ClusterScoped is false. */ + target_namespace?: string + version?: string +} diff --git a/ui/app/src/openapi/index.ts b/ui/app/src/openapi/index.ts new file mode 100644 index 0000000000..2980be8e18 --- /dev/null +++ b/ui/app/src/openapi/index.ts @@ -0,0 +1,2208 @@ +/** + * Generated by orval v6.12.1 🍺 + * Do not edit manually. + * Chaos Mesh Dashboard API + * Swagger for Chaos Mesh Dashboard. If you encounter any problems with API, please click on the issues link below to report. + * OpenAPI spec version: 2.2 + */ +import { useMutation, useQuery } from '@tanstack/react-query' +import type { + MutationFunction, + QueryFunction, + QueryKey, + UseMutationOptions, + UseQueryOptions, + UseQueryResult, +} from '@tanstack/react-query' + +import { customInstance } from '../api/http' +import type { + ConfigChaosDashboardConfig, + CoreEvent, + CoreWorkflowDetail, + CoreWorkflowMeta, + CurlRequestForm, + DeleteArchivesParams, + DeleteArchivesSchedulesParams, + DeleteArchivesWorkflowsParams, + DeleteExperimentsParams, + DeleteExperimentsUidParams, + DeleteSchedulesParams, + DeleteTemplatesStatuschecksStatuscheckParams, + GetArchivesParams, + GetArchivesSchedulesParams, + GetArchivesWorkflowsParams, + GetCommonAnnotationsParams, + GetCommonLabelsParams, + GetCommonPhysicalmachineAnnotationsParams, + GetCommonPhysicalmachineLabelsParams, + GetCommonRbacConfig200, + GetCommonRbacConfigParams, + GetEventsParams, + GetEventsWorkflowUidParams, + GetExperimentsParams, + GetExperimentsStateParams, + GetSchedulesParams, + GetTemplatesStatuschecksParams, + GetTemplatesStatuschecksStatuscheckParams, + GetWorkflowsParams, + PostExperiments200, + PostExperimentsBody, + StatusAllChaosStatus, + TypesArchive, + TypesArchiveDetail, + TypesExperiment, + TypesExperimentDetail, + TypesPhysicalMachine, + TypesPod, + TypesSchedule, + TypesScheduleDetail, + TypesStatusCheckTemplate, + TypesStatusCheckTemplateBase, + TypesStatusCheckTemplateDetail, + UtilsAPIError, + UtilsMapStringSliceResponse, + UtilsResponse, + V1alpha1PhysicalMachineSelectorSpec, + V1alpha1PodSelectorSpec, + V1alpha1Schedule, + V1alpha1Template, + V1alpha1TemplateBody, + V1alpha1WorkflowBody, +} from './index.schemas' + +/** + * Delete the specified archived experiment. + * @summary Delete the specified archived experiment. + */ +export const deleteArchives = (params: DeleteArchivesParams) => { + return customInstance({ url: `/archives`, method: 'delete', params }) +} + +export type DeleteArchivesMutationResult = NonNullable>> + +export type DeleteArchivesMutationError = UtilsAPIError + +export const useDeleteArchives = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { params: DeleteArchivesParams }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { params: DeleteArchivesParams }> = ( + props + ) => { + const { params } = props ?? {} + + return deleteArchives(params) + } + + return useMutation>, TError, { params: DeleteArchivesParams }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Get archived chaos experiments. + * @summary Get archived chaos experiments. + */ +export const getArchives = (params?: GetArchivesParams, signal?: AbortSignal) => { + return customInstance({ url: `/archives`, method: 'get', params, signal }) +} + +export const getGetArchivesQueryKey = (params?: GetArchivesParams) => [`/archives`, ...(params ? [params] : [])] + +export type GetArchivesQueryResult = NonNullable>> +export type GetArchivesQueryError = UtilsAPIError + +export const useGetArchives = >, TError = UtilsAPIError>( + params?: GetArchivesParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetArchivesQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => getArchives(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Delete the specified archived experiment. + * @summary Delete the specified archived experiment. + */ +export const deleteArchivesUid = (uid: string) => { + return customInstance({ url: `/archives/${uid}`, method: 'delete' }) +} + +export type DeleteArchivesUidMutationResult = NonNullable>> + +export type DeleteArchivesUidMutationError = UtilsAPIError + +export const useDeleteArchivesUid = (options?: { + mutation?: UseMutationOptions>, TError, { uid: string }, TContext> +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { uid: string }> = (props) => { + const { uid } = props ?? {} + + return deleteArchivesUid(uid) + } + + return useMutation>, TError, { uid: string }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Get the archived chaos experiment's detail by uid. + * @summary Get an archived chaos experiment. + */ +export const getArchivesUid = (uid: string, signal?: AbortSignal) => { + return customInstance({ url: `/archives/${uid}`, method: 'get', signal }) +} + +export const getGetArchivesUidQueryKey = (uid: string) => [`/archives/${uid}`] + +export type GetArchivesUidQueryResult = NonNullable>> +export type GetArchivesUidQueryError = UtilsAPIError + +export const useGetArchivesUid = >, TError = UtilsAPIError>( + uid: string, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetArchivesUidQueryKey(uid) + + const queryFn: QueryFunction>> = ({ signal }) => getArchivesUid(uid, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + enabled: !!uid, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Delete the specified archived schedule. + * @summary Delete the specified archived schedule. + */ +export const deleteArchivesSchedules = (params: DeleteArchivesSchedulesParams) => { + return customInstance({ url: `/archives/schedules`, method: 'delete', params }) +} + +export type DeleteArchivesSchedulesMutationResult = NonNullable>> + +export type DeleteArchivesSchedulesMutationError = UtilsAPIError + +export const useDeleteArchivesSchedules = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { params: DeleteArchivesSchedulesParams }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction< + Awaited>, + { params: DeleteArchivesSchedulesParams } + > = (props) => { + const { params } = props ?? {} + + return deleteArchivesSchedules(params) + } + + return useMutation< + Awaited>, + TError, + { params: DeleteArchivesSchedulesParams }, + TContext + >(mutationFn, mutationOptions) +} + +/** + * Get archived schedule experiments. + * @summary Get archived schedule experiments. + */ +export const getArchivesSchedules = (params?: GetArchivesSchedulesParams, signal?: AbortSignal) => { + return customInstance({ url: `/archives/schedules`, method: 'get', params, signal }) +} + +export const getGetArchivesSchedulesQueryKey = (params?: GetArchivesSchedulesParams) => [ + `/archives/schedules`, + ...(params ? [params] : []), +] + +export type GetArchivesSchedulesQueryResult = NonNullable>> +export type GetArchivesSchedulesQueryError = UtilsAPIError + +export const useGetArchivesSchedules = < + TData = Awaited>, + TError = UtilsAPIError +>( + params?: GetArchivesSchedulesParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetArchivesSchedulesQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => + getArchivesSchedules(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Delete the specified archived schedule. + * @summary Delete the specified archived schedule. + */ +export const deleteArchivesSchedulesUid = (uid: string) => { + return customInstance({ url: `/archives/schedules/${uid}`, method: 'delete' }) +} + +export type DeleteArchivesSchedulesUidMutationResult = NonNullable< + Awaited> +> + +export type DeleteArchivesSchedulesUidMutationError = UtilsAPIError + +export const useDeleteArchivesSchedulesUid = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { uid: string }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { uid: string }> = ( + props + ) => { + const { uid } = props ?? {} + + return deleteArchivesSchedulesUid(uid) + } + + return useMutation>, TError, { uid: string }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Get the detail of an archived schedule experiment. + * @summary Get the detail of an archived schedule experiment. + */ +export const getArchivesSchedulesUid = (uid: string, signal?: AbortSignal) => { + return customInstance({ url: `/archives/schedules/${uid}`, method: 'get', signal }) +} + +export const getGetArchivesSchedulesUidQueryKey = (uid: string) => [`/archives/schedules/${uid}`] + +export type GetArchivesSchedulesUidQueryResult = NonNullable>> +export type GetArchivesSchedulesUidQueryError = UtilsAPIError + +export const useGetArchivesSchedulesUid = < + TData = Awaited>, + TError = UtilsAPIError +>( + uid: string, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetArchivesSchedulesUidQueryKey(uid) + + const queryFn: QueryFunction>> = ({ signal }) => + getArchivesSchedulesUid(uid, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + enabled: !!uid, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Delete the specified archived workflows. + * @summary Delete the specified archived workflows. + */ +export const deleteArchivesWorkflows = (params: DeleteArchivesWorkflowsParams) => { + return customInstance({ url: `/archives/workflows`, method: 'delete', params }) +} + +export type DeleteArchivesWorkflowsMutationResult = NonNullable>> + +export type DeleteArchivesWorkflowsMutationError = UtilsAPIError + +export const useDeleteArchivesWorkflows = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { params: DeleteArchivesWorkflowsParams }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction< + Awaited>, + { params: DeleteArchivesWorkflowsParams } + > = (props) => { + const { params } = props ?? {} + + return deleteArchivesWorkflows(params) + } + + return useMutation< + Awaited>, + TError, + { params: DeleteArchivesWorkflowsParams }, + TContext + >(mutationFn, mutationOptions) +} + +/** + * Get archived workflow. + * @summary Get archived workflow. + */ +export const getArchivesWorkflows = (params?: GetArchivesWorkflowsParams, signal?: AbortSignal) => { + return customInstance({ url: `/archives/workflows`, method: 'get', params, signal }) +} + +export const getGetArchivesWorkflowsQueryKey = (params?: GetArchivesWorkflowsParams) => [ + `/archives/workflows`, + ...(params ? [params] : []), +] + +export type GetArchivesWorkflowsQueryResult = NonNullable>> +export type GetArchivesWorkflowsQueryError = UtilsAPIError + +export const useGetArchivesWorkflows = < + TData = Awaited>, + TError = UtilsAPIError +>( + params?: GetArchivesWorkflowsParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetArchivesWorkflowsQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => + getArchivesWorkflows(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Delete the specified archived workflow. + * @summary Delete the specified archived workflow. + */ +export const deleteArchivesWorkflowsUid = (uid: string) => { + return customInstance({ url: `/archives/workflows/${uid}`, method: 'delete' }) +} + +export type DeleteArchivesWorkflowsUidMutationResult = NonNullable< + Awaited> +> + +export type DeleteArchivesWorkflowsUidMutationError = UtilsAPIError + +export const useDeleteArchivesWorkflowsUid = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { uid: string }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { uid: string }> = ( + props + ) => { + const { uid } = props ?? {} + + return deleteArchivesWorkflowsUid(uid) + } + + return useMutation>, TError, { uid: string }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Get the detail of an archived workflow. + * @summary Get the detail of an archived workflow. + */ +export const getArchivesWorkflowsUid = (uid: string, signal?: AbortSignal) => { + return customInstance({ url: `/archives/workflows/${uid}`, method: 'get', signal }) +} + +export const getGetArchivesWorkflowsUidQueryKey = (uid: string) => [`/archives/workflows/${uid}`] + +export type GetArchivesWorkflowsUidQueryResult = NonNullable>> +export type GetArchivesWorkflowsUidQueryError = UtilsAPIError + +export const useGetArchivesWorkflowsUid = < + TData = Awaited>, + TError = UtilsAPIError +>( + uid: string, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetArchivesWorkflowsUidQueryKey(uid) + + const queryFn: QueryFunction>> = ({ signal }) => + getArchivesWorkflowsUid(uid, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + enabled: !!uid, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Get the annotations of the pods in the specified namespace from Kubernetes cluster. + * @summary Get the annotations of the pods in the specified namespace from Kubernetes cluster. + */ +export const getCommonAnnotations = (params: GetCommonAnnotationsParams, signal?: AbortSignal) => { + return customInstance({ url: `/common/annotations`, method: 'get', params, signal }) +} + +export const getGetCommonAnnotationsQueryKey = (params: GetCommonAnnotationsParams) => [ + `/common/annotations`, + ...(params ? [params] : []), +] + +export type GetCommonAnnotationsQueryResult = NonNullable>> +export type GetCommonAnnotationsQueryError = UtilsAPIError + +export const useGetCommonAnnotations = < + TData = Awaited>, + TError = UtilsAPIError +>( + params: GetCommonAnnotationsParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetCommonAnnotationsQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => + getCommonAnnotations(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Get all namespaces which could inject chaos(explosion scope) from Kubernetes cluster. + * @summary Get all namespaces which could inject chaos(explosion scope) from Kubernetes cluster. + */ +export const getCommonChaosAvailableNamespaces = (signal?: AbortSignal) => { + return customInstance({ url: `/common/chaos-available-namespaces`, method: 'get', signal }) +} + +export const getGetCommonChaosAvailableNamespacesQueryKey = () => [`/common/chaos-available-namespaces`] + +export type GetCommonChaosAvailableNamespacesQueryResult = NonNullable< + Awaited> +> +export type GetCommonChaosAvailableNamespacesQueryError = UtilsAPIError + +export const useGetCommonChaosAvailableNamespaces = < + TData = Awaited>, + TError = UtilsAPIError +>(options?: { + query?: UseQueryOptions>, TError, TData> +}): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetCommonChaosAvailableNamespacesQueryKey() + + const queryFn: QueryFunction>> = ({ signal }) => + getCommonChaosAvailableNamespaces(signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Get the config of Dashboard. + * @summary Get the config of Dashboard. + */ +export const getCommonConfig = (signal?: AbortSignal) => { + return customInstance({ url: `/common/config`, method: 'get', signal }) +} + +export const getGetCommonConfigQueryKey = () => [`/common/config`] + +export type GetCommonConfigQueryResult = NonNullable>> +export type GetCommonConfigQueryError = UtilsAPIError + +export const useGetCommonConfig = < + TData = Awaited>, + TError = UtilsAPIError +>(options?: { + query?: UseQueryOptions>, TError, TData> +}): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetCommonConfigQueryKey() + + const queryFn: QueryFunction>> = ({ signal }) => getCommonConfig(signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Get all chaos kinds from Kubernetes cluster. + * @summary Get all chaos kinds from Kubernetes cluster. + */ +export const getCommonKinds = (signal?: AbortSignal) => { + return customInstance({ url: `/common/kinds`, method: 'get', signal }) +} + +export const getGetCommonKindsQueryKey = () => [`/common/kinds`] + +export type GetCommonKindsQueryResult = NonNullable>> +export type GetCommonKindsQueryError = UtilsAPIError + +export const useGetCommonKinds = < + TData = Awaited>, + TError = UtilsAPIError +>(options?: { + query?: UseQueryOptions>, TError, TData> +}): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetCommonKindsQueryKey() + + const queryFn: QueryFunction>> = ({ signal }) => getCommonKinds(signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Get the labels of the pods in the specified namespace from Kubernetes cluster. + * @summary Get the labels of the pods in the specified namespace from Kubernetes cluster. + */ +export const getCommonLabels = (params: GetCommonLabelsParams, signal?: AbortSignal) => { + return customInstance({ url: `/common/labels`, method: 'get', params, signal }) +} + +export const getGetCommonLabelsQueryKey = (params: GetCommonLabelsParams) => [ + `/common/labels`, + ...(params ? [params] : []), +] + +export type GetCommonLabelsQueryResult = NonNullable>> +export type GetCommonLabelsQueryError = UtilsAPIError + +export const useGetCommonLabels = >, TError = UtilsAPIError>( + params: GetCommonLabelsParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetCommonLabelsQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => + getCommonLabels(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Get all from Kubernetes cluster. + * @deprecated + * @summary Get all namespaces from Kubernetes cluster. + */ +export const getCommonNamespaces = (signal?: AbortSignal) => { + return customInstance({ url: `/common/namespaces`, method: 'get', signal }) +} + +export const getGetCommonNamespacesQueryKey = () => [`/common/namespaces`] + +export type GetCommonNamespacesQueryResult = NonNullable>> +export type GetCommonNamespacesQueryError = UtilsAPIError + +export const useGetCommonNamespaces = < + TData = Awaited>, + TError = UtilsAPIError +>(options?: { + query?: UseQueryOptions>, TError, TData> +}): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetCommonNamespacesQueryKey() + + const queryFn: QueryFunction>> = ({ signal }) => + getCommonNamespaces(signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Get the annotations of the physicalMachines in the specified namespace from Kubernetes cluster. + * @summary Get the annotations of the physicalMachines in the specified namespace from Kubernetes cluster. + */ +export const getCommonPhysicalmachineAnnotations = ( + params: GetCommonPhysicalmachineAnnotationsParams, + signal?: AbortSignal +) => { + return customInstance({ + url: `/common/physicalmachine-annotations`, + method: 'get', + params, + signal, + }) +} + +export const getGetCommonPhysicalmachineAnnotationsQueryKey = (params: GetCommonPhysicalmachineAnnotationsParams) => [ + `/common/physicalmachine-annotations`, + ...(params ? [params] : []), +] + +export type GetCommonPhysicalmachineAnnotationsQueryResult = NonNullable< + Awaited> +> +export type GetCommonPhysicalmachineAnnotationsQueryError = UtilsAPIError + +export const useGetCommonPhysicalmachineAnnotations = < + TData = Awaited>, + TError = UtilsAPIError +>( + params: GetCommonPhysicalmachineAnnotationsParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetCommonPhysicalmachineAnnotationsQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => + getCommonPhysicalmachineAnnotations(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Get the labels of the physicalMachines in the specified namespace from Kubernetes cluster. + * @summary Get the labels of the physicalMachines in the specified namespace from Kubernetes cluster. + */ +export const getCommonPhysicalmachineLabels = (params: GetCommonPhysicalmachineLabelsParams, signal?: AbortSignal) => { + return customInstance({ + url: `/common/physicalmachine-labels`, + method: 'get', + params, + signal, + }) +} + +export const getGetCommonPhysicalmachineLabelsQueryKey = (params: GetCommonPhysicalmachineLabelsParams) => [ + `/common/physicalmachine-labels`, + ...(params ? [params] : []), +] + +export type GetCommonPhysicalmachineLabelsQueryResult = NonNullable< + Awaited> +> +export type GetCommonPhysicalmachineLabelsQueryError = UtilsAPIError + +export const useGetCommonPhysicalmachineLabels = < + TData = Awaited>, + TError = UtilsAPIError +>( + params: GetCommonPhysicalmachineLabelsParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetCommonPhysicalmachineLabelsQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => + getCommonPhysicalmachineLabels(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Get physicalMachines from Kubernetes cluster. + * @summary Get physicalMachines from Kubernetes cluster. + */ +export const postCommonPhysicalmachines = ( + v1alpha1PhysicalMachineSelectorSpec: V1alpha1PhysicalMachineSelectorSpec +) => { + return customInstance({ + url: `/common/physicalmachines`, + method: 'post', + headers: { 'Content-Type': 'application/json' }, + data: v1alpha1PhysicalMachineSelectorSpec, + }) +} + +export type PostCommonPhysicalmachinesMutationResult = NonNullable< + Awaited> +> +export type PostCommonPhysicalmachinesMutationBody = V1alpha1PhysicalMachineSelectorSpec +export type PostCommonPhysicalmachinesMutationError = UtilsAPIError + +export const usePostCommonPhysicalmachines = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { data: V1alpha1PhysicalMachineSelectorSpec }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction< + Awaited>, + { data: V1alpha1PhysicalMachineSelectorSpec } + > = (props) => { + const { data } = props ?? {} + + return postCommonPhysicalmachines(data) + } + + return useMutation< + Awaited>, + TError, + { data: V1alpha1PhysicalMachineSelectorSpec }, + TContext + >(mutationFn, mutationOptions) +} + +/** + * Get pods from Kubernetes cluster. + * @summary Get pods from Kubernetes cluster. + */ +export const postCommonPods = (v1alpha1PodSelectorSpec: V1alpha1PodSelectorSpec) => { + return customInstance({ + url: `/common/pods`, + method: 'post', + headers: { 'Content-Type': 'application/json' }, + data: v1alpha1PodSelectorSpec, + }) +} + +export type PostCommonPodsMutationResult = NonNullable>> +export type PostCommonPodsMutationBody = V1alpha1PodSelectorSpec +export type PostCommonPodsMutationError = UtilsAPIError + +export const usePostCommonPods = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { data: V1alpha1PodSelectorSpec }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { data: V1alpha1PodSelectorSpec }> = ( + props + ) => { + const { data } = props ?? {} + + return postCommonPods(data) + } + + return useMutation>, TError, { data: V1alpha1PodSelectorSpec }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Get the rbac config according to the user's choice. + * @summary Get the rbac config according to the user's choice. + */ +export const getCommonRbacConfig = (params?: GetCommonRbacConfigParams, signal?: AbortSignal) => { + return customInstance({ url: `/common/rbac-config`, method: 'get', params, signal }) +} + +export const getGetCommonRbacConfigQueryKey = (params?: GetCommonRbacConfigParams) => [ + `/common/rbac-config`, + ...(params ? [params] : []), +] + +export type GetCommonRbacConfigQueryResult = NonNullable>> +export type GetCommonRbacConfigQueryError = UtilsAPIError + +export const useGetCommonRbacConfig = >, TError = UtilsAPIError>( + params?: GetCommonRbacConfigParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetCommonRbacConfigQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => + getCommonRbacConfig(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Get events from db. + * @summary list events. + */ +export const getEvents = (params?: GetEventsParams, signal?: AbortSignal) => { + return customInstance({ url: `/events`, method: 'get', params, signal }) +} + +export const getGetEventsQueryKey = (params?: GetEventsParams) => [`/events`, ...(params ? [params] : [])] + +export type GetEventsQueryResult = NonNullable>> +export type GetEventsQueryError = UtilsAPIError + +export const useGetEvents = >, TError = UtilsAPIError>( + params?: GetEventsParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetEventsQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => getEvents(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Get the event from db by ID. + * @summary Get an event. + */ +export const getEventsId = (id: number, signal?: AbortSignal) => { + return customInstance({ url: `/events/${id}`, method: 'get', signal }) +} + +export const getGetEventsIdQueryKey = (id: number) => [`/events/${id}`] + +export type GetEventsIdQueryResult = NonNullable>> +export type GetEventsIdQueryError = UtilsAPIError + +export const useGetEventsId = >, TError = UtilsAPIError>( + id: number, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetEventsIdQueryKey(id) + + const queryFn: QueryFunction>> = ({ signal }) => getEventsId(id, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + enabled: !!id, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * list all events for Workflow and related WorkflowNode. + * @summary cascadeFetchEventsForWorkflow list all events for Workflow and related WorkflowNode. + */ +export const getEventsWorkflowUid = (uid: string, params?: GetEventsWorkflowUidParams, signal?: AbortSignal) => { + return customInstance({ url: `/events/workflow/${uid}`, method: 'get', params, signal }) +} + +export const getGetEventsWorkflowUidQueryKey = (uid: string, params?: GetEventsWorkflowUidParams) => [ + `/events/workflow/${uid}`, + ...(params ? [params] : []), +] + +export type GetEventsWorkflowUidQueryResult = NonNullable>> +export type GetEventsWorkflowUidQueryError = UtilsAPIError + +export const useGetEventsWorkflowUid = < + TData = Awaited>, + TError = UtilsAPIError +>( + uid: string, + params?: GetEventsWorkflowUidParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetEventsWorkflowUidQueryKey(uid, params) + + const queryFn: QueryFunction>> = ({ signal }) => + getEventsWorkflowUid(uid, params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + enabled: !!uid, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Batch delete chaos experiments by uids. + * @summary Batch delete chaos experiments. + */ +export const deleteExperiments = (params: DeleteExperimentsParams) => { + return customInstance({ url: `/experiments`, method: 'delete', params }) +} + +export type DeleteExperimentsMutationResult = NonNullable>> + +export type DeleteExperimentsMutationError = UtilsAPIError + +export const useDeleteExperiments = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { params: DeleteExperimentsParams }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction< + Awaited>, + { params: DeleteExperimentsParams } + > = (props) => { + const { params } = props ?? {} + + return deleteExperiments(params) + } + + return useMutation< + Awaited>, + TError, + { params: DeleteExperimentsParams }, + TContext + >(mutationFn, mutationOptions) +} + +/** + * Get chaos experiments from k8s clusters in real time. + * @summary List chaos experiments. + */ +export const getExperiments = (params?: GetExperimentsParams, signal?: AbortSignal) => { + return customInstance({ url: `/experiments`, method: 'get', params, signal }) +} + +export const getGetExperimentsQueryKey = (params?: GetExperimentsParams) => [ + `/experiments`, + ...(params ? [params] : []), +] + +export type GetExperimentsQueryResult = NonNullable>> +export type GetExperimentsQueryError = UtilsAPIError + +export const useGetExperiments = >, TError = UtilsAPIError>( + params?: GetExperimentsParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetExperimentsQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => + getExperiments(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Pass a JSON object to create a new chaos experiment. The schema for JSON is the same as the YAML schema for the Kubernetes object. + * @summary Create a new chaos experiment. + */ +export const postExperiments = (postExperimentsBody: PostExperimentsBody) => { + return customInstance({ + url: `/experiments`, + method: 'post', + headers: { 'Content-Type': 'application/json' }, + data: postExperimentsBody, + }) +} + +export type PostExperimentsMutationResult = NonNullable>> +export type PostExperimentsMutationBody = PostExperimentsBody +export type PostExperimentsMutationError = UtilsAPIError + +export const usePostExperiments = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { data: PostExperimentsBody }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { data: PostExperimentsBody }> = ( + props + ) => { + const { data } = props ?? {} + + return postExperiments(data) + } + + return useMutation>, TError, { data: PostExperimentsBody }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Delete the chaos experiment by uid. + * @summary Delete a chaos experiment. + */ +export const deleteExperimentsUid = (uid: string, params?: DeleteExperimentsUidParams) => { + return customInstance({ url: `/experiments/${uid}`, method: 'delete', params }) +} + +export type DeleteExperimentsUidMutationResult = NonNullable>> + +export type DeleteExperimentsUidMutationError = UtilsAPIError + +export const useDeleteExperimentsUid = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { uid: string; params?: DeleteExperimentsUidParams }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction< + Awaited>, + { uid: string; params?: DeleteExperimentsUidParams } + > = (props) => { + const { uid, params } = props ?? {} + + return deleteExperimentsUid(uid, params) + } + + return useMutation< + Awaited>, + TError, + { uid: string; params?: DeleteExperimentsUidParams }, + TContext + >(mutationFn, mutationOptions) +} + +/** + * Get the chaos experiment's detail by uid. + * @summary Get a chaos experiment. + */ +export const getExperimentsUid = (uid: string, signal?: AbortSignal) => { + return customInstance({ url: `/experiments/${uid}`, method: 'get', signal }) +} + +export const getGetExperimentsUidQueryKey = (uid: string) => [`/experiments/${uid}`] + +export type GetExperimentsUidQueryResult = NonNullable>> +export type GetExperimentsUidQueryError = UtilsAPIError + +export const useGetExperimentsUid = >, TError = UtilsAPIError>( + uid: string, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetExperimentsUidQueryKey(uid) + + const queryFn: QueryFunction>> = ({ signal }) => + getExperimentsUid(uid, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + enabled: !!uid, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Pause a chaos experiment. + * @summary Pause a chaos experiment. + */ +export const putExperimentsPauseUid = (uid: string) => { + return customInstance({ url: `/experiments/pause/${uid}`, method: 'put' }) +} + +export type PutExperimentsPauseUidMutationResult = NonNullable>> + +export type PutExperimentsPauseUidMutationError = UtilsAPIError + +export const usePutExperimentsPauseUid = (options?: { + mutation?: UseMutationOptions>, TError, { uid: string }, TContext> +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { uid: string }> = (props) => { + const { uid } = props ?? {} + + return putExperimentsPauseUid(uid) + } + + return useMutation>, TError, { uid: string }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Start a chaos experiment. + * @summary Start a chaos experiment. + */ +export const putExperimentsStartUid = (uid: string) => { + return customInstance({ url: `/experiments/start/${uid}`, method: 'put' }) +} + +export type PutExperimentsStartUidMutationResult = NonNullable>> + +export type PutExperimentsStartUidMutationError = UtilsAPIError + +export const usePutExperimentsStartUid = (options?: { + mutation?: UseMutationOptions>, TError, { uid: string }, TContext> +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { uid: string }> = (props) => { + const { uid } = props ?? {} + + return putExperimentsStartUid(uid) + } + + return useMutation>, TError, { uid: string }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Get the status of all experiments. + * @summary Get the status of all experiments. + */ +export const getExperimentsState = (params?: GetExperimentsStateParams, signal?: AbortSignal) => { + return customInstance({ url: `/experiments/state`, method: 'get', params, signal }) +} + +export const getGetExperimentsStateQueryKey = (params?: GetExperimentsStateParams) => [ + `/experiments/state`, + ...(params ? [params] : []), +] + +export type GetExperimentsStateQueryResult = NonNullable>> +export type GetExperimentsStateQueryError = UtilsAPIError + +export const useGetExperimentsState = >, TError = UtilsAPIError>( + params?: GetExperimentsStateParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetExperimentsStateQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => + getExperimentsState(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Batch delete schedules by uids. + * @summary Batch delete schedules. + */ +export const deleteSchedules = (params: DeleteSchedulesParams) => { + return customInstance({ url: `/schedules`, method: 'delete', params }) +} + +export type DeleteSchedulesMutationResult = NonNullable>> + +export type DeleteSchedulesMutationError = UtilsAPIError + +export const useDeleteSchedules = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { params: DeleteSchedulesParams }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { params: DeleteSchedulesParams }> = ( + props + ) => { + const { params } = props ?? {} + + return deleteSchedules(params) + } + + return useMutation>, TError, { params: DeleteSchedulesParams }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Get chaos schedules from k8s cluster in real time. + * @summary List chaos schedules. + */ +export const getSchedules = (params?: GetSchedulesParams, signal?: AbortSignal) => { + return customInstance({ url: `/schedules`, method: 'get', params, signal }) +} + +export const getGetSchedulesQueryKey = (params?: GetSchedulesParams) => [`/schedules`, ...(params ? [params] : [])] + +export type GetSchedulesQueryResult = NonNullable>> +export type GetSchedulesQueryError = UtilsAPIError + +export const useGetSchedules = >, TError = UtilsAPIError>( + params?: GetSchedulesParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetSchedulesQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => getSchedules(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Pass a JSON object to create a new schedule. The schema for JSON is the same as the YAML schema for the Kubernetes object. + * @summary Create a new schedule. + */ +export const postSchedules = (v1alpha1Schedule: V1alpha1Schedule) => { + return customInstance({ + url: `/schedules`, + method: 'post', + headers: { 'Content-Type': 'application/json' }, + data: v1alpha1Schedule, + }) +} + +export type PostSchedulesMutationResult = NonNullable>> +export type PostSchedulesMutationBody = V1alpha1Schedule +export type PostSchedulesMutationError = UtilsAPIError + +export const usePostSchedules = (options?: { + mutation?: UseMutationOptions>, TError, { data: V1alpha1Schedule }, TContext> +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { data: V1alpha1Schedule }> = ( + props + ) => { + const { data } = props ?? {} + + return postSchedules(data) + } + + return useMutation>, TError, { data: V1alpha1Schedule }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Delete the schedule by uid. + * @summary Delete a schedule. + */ +export const deleteSchedulesUid = (uid: string) => { + return customInstance({ url: `/schedules/${uid}`, method: 'delete' }) +} + +export type DeleteSchedulesUidMutationResult = NonNullable>> + +export type DeleteSchedulesUidMutationError = UtilsAPIError + +export const useDeleteSchedulesUid = (options?: { + mutation?: UseMutationOptions>, TError, { uid: string }, TContext> +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { uid: string }> = (props) => { + const { uid } = props ?? {} + + return deleteSchedulesUid(uid) + } + + return useMutation>, TError, { uid: string }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Get the schedule's detail by uid. + * @summary Get a schedule. + */ +export const getSchedulesUid = (uid: string, signal?: AbortSignal) => { + return customInstance({ url: `/schedules/${uid}`, method: 'get', signal }) +} + +export const getGetSchedulesUidQueryKey = (uid: string) => [`/schedules/${uid}`] + +export type GetSchedulesUidQueryResult = NonNullable>> +export type GetSchedulesUidQueryError = UtilsAPIError + +export const useGetSchedulesUid = >, TError = UtilsAPIError>( + uid: string, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetSchedulesUidQueryKey(uid) + + const queryFn: QueryFunction>> = ({ signal }) => + getSchedulesUid(uid, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + enabled: !!uid, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Pause a schedule. + * @summary Pause a schedule. + */ +export const putSchedulesPauseUid = (uid: string) => { + return customInstance({ url: `/schedules/pause/${uid}`, method: 'put' }) +} + +export type PutSchedulesPauseUidMutationResult = NonNullable>> + +export type PutSchedulesPauseUidMutationError = UtilsAPIError + +export const usePutSchedulesPauseUid = (options?: { + mutation?: UseMutationOptions>, TError, { uid: string }, TContext> +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { uid: string }> = (props) => { + const { uid } = props ?? {} + + return putSchedulesPauseUid(uid) + } + + return useMutation>, TError, { uid: string }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Start a schedule. + * @summary Start a schedule. + */ +export const putSchedulesStartUid = (uid: string) => { + return customInstance({ url: `/schedules/start/${uid}`, method: 'put' }) +} + +export type PutSchedulesStartUidMutationResult = NonNullable>> + +export type PutSchedulesStartUidMutationError = UtilsAPIError + +export const usePutSchedulesStartUid = (options?: { + mutation?: UseMutationOptions>, TError, { uid: string }, TContext> +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { uid: string }> = (props) => { + const { uid } = props ?? {} + + return putSchedulesStartUid(uid) + } + + return useMutation>, TError, { uid: string }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Get status check templates from k8s cluster in real time. + * @summary List status check templates. + */ +export const getTemplatesStatuschecks = (params?: GetTemplatesStatuschecksParams, signal?: AbortSignal) => { + return customInstance({ + url: `/templates/statuschecks`, + method: 'get', + params, + signal, + }) +} + +export const getGetTemplatesStatuschecksQueryKey = (params?: GetTemplatesStatuschecksParams) => [ + `/templates/statuschecks`, + ...(params ? [params] : []), +] + +export type GetTemplatesStatuschecksQueryResult = NonNullable>> +export type GetTemplatesStatuschecksQueryError = UtilsAPIError + +export const useGetTemplatesStatuschecks = < + TData = Awaited>, + TError = UtilsAPIError +>( + params?: GetTemplatesStatuschecksParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetTemplatesStatuschecksQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => + getTemplatesStatuschecks(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Pass a JSON object to create a new status check template. + * @summary Create a new status check template. + */ +export const postTemplatesStatuschecks = (typesStatusCheckTemplate: TypesStatusCheckTemplate) => { + return customInstance({ + url: `/templates/statuschecks`, + method: 'post', + headers: { 'Content-Type': 'application/json' }, + data: typesStatusCheckTemplate, + }) +} + +export type PostTemplatesStatuschecksMutationResult = NonNullable>> +export type PostTemplatesStatuschecksMutationBody = TypesStatusCheckTemplate +export type PostTemplatesStatuschecksMutationError = UtilsAPIError + +export const usePostTemplatesStatuschecks = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { data: TypesStatusCheckTemplate }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction< + Awaited>, + { data: TypesStatusCheckTemplate } + > = (props) => { + const { data } = props ?? {} + + return postTemplatesStatuschecks(data) + } + + return useMutation< + Awaited>, + TError, + { data: TypesStatusCheckTemplate }, + TContext + >(mutationFn, mutationOptions) +} + +/** + * Delete the status check template by namespaced name. + * @summary Delete a status check template. + */ +export const deleteTemplatesStatuschecksStatuscheck = (params: DeleteTemplatesStatuschecksStatuscheckParams) => { + return customInstance({ url: `/templates/statuschecks/statuscheck`, method: 'delete', params }) +} + +export type DeleteTemplatesStatuschecksStatuscheckMutationResult = NonNullable< + Awaited> +> + +export type DeleteTemplatesStatuschecksStatuscheckMutationError = UtilsAPIError + +export const useDeleteTemplatesStatuschecksStatuscheck = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { params: DeleteTemplatesStatuschecksStatuscheckParams }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction< + Awaited>, + { params: DeleteTemplatesStatuschecksStatuscheckParams } + > = (props) => { + const { params } = props ?? {} + + return deleteTemplatesStatuschecksStatuscheck(params) + } + + return useMutation< + Awaited>, + TError, + { params: DeleteTemplatesStatuschecksStatuscheckParams }, + TContext + >(mutationFn, mutationOptions) +} + +/** + * Get the status check template's detail by namespaced name. + * @summary Get a status check template. + */ +export const getTemplatesStatuschecksStatuscheck = ( + params: GetTemplatesStatuschecksStatuscheckParams, + signal?: AbortSignal +) => { + return customInstance({ + url: `/templates/statuschecks/statuscheck`, + method: 'get', + params, + signal, + }) +} + +export const getGetTemplatesStatuschecksStatuscheckQueryKey = (params: GetTemplatesStatuschecksStatuscheckParams) => [ + `/templates/statuschecks/statuscheck`, + ...(params ? [params] : []), +] + +export type GetTemplatesStatuschecksStatuscheckQueryResult = NonNullable< + Awaited> +> +export type GetTemplatesStatuschecksStatuscheckQueryError = UtilsAPIError + +export const useGetTemplatesStatuschecksStatuscheck = < + TData = Awaited>, + TError = UtilsAPIError +>( + params: GetTemplatesStatuschecksStatuscheckParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetTemplatesStatuschecksStatuscheckQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => + getTemplatesStatuschecksStatuscheck(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Update a status check template by namespaced name. + * @summary Update a status check template. + */ +export const putTemplatesStatuschecksStatuscheck = (typesStatusCheckTemplate: TypesStatusCheckTemplate) => { + return customInstance({ + url: `/templates/statuschecks/statuscheck`, + method: 'put', + headers: { 'Content-Type': 'application/json' }, + data: typesStatusCheckTemplate, + }) +} + +export type PutTemplatesStatuschecksStatuscheckMutationResult = NonNullable< + Awaited> +> +export type PutTemplatesStatuschecksStatuscheckMutationBody = TypesStatusCheckTemplate +export type PutTemplatesStatuschecksStatuscheckMutationError = UtilsAPIError + +export const usePutTemplatesStatuschecksStatuscheck = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { data: TypesStatusCheckTemplate }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction< + Awaited>, + { data: TypesStatusCheckTemplate } + > = (props) => { + const { data } = props ?? {} + + return putTemplatesStatuschecksStatuscheck(data) + } + + return useMutation< + Awaited>, + TError, + { data: TypesStatusCheckTemplate }, + TContext + >(mutationFn, mutationOptions) +} + +/** + * List workflows from Kubernetes cluster. + * @summary List workflows from Kubernetes cluster. + */ +export const getWorkflows = (params?: GetWorkflowsParams, signal?: AbortSignal) => { + return customInstance({ url: `/workflows`, method: 'get', params, signal }) +} + +export const getGetWorkflowsQueryKey = (params?: GetWorkflowsParams) => [`/workflows`, ...(params ? [params] : [])] + +export type GetWorkflowsQueryResult = NonNullable>> +export type GetWorkflowsQueryError = UtilsAPIError + +export const useGetWorkflows = >, TError = UtilsAPIError>( + params?: GetWorkflowsParams, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetWorkflowsQueryKey(params) + + const queryFn: QueryFunction>> = ({ signal }) => getWorkflows(params, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Create a new workflow. + * @summary Create a new workflow. + */ +export const postWorkflows = (v1alpha1WorkflowBody: V1alpha1WorkflowBody) => { + return customInstance({ + url: `/workflows`, + method: 'post', + headers: { 'Content-Type': 'application/json' }, + data: v1alpha1WorkflowBody, + }) +} + +export type PostWorkflowsMutationResult = NonNullable>> +export type PostWorkflowsMutationBody = V1alpha1WorkflowBody +export type PostWorkflowsMutationError = UtilsAPIError + +export const usePostWorkflows = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { data: V1alpha1WorkflowBody }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { data: V1alpha1WorkflowBody }> = ( + props + ) => { + const { data } = props ?? {} + + return postWorkflows(data) + } + + return useMutation>, TError, { data: V1alpha1WorkflowBody }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Delete the specified workflow. + * @summary Delete the specified workflow. + */ +export const deleteWorkflowsUid = (uid: string) => { + return customInstance({ url: `/workflows/${uid}`, method: 'delete' }) +} + +export type DeleteWorkflowsUidMutationResult = NonNullable>> + +export type DeleteWorkflowsUidMutationError = UtilsAPIError + +export const useDeleteWorkflowsUid = (options?: { + mutation?: UseMutationOptions>, TError, { uid: string }, TContext> +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction>, { uid: string }> = (props) => { + const { uid } = props ?? {} + + return deleteWorkflowsUid(uid) + } + + return useMutation>, TError, { uid: string }, TContext>( + mutationFn, + mutationOptions + ) +} + +/** + * Get detailed information about the specified workflow. If that object is not existed in kubernetes, it will only return ths persisted data in the database. + * @summary Get detailed information about the specified workflow. + */ +export const getWorkflowsUid = (uid: string, signal?: AbortSignal) => { + return customInstance({ url: `/workflows/${uid}`, method: 'get', signal }) +} + +export const getGetWorkflowsUidQueryKey = (uid: string) => [`/workflows/${uid}`] + +export type GetWorkflowsUidQueryResult = NonNullable>> +export type GetWorkflowsUidQueryError = UtilsAPIError + +export const useGetWorkflowsUid = >, TError = UtilsAPIError>( + uid: string, + options?: { query?: UseQueryOptions>, TError, TData> } +): UseQueryResult & { queryKey: QueryKey } => { + const { query: queryOptions } = options ?? {} + + const queryKey = queryOptions?.queryKey ?? getGetWorkflowsUidQueryKey(uid) + + const queryFn: QueryFunction>> = ({ signal }) => + getWorkflowsUid(uid, signal) + + const query = useQuery>, TError, TData>({ + queryKey, + queryFn, + enabled: !!uid, + retry: 1, + retryDelay: 3000, + ...queryOptions, + }) as UseQueryResult & { queryKey: QueryKey } + + query.queryKey = queryKey + + return query +} + +/** + * Update a workflow. + * @summary Update a workflow. + */ +export const putWorkflowsUid = (uid: string, v1alpha1WorkflowBody: V1alpha1WorkflowBody) => { + return customInstance({ + url: `/workflows/${uid}`, + method: 'put', + headers: { 'Content-Type': 'application/json' }, + data: v1alpha1WorkflowBody, + }) +} + +export type PutWorkflowsUidMutationResult = NonNullable>> +export type PutWorkflowsUidMutationBody = V1alpha1WorkflowBody +export type PutWorkflowsUidMutationError = UtilsAPIError + +export const usePutWorkflowsUid = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { uid: string; data: V1alpha1WorkflowBody }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction< + Awaited>, + { uid: string; data: V1alpha1WorkflowBody } + > = (props) => { + const { uid, data } = props ?? {} + + return putWorkflowsUid(uid, data) + } + + return useMutation< + Awaited>, + TError, + { uid: string; data: V1alpha1WorkflowBody }, + TContext + >(mutationFn, mutationOptions) +} + +/** + * Parse the rendered task back to the original request + * @summary Parse the rendered task back to the original request + */ +export const postWorkflowsParseTaskHttp = (v1alpha1TemplateBody: V1alpha1TemplateBody) => { + return customInstance({ + url: `/workflows/parse-task/http`, + method: 'post', + headers: { 'Content-Type': 'application/json' }, + data: v1alpha1TemplateBody, + }) +} + +export type PostWorkflowsParseTaskHttpMutationResult = NonNullable< + Awaited> +> +export type PostWorkflowsParseTaskHttpMutationBody = V1alpha1TemplateBody +export type PostWorkflowsParseTaskHttpMutationError = UtilsAPIError + +export const usePostWorkflowsParseTaskHttp = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { data: V1alpha1TemplateBody }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction< + Awaited>, + { data: V1alpha1TemplateBody } + > = (props) => { + const { data } = props ?? {} + + return postWorkflowsParseTaskHttp(data) + } + + return useMutation< + Awaited>, + TError, + { data: V1alpha1TemplateBody }, + TContext + >(mutationFn, mutationOptions) +} + +/** + * Render a task which sends HTTP request + * @summary Render a task which sends HTTP request + */ +export const postWorkflowsRenderTaskHttp = (curlRequestForm: CurlRequestForm) => { + return customInstance({ + url: `/workflows/render-task/http`, + method: 'post', + headers: { 'Content-Type': 'application/json' }, + data: curlRequestForm, + }) +} + +export type PostWorkflowsRenderTaskHttpMutationResult = NonNullable< + Awaited> +> +export type PostWorkflowsRenderTaskHttpMutationBody = CurlRequestForm +export type PostWorkflowsRenderTaskHttpMutationError = UtilsAPIError + +export const usePostWorkflowsRenderTaskHttp = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { data: CurlRequestForm }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction< + Awaited>, + { data: CurlRequestForm } + > = (props) => { + const { data } = props ?? {} + + return postWorkflowsRenderTaskHttp(data) + } + + return useMutation< + Awaited>, + TError, + { data: CurlRequestForm }, + TContext + >(mutationFn, mutationOptions) +} + +/** + * Validate the given template is a valid rendered HTTP Task + * @summary Validate the given template is a valid rendered HTTP Task + */ +export const postWorkflowsValidateTaskHttp = (v1alpha1TemplateBody: V1alpha1TemplateBody) => { + return customInstance({ + url: `/workflows/validate-task/http`, + method: 'post', + headers: { 'Content-Type': 'application/json' }, + data: v1alpha1TemplateBody, + }) +} + +export type PostWorkflowsValidateTaskHttpMutationResult = NonNullable< + Awaited> +> +export type PostWorkflowsValidateTaskHttpMutationBody = V1alpha1TemplateBody +export type PostWorkflowsValidateTaskHttpMutationError = UtilsAPIError + +export const usePostWorkflowsValidateTaskHttp = (options?: { + mutation?: UseMutationOptions< + Awaited>, + TError, + { data: V1alpha1TemplateBody }, + TContext + > +}) => { + const { mutation: mutationOptions } = options ?? {} + + const mutationFn: MutationFunction< + Awaited>, + { data: V1alpha1TemplateBody } + > = (props) => { + const { data } = props ?? {} + + return postWorkflowsValidateTaskHttp(data) + } + + return useMutation< + Awaited>, + TError, + { data: V1alpha1TemplateBody }, + TContext + >(mutationFn, mutationOptions) +} diff --git a/ui/app/src/pages/Archives/Single.tsx b/ui/app/src/pages/Archives/Single.tsx new file mode 100644 index 0000000000..28ee17293f --- /dev/null +++ b/ui/app/src/pages/Archives/Single.tsx @@ -0,0 +1,120 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import loadable from '@loadable/component' +import { Box, Grid, Grow } from '@mui/material' +import yaml from 'js-yaml' +import { useGetArchivesSchedulesUid, useGetArchivesUid, useGetArchivesWorkflowsUid, useGetEvents } from 'openapi' +import { TypesArchiveDetail } from 'openapi/index.schemas' +import { useState } from 'react' +import { useParams } from 'react-router-dom' + +import Loading from '@ui/mui-extends/esm/Loading' +import Paper from '@ui/mui-extends/esm/Paper' +import PaperTop from '@ui/mui-extends/esm/PaperTop' +import Space from '@ui/mui-extends/esm/Space' + +import EventsTimeline from 'components/EventsTimeline' +import Helmet from 'components/Helmet' +import ObjectConfiguration from 'components/ObjectConfiguration' +import i18n from 'components/T' + +import { useQuery } from 'lib/hooks' + +const YAMLEditor = loadable(() => import('components/YAMLEditor')) + +const Single = () => { + const { uuid } = useParams() + const query = useQuery() + let kind = query.get('kind') || 'experiment' + let useGetArchives = + kind === 'workflow' + ? useGetArchivesWorkflowsUid + : kind === 'schedule' + ? useGetArchivesSchedulesUid + : useGetArchivesUid + + const [archive, setArchive] = useState() + + const { isLoading: loadingArchives } = useGetArchives(uuid!, { + query: { onSuccess: setArchive }, + }) + const { data: events, isLoading: loadingEvents } = useGetEvents( + { + object_id: uuid, + limit: 999, + }, + { query: { enabled: kind !== 'workflow' } } + ) + const loading = kind === 'workflow' ? loadingArchives : loadingArchives && loadingEvents + + const YAML = () => ( + `calc(100vh - 56px - ${theme.spacing(18)})` : 600, p: 0 }}> + {archive && ( + + + + + + + )} + + ) + + return ( + <> + +
    + {archive && } + {kind !== 'workflow' ? ( + + {archive && ( + + + + )} + + + + + + + {events && } + + + + + + + + + ) : ( + + )} +
    + + + {loading && } + + ) +} + +export default Single diff --git a/ui/app/src/pages/Archives/index.tsx b/ui/app/src/pages/Archives/index.tsx new file mode 100644 index 0000000000..a8ceab7006 --- /dev/null +++ b/ui/app/src/pages/Archives/index.tsx @@ -0,0 +1,298 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import CloseIcon from '@mui/icons-material/Close' +import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined' +import FilterListIcon from '@mui/icons-material/FilterList' +import PlaylistAddCheckIcon from '@mui/icons-material/PlaylistAddCheck' +import TabContext from '@mui/lab/TabContext' +import TabList from '@mui/lab/TabList' +import { Box, Button, Checkbox, Typography, styled } from '@mui/material' +import Tab from '@mui/material/Tab' +import _ from 'lodash' +import { + useDeleteArchives, + useDeleteArchivesSchedules, + useDeleteArchivesSchedulesUid, + useDeleteArchivesUid, + useDeleteArchivesWorkflows, + useDeleteArchivesWorkflowsUid, + useGetArchives, + useGetArchivesSchedules, + useGetArchivesWorkflows, +} from 'openapi' +import { + DeleteArchivesWorkflowsParams, + DeleteExperimentsParams, + DeleteSchedulesParams, + TypesArchive, +} from 'openapi/index.schemas' +import { useState } from 'react' +import { useIntl } from 'react-intl' +import { useNavigate } from 'react-router-dom' +import { FixedSizeList as RWList, ListChildComponentProps as RWListChildComponentProps } from 'react-window' + +import Loading from '@ui/mui-extends/esm/Loading' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch } from 'store' + +import { Confirm, setAlert, setConfirm } from 'slices/globalStatus' + +import NotFound from 'components/NotFound' +import ObjectListItem from 'components/ObjectListItem' +import i18n from 'components/T' + +import { transByKind } from 'lib/byKind' +import { useQuery } from 'lib/hooks' + +const StyledCheckBox = styled(Checkbox)({ + position: 'relative', + left: -11, + paddingRight: 0, + '&:hover': { + background: 'none !important', + }, +}) + +type PanelType = 'workflow' | 'schedule' | 'experiment' + +export default function Archives() { + const navigate = useNavigate() + const intl = useIntl() + const query = useQuery() + let kind = query.get('kind') || 'experiment' + + const dispatch = useStoreDispatch() + + const [panel, setPanel] = useState(kind as PanelType) + const [archives, setArchives] = useState([]) + const [batch, setBatch] = useState>({}) + const batchLength = Object.keys(batch).length + const isBatchEmpty = batchLength === 0 + + const { isLoading: loading1, refetch: refetchWorkflows } = useGetArchivesWorkflows(undefined, { + query: { enabled: kind === 'workflow', onSuccess: setArchives }, + }) + const { isLoading: loading2, refetch: refetchSchedules } = useGetArchivesSchedules(undefined, { + query: { enabled: kind === 'schedule', onSuccess: setArchives }, + }) + const { isLoading: loading3, refetch: refetchExperiments } = useGetArchives(undefined, { + query: { enabled: kind === 'experiment', onSuccess: setArchives }, + }) + const loading = kind === 'workflow' ? loading1 : kind === 'schedule' ? loading2 : loading3 + function refetchByKind() { + switch (kind) { + case 'workflow': + refetchWorkflows() + + break + case 'schedule': + refetchSchedules() + + break + default: + refetchExperiments() + } + } + const { mutateAsync: deleteWorkflows } = useDeleteArchivesWorkflows() + const { mutateAsync: deleteSchedules } = useDeleteArchivesSchedules() + const { mutateAsync: deleteExperiments } = useDeleteArchives() + const { mutateAsync: deleteWorkflowsByUUID } = useDeleteArchivesWorkflowsUid() + const { mutateAsync: deleteSchedulesByUUID } = useDeleteArchivesSchedulesUid() + const { mutateAsync: deleteExperimentsByUUID } = useDeleteArchivesUid() + + const handleSelect = (selected: Confirm) => dispatch(setConfirm(selected)) + const onSelect = (selected: Confirm) => + dispatch( + setConfirm({ + title: selected.title, + description: selected.description, + handle: handleAction(selected.action, selected.uuid), + }) + ) + + const handleAction = (action: string, uuid?: uuid) => () => { + let actionFunc + let arg: + | { uid: string } + | { params: DeleteArchivesWorkflowsParams | DeleteExperimentsParams | DeleteSchedulesParams } + | undefined + + switch (action) { + case 'delete': + switch (kind) { + case 'workflow': + actionFunc = deleteWorkflowsByUUID + break + case 'schedule': + actionFunc = deleteSchedulesByUUID + break + case 'experiment': + default: + actionFunc = deleteExperimentsByUUID + break + } + arg = { uid: uuid! } + + break + case 'deleteMulti': + action = 'delete' + switch (kind) { + case 'workflow': + actionFunc = deleteWorkflows + break + case 'schedule': + actionFunc = deleteSchedules + break + case 'experiment': + default: + actionFunc = deleteExperiments + break + } + arg = { + params: { + uids: Object.keys(batch) + .filter((d) => batch[d] === true) + .join(','), + }, + } + setBatch({}) + + break + } + + if (actionFunc) { + actionFunc(arg as any) + .then(() => { + dispatch( + setAlert({ + type: 'success', + message: i18n(`confirm.success.${action}`, intl), + }) + ) + + refetchByKind() + }) + .catch(console.error) + } + } + + const handleBatchSelect = () => setBatch(isBatchEmpty ? { [archives[0].uid!]: true } : {}) + + const handleBatchSelectAll = () => + setBatch( + batchLength <= archives.length + ? archives.reduce>((acc, d) => { + acc[d.uid!] = true + + return acc + }, {}) + : {} + ) + + const handleBatchDelete = () => + handleSelect({ + title: i18n('archives.deleteMulti', intl), + description: i18n('archives.deleteDesc', intl), + handle: handleAction('deleteMulti'), + }) + + const onCheckboxChange = (uuid: uuid) => (e: React.ChangeEvent) => { + setBatch({ + ...batch, + [uuid]: e.target.checked, + }) + } + + const Row = ({ data, index, style }: RWListChildComponentProps) => ( + + {!isBatchEmpty && ( + + )} + + + + + ) + + const onTabChange = (_: any, newValue: PanelType) => { + navigate(`/archives?kind=${newValue}`) + setPanel(newValue) + } + + return ( + + + + + + + + + + + + {!isBatchEmpty && ( + <> + + + + )} + + + {archives.length > 0 && + Object.entries(_.groupBy(archives, 'kind')).map(([kind, archivesByKind]) => ( + + {transByKind(kind as any)} + 3 ? 300 : archivesByKind.length * 70} + itemCount={archivesByKind.length} + itemSize={70} + itemData={archivesByKind} + > + {Row} + + + ))} + + {!loading && archives.length === 0 && ( + + {i18n('archives.notFound')} + + )} + + {loading && } + + ) +} diff --git a/ui/app/src/pages/Dashboard/Predefined.tsx b/ui/app/src/pages/Dashboard/Predefined.tsx new file mode 100644 index 0000000000..ac1d176e7d --- /dev/null +++ b/ui/app/src/pages/Dashboard/Predefined.tsx @@ -0,0 +1,203 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import loadable from '@loadable/component' +import { Box, Button, Card, Modal, Typography } from '@mui/material' +import { makeStyles } from '@mui/styles' +import { Ace } from 'ace-builds' +import clsx from 'clsx' +import yaml from 'js-yaml' +import { postExperiments, postSchedules } from 'openapi' +import { useEffect, useRef, useState } from 'react' +import { useIntl } from 'react-intl' + +import Paper from '@ui/mui-extends/esm/Paper' +import PaperTop from '@ui/mui-extends/esm/PaperTop' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch } from 'store' + +import { setAlert, setConfirm } from 'slices/globalStatus' + +import i18n from 'components/T' +import YAML from 'components/YAML' + +import { iconByKind } from 'lib/byKind' +import { PreDefinedValue, getDB } from 'lib/idb' + +const YAMLEditor = loadable(() => import('components/YAMLEditor')) + +const useStyles = makeStyles((theme) => ({ + card: { + flex: '0 0 240px', + cursor: 'pointer', + '&:hover': { + background: theme.palette.action.hover, + }, + }, + addCard: { + width: 210, + }, + editorPaperWrapper: { + position: 'absolute', + top: '50%', + left: '50%', + width: '75vw', + height: '90vh', + padding: 0, + transform: 'translate(-50%, -50%)', + [theme.breakpoints.down('lg')]: { + width: '90vw', + }, + }, +})) + +const Predefined = () => { + const classes = useStyles() + + const intl = useIntl() + + const dispatch = useStoreDispatch() + + const idb = useRef(getDB()) + + const [yamlEditor, setYAMLEditor] = useState() + const [editorOpen, seteditorOpen] = useState(false) + const [experiment, setExperiment] = useState() + const [experiments, setExperiments] = useState([]) + + async function getExperiments() { + setExperiments(await (await idb.current).getAll('predefined')) + } + + useEffect(() => { + getExperiments() + }, []) + + const saveExperiment = async (_y: any) => { + const db = await idb.current + + const y: any = yaml.load(_y) + + await db.put('predefined', { + name: y.metadata.name, + kind: y.kind, + yaml: y, + }) + + getExperiments() + } + + const onModalOpen = (exp: PreDefinedValue) => () => { + seteditorOpen(true) + setExperiment(exp) + } + const onModalClose = () => seteditorOpen(false) + + const handleApplyExperiment = () => { + const exp: any = yaml.load(yamlEditor!.getValue()) + + const isSchedule = exp['kind'] === 'Schedule' + const action = isSchedule ? (schedule: any) => postSchedules(schedule) : (chaos: any) => postExperiments(chaos) + + action(exp) + .then(() => { + seteditorOpen(false) + dispatch( + setAlert({ + type: 'success', + message: i18n('confirm.success.create', intl), + }) + ) + }) + .catch(console.error) + } + + const handleDeleteConfirm = () => { + dispatch( + setConfirm({ + title: `${i18n('common.delete', intl)} ${experiment!.name}`, + description: i18n('common.deleteDesc', intl), + handle: handleDeleteExperiment, + }) + ) + } + + const handleDeleteExperiment = async () => { + const db = await idb.current + + await db.delete('predefined', experiment!.name) + + getExperiments() + seteditorOpen(false) + dispatch( + setAlert({ + type: 'success', + message: i18n('confirm.success.delete', intl), + }) + ) + } + + return ( + <> + + + {experiments.map((d) => ( + + + + {iconByKind(d.kind)} + + + {d.name} + + + + ))} + + +
    + + {experiment && ( + + + + + + + + + + + + + + )} + +
    +
    + + ) +} + +export default Predefined diff --git a/ui/app/src/pages/Dashboard/TotalStatus.tsx b/ui/app/src/pages/Dashboard/TotalStatus.tsx new file mode 100644 index 0000000000..9df11801c1 --- /dev/null +++ b/ui/app/src/pages/Dashboard/TotalStatus.tsx @@ -0,0 +1,108 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Box, BoxProps } from '@mui/material' +import { useTheme } from '@mui/material/styles' +import { PropertyAccessor } from '@nivo/core' +import { ComputedDatum, PieTooltipProps, ResponsivePie } from '@nivo/pie' +import { useGetExperimentsState } from 'openapi' +import { StatusAllChaosStatus } from 'openapi/index.schemas' +import { useState } from 'react' +import { useIntl } from 'react-intl' + +import NotFound from 'components/NotFound' +import i18n from 'components/T' + +interface SingleData { + id: keyof StatusAllChaosStatus + label: string + value: number +} + +const TotalStatus: React.FC = (props) => { + const intl = useIntl() + const theme = useTheme() + + const [state, setState] = useState([]) + + const arcLinkLabel: PropertyAccessor, string> = (d) => + d.value + ' ' + i18n(`status.${d.id}`, intl) + + const tooltip = ({ datum }: PieTooltipProps) => ( + + + {(datum.value < 1 ? 0 : datum.value) + ' ' + i18n(`status.${datum.id}`, intl)} + + ) + + useGetExperimentsState(undefined, { + query: { + onSuccess(data) { + setState( + (Object.entries(data) as [keyof StatusAllChaosStatus, number][]).map(([k, v]) => ({ + id: k, + label: i18n(`status.${k}`, intl), + value: v === 0 ? 0.01 : v, + })) + ) + }, + }, + }) + + return ( + + {state.some((d) => d.value >= 1) ? ( + + ) : ( + {i18n('experiments.notFound')} + )} + + ) +} + +export default TotalStatus diff --git a/ui/app/src/pages/Dashboard/Welcome.tsx b/ui/app/src/pages/Dashboard/Welcome.tsx new file mode 100644 index 0000000000..e0149bbb0f --- /dev/null +++ b/ui/app/src/pages/Dashboard/Welcome.tsx @@ -0,0 +1,109 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import AccountTreeOutlinedIcon from '@mui/icons-material/AccountTreeOutlined' +import ScheduleIcon from '@mui/icons-material/Schedule' +import ScienceOutlinedIcon from '@mui/icons-material/ScienceOutlined' +import { Button, Grid } from '@mui/material' +import { makeStyles } from '@mui/styles' +import { useTour } from '@reactour/tour' +import { Link } from 'react-router-dom' + +import Paper from '@ui/mui-extends/esm/Paper' +import PaperTop from '@ui/mui-extends/esm/PaperTop' +import Space from '@ui/mui-extends/esm/Space' + +import i18n from 'components/T' + +const useStyles = makeStyles((theme) => ({ + space: { + width: '75%', + [theme.breakpoints.down('md')]: { + width: 'unset', + }, + }, +})) + +const Welcome = () => { + const classes = useStyles() + + const { setIsOpen } = useTour() + + return ( + + + + + + + + + + + + + + + + + + + + + + + ) +} + +export default Welcome diff --git a/ui/app/src/pages/Dashboard/index.tsx b/ui/app/src/pages/Dashboard/index.tsx new file mode 100644 index 0000000000..11b7ff1df3 --- /dev/null +++ b/ui/app/src/pages/Dashboard/index.tsx @@ -0,0 +1,205 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import AccountTreeOutlinedIcon from '@mui/icons-material/AccountTreeOutlined' +import ArrowBackOutlinedIcon from '@mui/icons-material/ArrowBackOutlined' +import ArrowForwardOutlinedIcon from '@mui/icons-material/ArrowForwardOutlined' +import ScheduleIcon from '@mui/icons-material/Schedule' +import ScienceOutlinedIcon from '@mui/icons-material/ScienceOutlined' +import { Box, Grid, Grow, IconButton, Typography } from '@mui/material' +import { useTheme } from '@mui/material/styles' +import { TourProvider } from '@reactour/tour' +import { useGetEvents, useGetExperiments, useGetSchedules, useGetWorkflows } from 'openapi' +import type { ReactChild } from 'react' + +import Paper from '@ui/mui-extends/esm/Paper' +import PaperTop from '@ui/mui-extends/esm/PaperTop' + +import EventsChart from 'components/EventsChart' +import EventsTimeline from 'components/EventsTimeline' +import i18n from 'components/T' + +import Predefined from './Predefined' +import TotalStatus from './TotalStatus' +import Welcome from './Welcome' + +const NumPanel: React.FC<{ title: ReactChild; num?: number; background: ReactChild }> = ({ + title, + num, + background, +}) => ( + + + + + {num} + + + + {background} + + +) + +export default function Dashboard() { + const theme = useTheme() + const steps = [ + { + selector: '.tutorial-dashboard', + content: i18n('dashboard.tutorial.steps.dashboard'), + }, + { + selector: '.tutorial-workflows', + content: i18n('dashboard.tutorial.steps.workflows'), + }, + { + selector: '.tutorial-schedules', + content: i18n('dashboard.tutorial.steps.schedules'), + }, + { + selector: '.tutorial-experiments', + content: i18n('dashboard.tutorial.steps.experiments'), + }, + { + selector: '.tutorial-events', + content: i18n('dashboard.tutorial.steps.events'), + }, + { + selector: '.tutorial-archives', + content: i18n('dashboard.tutorial.steps.archives'), + }, + { + selector: '.tutorial-newW', + content: i18n('dashboard.tutorial.steps.newW'), + }, + { + selector: '.tutorial-newS', + content: i18n('dashboard.tutorial.steps.newS'), + }, + { + selector: '.tutorial-newE', + content: i18n('dashboard.tutorial.steps.newE'), + }, + { + selector: '.tutorial-search', + content: i18n('dashboard.tutorial.steps.search'), + }, + { + selector: '.tutorial-namespace', + content: i18n('dashboard.tutorial.steps.namespace'), + }, + { + selector: '.tutorial-predefined', + content: i18n('dashboard.tutorial.steps.predefined'), + }, + { + selector: '.tutorial-end', + content: i18n('dashboard.tutorial.steps.end'), + }, + ] + + const { data: experiments } = useGetExperiments() + const { data: schedules } = useGetSchedules() + const { data: workflows } = useGetWorkflows() + const { data: events } = useGetEvents() + + return ( + ({ + ...base, + '--reactour-accent': theme.palette.primary.main, + background: theme.palette.background.default, + borderRadius: theme.shape.borderRadius, + }), + }} + prevButton={({ setCurrentStep }) => ( + setCurrentStep((s) => s + 1)}> + + + )} + nextButton={({ setCurrentStep }) => ( + setCurrentStep((s) => s + 1)}> + + + )} + showCloseButton={false} + > + + + + + } + /> + + + } + /> + + + } + /> + + + + + + + + + + + + + + {events && } + + + + + + + + + {experiments && 0 ? 300 : '100%'} />} + + + + + + {events && } + + + + + + + ) +} diff --git a/ui/app/src/pages/Events/index.tsx b/ui/app/src/pages/Events/index.tsx new file mode 100644 index 0000000000..b64d4b0d1f --- /dev/null +++ b/ui/app/src/pages/Events/index.tsx @@ -0,0 +1,48 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Grow, Typography } from '@mui/material' +import { useGetEvents } from 'openapi' + +import Loading from '@ui/mui-extends/esm/Loading' + +import EventsTable from 'components/EventsTable' +import NotFound from 'components/NotFound' +import i18n from 'components/T' + +export default function Events() { + const { data: events, isLoading: loading } = useGetEvents() + + return ( + <> + {events && events.length > 0 && ( + +
    + +
    +
    + )} + + {!loading && events?.length === 0 && ( + + {i18n('events.notFound')} + + )} + + {loading && } + + ) +} diff --git a/ui/app/src/pages/Experiments/New.tsx b/ui/app/src/pages/Experiments/New.tsx new file mode 100644 index 0000000000..1367318103 --- /dev/null +++ b/ui/app/src/pages/Experiments/New.tsx @@ -0,0 +1,28 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Grid } from '@mui/material' +import NewExperiment from 'components/NewExperimentNext' + +const New = () => ( + + + + + +) + +export default New diff --git a/ui/app/src/pages/Experiments/Single.tsx b/ui/app/src/pages/Experiments/Single.tsx new file mode 100644 index 0000000000..a63ed59071 --- /dev/null +++ b/ui/app/src/pages/Experiments/Single.tsx @@ -0,0 +1,215 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import loadable from '@loadable/component' +import ArchiveOutlinedIcon from '@mui/icons-material/ArchiveOutlined' +import PauseCircleOutlineIcon from '@mui/icons-material/PauseCircleOutline' +import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline' +import Alert from '@mui/lab/Alert' +import { Box, Button, Grid, Grow } from '@mui/material' +import yaml from 'js-yaml' +import { + useDeleteExperimentsUid, + useGetEvents, + useGetExperimentsUid, + usePutExperimentsPauseUid, + usePutExperimentsStartUid, +} from 'openapi' +import { useIntl } from 'react-intl' +import { useNavigate, useParams } from 'react-router-dom' + +import Loading from '@ui/mui-extends/esm/Loading' +import Paper from '@ui/mui-extends/esm/Paper' +import PaperTop from '@ui/mui-extends/esm/PaperTop' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch } from 'store' + +import { setAlert, setConfirm } from 'slices/globalStatus' + +import EventsTimeline from 'components/EventsTimeline' +import Helmet from 'components/Helmet' +import ObjectConfiguration from 'components/ObjectConfiguration' +import i18n from 'components/T' + +const YAMLEditor = loadable(() => import('components/YAMLEditor')) + +export default function Single() { + const navigate = useNavigate() + const { uuid } = useParams() + + const intl = useIntl() + + const dispatch = useStoreDispatch() + + const { data: experiment, isLoading: isLoading1, refetch } = useGetExperimentsUid(uuid!) + const { data: events, isLoading: isLoading2 } = useGetEvents({ object_id: uuid, limit: 999 }) + const loading = isLoading1 || isLoading2 + const { mutateAsync: deleteExperiments } = useDeleteExperimentsUid() + const { mutateAsync: pauseExperiments } = usePutExperimentsPauseUid() + const { mutateAsync: startExperiments } = usePutExperimentsStartUid() + + const handleSelect = (action: string) => () => { + switch (action) { + case 'archive': + dispatch( + setConfirm({ + title: `${i18n('archives.single', intl)} ${experiment!.name}`, + description: i18n('experiments.deleteDesc', intl), + handle: handleAction('archive'), + }) + ) + + break + case 'pause': + dispatch( + setConfirm({ + title: `${i18n('common.pause', intl)} ${experiment!.name}`, + description: i18n('experiments.pauseDesc', intl), + handle: handleAction('pause'), + }) + ) + + break + case 'start': + dispatch( + setConfirm({ + title: `${i18n('common.start', intl)} ${experiment!.name}`, + description: i18n('experiments.startDesc', intl), + handle: handleAction('start'), + }) + ) + + break + } + } + + const handleAction = (action: string) => () => { + let actionFunc + + switch (action) { + case 'archive': + actionFunc = deleteExperiments + + break + case 'pause': + actionFunc = pauseExperiments + + break + case 'start': + actionFunc = startExperiments + + break + default: + break + } + + if (actionFunc) { + actionFunc({ uid: uuid! }) + .then(() => { + dispatch( + setAlert({ + type: 'success', + message: i18n(`confirm.success.${action}`, intl), + }) + ) + + if (action === 'archive') { + navigate('/experiments') + } + + if (action === 'pause' || action === 'start') { + refetch() + } + }) + .catch(console.error) + } + } + + return ( + <> + +
    + {experiment && } + + + + {experiment?.status === 'paused' ? ( + + ) : experiment?.status !== 'finished' ? ( + + ) : null} + + + {experiment?.failed_message && ( + + An error occurred: {experiment.failed_message} + + )} + + {experiment && } + + + + + + + {events && } + + + + + + {experiment && ( + + + + + + + )} + + + + +
    +
    + + {loading && } + + ) +} diff --git a/ui/app/src/pages/Experiments/index.tsx b/ui/app/src/pages/Experiments/index.tsx new file mode 100644 index 0000000000..b8178f59d2 --- /dev/null +++ b/ui/app/src/pages/Experiments/index.tsx @@ -0,0 +1,230 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import AddIcon from '@mui/icons-material/Add' +import ArchiveOutlinedIcon from '@mui/icons-material/ArchiveOutlined' +import CloseIcon from '@mui/icons-material/Close' +import FilterListIcon from '@mui/icons-material/FilterList' +import PlaylistAddCheckIcon from '@mui/icons-material/PlaylistAddCheck' +import { Box, Button, Checkbox, Typography, styled } from '@mui/material' +import _ from 'lodash' +import { + useDeleteExperiments, + useDeleteExperimentsUid, + useGetExperiments, + usePutExperimentsPauseUid, + usePutExperimentsStartUid, +} from 'openapi' +import { DeleteExperimentsParams } from 'openapi/index.schemas' +import { useState } from 'react' +import { useIntl } from 'react-intl' +import { useNavigate } from 'react-router-dom' +import { FixedSizeList as RWList, ListChildComponentProps as RWListChildComponentProps } from 'react-window' + +import Loading from '@ui/mui-extends/esm/Loading' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch } from 'store' + +import { Confirm, setAlert, setConfirm } from 'slices/globalStatus' + +import NotFound from 'components/NotFound' +import ObjectListItem from 'components/ObjectListItem' +import i18n from 'components/T' + +import { transByKind } from 'lib/byKind' + +const StyledCheckBox = styled(Checkbox)({ + position: 'relative', + left: -11, + paddingRight: 0, + '&:hover': { + background: 'none !important', + }, +}) + +export default function Experiments() { + const intl = useIntl() + const navigate = useNavigate() + + const dispatch = useStoreDispatch() + + const [batch, setBatch] = useState>({}) + const batchLength = Object.keys(batch).length + const isBatchEmpty = batchLength === 0 + + const { data: experiments, isLoading: loading, refetch } = useGetExperiments() + const { mutateAsync: deleteExperimentsByUUID } = useDeleteExperimentsUid() + const { mutateAsync: deleteExperiments } = useDeleteExperiments() + const { mutateAsync: pauseExperiments } = usePutExperimentsPauseUid() + const { mutateAsync: startExperiments } = usePutExperimentsStartUid() + + const handleSelect = (selected: Confirm) => dispatch(setConfirm(selected)) + const onSelect = (selected: Confirm) => + dispatch( + setConfirm({ + title: selected.title, + description: selected.description, + handle: handleAction(selected.action, selected.uuid), + }) + ) + + const handleAction = (action: string, uuid?: uuid) => () => { + let actionFunc + let arg: { uid: string } | { params: DeleteExperimentsParams } | undefined + + switch (action) { + case 'archive': + actionFunc = deleteExperimentsByUUID + arg = { uid: uuid! } + + break + case 'archiveMulti': + action = 'archive' + actionFunc = deleteExperiments + arg = { params: { uids: Object.keys(batch).join(',') } } + setBatch({}) + + break + case 'pause': + actionFunc = pauseExperiments + arg = { uid: uuid! } + + break + case 'start': + actionFunc = startExperiments + arg = { uid: uuid! } + + break + } + + if (actionFunc) { + actionFunc(arg as any) + .then(() => { + dispatch( + setAlert({ + type: 'success', + message: i18n(`confirm.success.${action}`, intl), + }) + ) + + refetch() + }) + .catch(console.error) + } + } + + const handleBatchSelect = () => setBatch(isBatchEmpty ? { [experiments![0].uid!]: true } : {}) + + const handleBatchSelectAll = () => + setBatch( + batchLength <= experiments!.length + ? experiments!.reduce>((acc, d) => { + acc[d.uid!] = true + + return acc + }, {}) + : {} + ) + + const handleBatchDelete = () => + handleSelect({ + title: i18n('experiments.deleteMulti', intl), + description: i18n('experiments.deleteDesc', intl), + handle: handleAction('archiveMulti'), + }) + + const onCheckboxChange = (uuid: uuid) => (e: React.ChangeEvent) => { + setBatch({ + ...batch, + [uuid]: e.target.checked, + }) + } + + const Row = ({ data, index, style }: RWListChildComponentProps) => ( + + {!isBatchEmpty && ( + + )} + + + + + ) + + return ( + <> + + + + {!isBatchEmpty && ( + <> + + + + )} + + + {experiments && + experiments.length > 0 && + Object.entries(_.groupBy(experiments, 'kind')).map(([kind, experimentsByKind]) => ( + + {transByKind(kind as any)} + 3 ? 300 : experimentsByKind.length * 70} + itemCount={experimentsByKind.length} + itemSize={70} + itemData={experimentsByKind} + > + {Row} + + + ))} + + {!loading && experiments?.length === 0 && ( + + {i18n('experiments.notFound')} + + )} + + {loading && } + + ) +} diff --git a/ui/app/src/pages/Schedules/New.tsx b/ui/app/src/pages/Schedules/New.tsx new file mode 100644 index 0000000000..e760fa8a8b --- /dev/null +++ b/ui/app/src/pages/Schedules/New.tsx @@ -0,0 +1,64 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Grid } from '@mui/material' +import { usePostSchedules } from 'openapi' +import { useIntl } from 'react-intl' +import { useNavigate } from 'react-router-dom' + +import { useStoreDispatch } from 'store' + +import { resetNewExperiment } from 'slices/experiments' +import { setAlert } from 'slices/globalStatus' + +import NewExperiment from 'components/NewExperimentNext' +import i18n from 'components/T' + +const New = () => { + const navigate = useNavigate() + const intl = useIntl() + + const dispatch = useStoreDispatch() + + const { mutateAsync } = usePostSchedules() + + const onSubmit = (parsedValues: any) => { + mutateAsync({ data: parsedValues }) + .then(() => { + dispatch( + setAlert({ + type: 'success', + message: i18n('confirm.success.create', intl), + }) + ) + + dispatch(resetNewExperiment()) + + navigate('/schedules') + }) + .catch(console.error) + } + + return ( + + + + + + ) +} + +export default New diff --git a/ui/app/src/pages/Schedules/Single.tsx b/ui/app/src/pages/Schedules/Single.tsx new file mode 100644 index 0000000000..6bb8b7c3fa --- /dev/null +++ b/ui/app/src/pages/Schedules/Single.tsx @@ -0,0 +1,210 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import loadable from '@loadable/component' +import ArchiveOutlinedIcon from '@mui/icons-material/ArchiveOutlined' +import PauseCircleOutlineIcon from '@mui/icons-material/PauseCircleOutline' +import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline' +import { Box, Button, Grid, Grow } from '@mui/material' +import yaml from 'js-yaml' +import { + useDeleteSchedulesUid, + useGetEvents, + useGetSchedulesUid, + usePutSchedulesPauseUid, + usePutSchedulesStartUid, +} from 'openapi' +import { useIntl } from 'react-intl' +import { useNavigate, useParams } from 'react-router-dom' + +import Loading from '@ui/mui-extends/esm/Loading' +import Paper from '@ui/mui-extends/esm/Paper' +import PaperTop from '@ui/mui-extends/esm/PaperTop' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch } from 'store' + +import { setAlert, setConfirm } from 'slices/globalStatus' + +import EventsTimeline from 'components/EventsTimeline' +import Helmet from 'components/Helmet' +import ObjectConfiguration from 'components/ObjectConfiguration' +import i18n from 'components/T' + +const YAMLEditor = loadable(() => import('components/YAMLEditor')) + +const Single = () => { + const navigate = useNavigate() + const { uuid } = useParams() + + const intl = useIntl() + + const dispatch = useStoreDispatch() + + const { data: schedule, isLoading: isLoading1, refetch } = useGetSchedulesUid(uuid!) + const { data: events, isLoading: isLoading2 } = useGetEvents({ object_id: uuid, limit: 999 }) + const loading = isLoading1 || isLoading2 + const { mutateAsync: deleteSchedules } = useDeleteSchedulesUid() + const { mutateAsync: pauseSchedules } = usePutSchedulesPauseUid() + const { mutateAsync: startSchedules } = usePutSchedulesStartUid() + + const handleSelect = (action: string) => () => { + switch (action) { + case 'archive': + dispatch( + setConfirm({ + title: `${i18n('archives.single', intl)} ${schedule!.name}`, + description: i18n('experiments.deleteDesc', intl), + handle: handleAction('archive'), + }) + ) + + break + case 'pause': + dispatch( + setConfirm({ + title: `${i18n('common.pause', intl)} ${schedule!.name}`, + description: i18n('experiments.pauseDesc', intl), + handle: handleAction('pause'), + }) + ) + + break + case 'start': + dispatch( + setConfirm({ + title: `${i18n('common.start', intl)} ${schedule!.name}`, + description: i18n('experiments.startDesc', intl), + handle: handleAction('start'), + }) + ) + + break + } + } + + const handleAction = (action: string) => () => { + let actionFunc + + switch (action) { + case 'archive': + actionFunc = deleteSchedules + + break + case 'pause': + actionFunc = pauseSchedules + + break + case 'start': + actionFunc = startSchedules + + break + default: + break + } + + if (actionFunc) { + actionFunc({ uid: uuid! }) + .then(() => { + dispatch( + setAlert({ + type: 'success', + message: i18n(`confirm.success.${action}`, intl), + }) + ) + + if (action === 'archive') { + navigate('/schedules') + } + + if (action === 'pause' || action === 'start') { + refetch() + } + }) + .catch(console.error) + } + } + + return ( + <> + +
    + {schedule && } + + + + {schedule?.status === 'paused' ? ( + + ) : schedule?.status !== 'finished' ? ( + + ) : null} + + + {schedule && } + + + + + + + {events && } + + + + + + {schedule && ( + + + + + + + )} + + + + +
    +
    + + {loading && } + + ) +} + +export default Single diff --git a/ui/app/src/pages/Schedules/index.tsx b/ui/app/src/pages/Schedules/index.tsx new file mode 100644 index 0000000000..f981f660e1 --- /dev/null +++ b/ui/app/src/pages/Schedules/index.tsx @@ -0,0 +1,230 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import AddIcon from '@mui/icons-material/Add' +import CloseIcon from '@mui/icons-material/Close' +import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined' +import FilterListIcon from '@mui/icons-material/FilterList' +import PlaylistAddCheckIcon from '@mui/icons-material/PlaylistAddCheck' +import { Box, Button, Checkbox, styled } from '@mui/material' +import { Typography } from '@mui/material' +import _ from 'lodash' +import { + useDeleteSchedules, + useDeleteSchedulesUid, + useGetSchedules, + usePutSchedulesPauseUid, + usePutSchedulesStartUid, +} from 'openapi' +import { DeleteSchedulesParams } from 'openapi/index.schemas' +import { useState } from 'react' +import { useIntl } from 'react-intl' +import { useNavigate } from 'react-router-dom' +import { FixedSizeList as RWList, ListChildComponentProps as RWListChildComponentProps } from 'react-window' + +import Loading from '@ui/mui-extends/esm/Loading' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch } from 'store' + +import { Confirm, setAlert, setConfirm } from 'slices/globalStatus' + +import NotFound from 'components/NotFound' +import ObjectListItem from 'components/ObjectListItem' +import i18n from 'components/T' + +import { transByKind } from 'lib/byKind' + +const StyledCheckBox = styled(Checkbox)({ + position: 'relative', + left: -11, + paddingRight: 0, + '&:hover': { + background: 'none !important', + }, +}) + +const Schedules = () => { + const navigate = useNavigate() + const intl = useIntl() + + const dispatch = useStoreDispatch() + + const [batch, setBatch] = useState>({}) + const batchLength = Object.keys(batch).length + const isBatchEmpty = batchLength === 0 + + const { data: schedules, isLoading: loading, refetch } = useGetSchedules() + const { mutateAsync: deleteSchedulesByUUID } = useDeleteSchedulesUid() + const { mutateAsync: deleteSchedules } = useDeleteSchedules() + const { mutateAsync: pauseSchedules } = usePutSchedulesPauseUid() + const { mutateAsync: startSchedules } = usePutSchedulesStartUid() + + const handleSelect = (selected: Confirm) => dispatch(setConfirm(selected)) + const onSelect = (selected: Confirm) => + dispatch( + setConfirm({ + title: selected.title, + description: selected.description, + handle: handleAction(selected.action, selected.uuid), + }) + ) + + const handleAction = (action: string, uuid?: uuid) => () => { + let actionFunc + let arg: { uid: string } | { params: DeleteSchedulesParams } | undefined + + switch (action) { + case 'archive': + actionFunc = deleteSchedulesByUUID + arg = { uid: uuid! } + + break + case 'archiveMulti': + action = 'archive' + actionFunc = deleteSchedules + arg = { params: { uids: Object.keys(batch).join(',') } } + setBatch({}) + + break + case 'pause': + actionFunc = pauseSchedules + arg = { uid: uuid! } + + break + case 'start': + actionFunc = startSchedules + arg = { uid: uuid! } + + break + default: + break + } + + if (actionFunc) { + actionFunc(arg as any) + .then(() => { + dispatch( + setAlert({ + type: 'success', + message: i18n(`confirm.success.${action}`, intl), + }) + ) + + refetch() + }) + .catch(console.error) + } + } + + const handleBatchSelect = () => setBatch(isBatchEmpty ? { [schedules![0].uid!]: true } : {}) + + const handleBatchSelectAll = () => + setBatch( + batchLength <= schedules!.length + ? schedules!.reduce>((acc, d) => { + acc[d.uid!] = true + + return acc + }, {}) + : {} + ) + + const handleBatchDelete = () => + handleSelect({ + title: i18n('schedules.deleteMulti', intl), + description: i18n('schedules.deleteDesc', intl), + handle: handleAction('archiveMulti'), + }) + + const onCheckboxChange = (uuid: uuid) => (e: React.ChangeEvent) => { + setBatch({ + ...batch, + [uuid]: e.target.checked, + }) + } + + const Row = ({ data, index, style }: RWListChildComponentProps) => ( + + {!isBatchEmpty && ( + + )} + + + + + ) + + return ( + <> + + + + {!isBatchEmpty && ( + <> + + + + )} + + + {schedules && + schedules.length > 0 && + Object.entries(_.groupBy(schedules, 'kind')).map(([type, schedulesByType]) => ( + + {transByKind(type as any)} + 3 ? 300 : schedulesByType.length * 70} + itemCount={schedulesByType.length} + itemSize={70} + itemData={schedulesByType} + > + {Row} + + + ))} + + {!loading && schedules?.length === 0 && ( + + {i18n('schedules.notFound')} + + )} + + {loading && } + + ) +} + +export default Schedules diff --git a/ui/app/src/pages/Settings/Token.tsx b/ui/app/src/pages/Settings/Token.tsx new file mode 100644 index 0000000000..c5a0e014fc --- /dev/null +++ b/ui/app/src/pages/Settings/Token.tsx @@ -0,0 +1,87 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import GoogleIcon from '@mui/icons-material/Google' +import { Box, Button } from '@mui/material' +import { resetAPIAuthentication } from 'api/interceptors' +import Cookies from 'js-cookie' +import _ from 'lodash' +import { useIntl } from 'react-intl' +import { useNavigate } from 'react-router-dom' + +import PaperTop from '@ui/mui-extends/esm/PaperTop' + +import { useStoreDispatch, useStoreSelector } from 'store' + +import { removeToken, setAuthOpen, setConfirm } from 'slices/globalStatus' + +import i18n from 'components/T' + +const Token = () => { + const navigate = useNavigate() + const intl = useIntl() + + const { tokens, tokenName } = useStoreSelector((state) => state.globalStatus) + const tokenDesc = + tokenName === 'gcp' ? ( + + {i18n('settings.addToken.gcp')} + + + ) : ( + tokenName + ': ' + _.truncate(tokens[0].token) + ) + const dispatch = useStoreDispatch() + + const handleRemoveToken = () => + dispatch( + setConfirm({ + title: i18n('common.logout', intl), + description: i18n('common.logoutDesc', intl), + handle: handleRemoveTokenConfirm, + }) + ) + + const handleRemoveTokenConfirm = () => { + if (tokenName === 'gcp') { + Cookies.remove('access_token') + Cookies.remove('refresh_token') + Cookies.remove('expiry') + } else { + resetAPIAuthentication() + dispatch(removeToken()) + dispatch(setAuthOpen(true)) + } + + navigate('/dashboard') + } + + return ( + + + + ) +} + +export default Token diff --git a/ui/app/src/pages/Settings/index.tsx b/ui/app/src/pages/Settings/index.tsx new file mode 100644 index 0000000000..6ca130ba73 --- /dev/null +++ b/ui/app/src/pages/Settings/index.tsx @@ -0,0 +1,165 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { Box, Chip, Grow, MenuItem, Typography } from '@mui/material' +import type { SelectChangeEvent } from '@mui/material' +import { Stale } from 'api/queryUtils' +import messages from 'i18n/messages' +import { useGetCommonConfig } from 'openapi' + +import Checkbox from '@ui/mui-extends/esm/Checkbox' +import PaperTop from '@ui/mui-extends/esm/PaperTop' +import SelectField from '@ui/mui-extends/esm/SelectField' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch, useStoreSelector } from 'store' + +import { + setDebugMode, + setEnableKubeSystemNS, + setLang, + setTheme, + setUseNewPhysicalMachine, + setUseNextWorkflowInterface, +} from 'slices/settings' + +import { T } from 'components/T' + +import logoWhite from 'images/logo-white.svg' +import logo from 'images/logo.svg' + +import Token from './Token' + +const Settings = () => { + const state = useStoreSelector((state) => state) + const { tokenName } = state.globalStatus + const { debugMode, enableKubeSystemNS, useNewPhysicalMachine, useNextWorkflowInterface, theme, lang } = state.settings + const dispatch = useStoreDispatch() + + const { data: config } = useGetCommonConfig({ + query: { + enabled: false, + staleTime: Stale.DAY, + }, + }) + + const handleChangeDebugMode = () => dispatch(setDebugMode(!debugMode)) + const handleChangeEnableKubeSystemNS = () => dispatch(setEnableKubeSystemNS(!enableKubeSystemNS)) + const handleChangeUseNewPhysicalMachine = () => dispatch(setUseNewPhysicalMachine(!useNewPhysicalMachine)) + const handleChangeUseNextWorkflowInterface = () => dispatch(setUseNextWorkflowInterface(!useNextWorkflowInterface)) + const handleChangeTheme = (e: SelectChangeEvent) => dispatch(setTheme(e.target.value)) + const handleChangeLang = (e: SelectChangeEvent) => dispatch(setLang(e.target.value)) + + return ( + +
    + + } h1 divider /> + {config?.security_mode && tokenName && } + } /> + } + helperText={} + checked={debugMode} + onChange={handleChangeDebugMode} + /> + } + helperText={} + checked={enableKubeSystemNS} + onChange={handleChangeEnableKubeSystemNS} + /> + + + + + + + } + helperText={} + checked={useNewPhysicalMachine} + onChange={handleChangeUseNewPhysicalMachine} + /> + } /> + + + + + + + } + helperText={ + + + + } + checked={useNextWorkflowInterface} + onChange={handleChangeUseNextWorkflowInterface} + /> + } /> + } + helperText={} + value={theme} + onChange={handleChangeTheme} + sx={{ width: 300 }} + > + + + + + + + + + + + + } /> + } + helperText={} + value={lang} + onChange={handleChangeLang} + sx={{ width: 300 }} + > + {Object.keys(messages).map((lang) => ( + + + + + + ))} + + + } /> + + Chaos Mesh + + Git Version: {config?.version} + + + +
    +
    + ) +} + +export default Settings diff --git a/ui/app/src/pages/Workflows/Single.tsx b/ui/app/src/pages/Workflows/Single.tsx new file mode 100644 index 0000000000..854968f0a6 --- /dev/null +++ b/ui/app/src/pages/Workflows/Single.tsx @@ -0,0 +1,247 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import loadable from '@loadable/component' +import ArchiveOutlinedIcon from '@mui/icons-material/ArchiveOutlined' +import { Box, Button, Grid, Grow, Modal, useTheme } from '@mui/material' +import { makeStyles } from '@mui/styles' +import { EventHandler } from 'cytoscape' +import yaml from 'js-yaml' +import { useDeleteWorkflowsUid, useGetEventsWorkflowUid, useGetWorkflowsUid } from 'openapi' +import { CoreWorkflowDetail } from 'openapi/index.schemas' +import { useEffect, useRef, useState } from 'react' +import { useIntl } from 'react-intl' +import { useNavigate, useParams } from 'react-router-dom' + +import Paper from '@ui/mui-extends/esm/Paper' +import PaperTop from '@ui/mui-extends/esm/PaperTop' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch } from 'store' + +import { Confirm, setAlert, setConfirm } from 'slices/globalStatus' + +import EventsTimeline from 'components/EventsTimeline' +import Helmet from 'components/Helmet' +import NodeConfiguration from 'components/ObjectConfiguration/Node' +import i18n from 'components/T' + +import { constructWorkflowTopology } from 'lib/cytoscape' + +const YAMLEditor = loadable(() => import('components/YAMLEditor')) + +const useStyles = makeStyles((theme) => ({ + root: {}, + configPaper: { + position: 'absolute', + top: '50%', + left: '50%', + width: '75vw', + height: '90vh', + padding: 0, + transform: 'translate(-50%, -50%)', + [theme.breakpoints.down('lg')]: { + width: '90vw', + }, + }, +})) + +function transformWorkflow(data: CoreWorkflowDetail) { + // TODO: remove noise in API + data.kube_object!.metadata!.annotations && + delete data.kube_object!.metadata!.annotations['kubectl.kubernetes.io/last-applied-configuration'] + + return data +} + +const Single = () => { + const classes = useStyles() + const intl = useIntl() + const navigate = useNavigate() + const theme = useTheme() + const { uuid } = useParams() + + const dispatch = useStoreDispatch() + + const [data, setData] = useState() + const [selected, setSelected] = useState<'workflow' | 'node'>('workflow') + const [configOpen, setConfigOpen] = useState(false) + const topologyRef = useRef(null) + + const { data: workflow } = useGetWorkflowsUid(uuid!, { + query: { + select: transformWorkflow, + }, + }) + const modalTitle = selected === 'workflow' ? workflow?.name : selected === 'node' ? data.name : '' + const { data: events } = useGetEventsWorkflowUid(uuid!, { limit: 999 }) + const { mutateAsync: deleteWorkflows } = useDeleteWorkflowsUid() + + useEffect(() => { + if (workflow) { + const topology = topologyRef.current! + + if (typeof topology === 'function') { + topology(workflow) + + return + } + + const { updateElements } = constructWorkflowTopology( + topologyRef.current!, + workflow as any, + theme, + handleNodeClick + ) + + topologyRef.current = updateElements + } + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [workflow]) + + const onModalOpen = () => setConfigOpen(true) + const onModalClose = () => setConfigOpen(false) + + const handleSelect = (selected: Confirm) => () => dispatch(setConfirm(selected)) + + const handleAction = (action: string) => () => { + let actionFunc + + switch (action) { + case 'archive': + actionFunc = deleteWorkflows + + break + default: + break + } + + if (actionFunc) { + actionFunc({ uid: uuid! }) + .then(() => { + dispatch( + setAlert({ + type: 'success', + message: i18n(`confirm.success.${action}`, intl), + }) + ) + + if (action === 'archive') { + navigate('/workflows') + } + }) + .catch(console.error) + } + } + + const handleNodeClick: EventHandler = (e) => { + const node = e.target + const { template: nodeTemplate } = node.data() + const template = (workflow?.kube_object!.spec as any).templates.find((t: any) => t.name === nodeTemplate) + + setData(template) + setSelected('node') + + onModalOpen() + } + + return ( + <> + +
    + {workflow && } + + + + + + +
    + + + + + + + + {events && } + + + + + + {workflow && ( + + + + + + + )} + + + + +
    + + + +
    + + {workflow && configOpen && ( + + + + {selected === 'node' && ( + + + + )} + + + + )} + +
    +
    + + ) +} + +export default Single diff --git a/ui/app/src/pages/Workflows/index.tsx b/ui/app/src/pages/Workflows/index.tsx new file mode 100644 index 0000000000..4f63c2bc72 --- /dev/null +++ b/ui/app/src/pages/Workflows/index.tsx @@ -0,0 +1,226 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import AddIcon from '@mui/icons-material/Add' +import RemoveCircleOutlineIcon from '@mui/icons-material/RemoveCircleOutline' +import ReplayIcon from '@mui/icons-material/Replay' +import { Box, Button, Grow, Typography } from '@mui/material' +import type { ButtonProps } from '@mui/material' +import type { GridColDef, GridRenderCellParams, GridRowParams } from '@mui/x-data-grid' +import { GridActionsCellItem } from '@mui/x-data-grid' +import _ from 'lodash' +import { getWorkflowsUid, useDeleteWorkflowsUid, useGetWorkflows, usePostWorkflows } from 'openapi' +import { CoreWorkflowMeta } from 'openapi/index.schemas' +import React, { useState } from 'react' +import { useIntl } from 'react-intl' +import { useNavigate } from 'react-router-dom' +import { v4 as uuidv4 } from 'uuid' + +import Loading from '@ui/mui-extends/esm/Loading' +import PaperTop from '@ui/mui-extends/esm/PaperTop' +import Space from '@ui/mui-extends/esm/Space' + +import { useStoreDispatch, useStoreSelector } from 'store' + +import { setAlert, setConfirm } from 'slices/globalStatus' + +import DataTable from 'components/DataTable' +import NotFound from 'components/NotFound' +import StatusLabel from 'components/StatusLabel' +import i18n, { T } from 'components/T' + +import { comparator, format, toRelative } from 'lib/luxon' + +function transformWorkflows(data: CoreWorkflowMeta[]) { + return data + .map((d) => ({ + ...d, + time: d.status === 'finished' ? 'Ended at: ' + format(d.end_time!) : 'Created at: ' + toRelative(d.created_at!), + })) + .sort((a, b) => comparator(b.created_at!, a.created_at!)) +} + +const Workflows = () => { + const navigate = useNavigate() + const intl = useIntl() + + const [loading, setLoading] = useState(true) + + const { useNextWorkflowInterface } = useStoreSelector((state) => state.settings) + const dispatch = useStoreDispatch() + + const { data: workflows, refetch } = useGetWorkflows(undefined, { + query: { + select: transformWorkflows, + onSettled() { + setLoading(false) + }, + }, + }) + const { mutateAsync: deleteWorkflows } = useDeleteWorkflowsUid() + const { mutateAsync: createWorkflows } = usePostWorkflows() + + const NewWorkflow = (props: ButtonProps) => ( + + ) + + const handleAction = (action: string, uuid: uuid) => () => { + let actionFunc + + switch (action) { + case 'archive': + actionFunc = deleteWorkflows + + break + default: + break + } + + if (actionFunc) { + actionFunc({ uid: uuid }) + .then(() => { + dispatch( + setAlert({ + type: 'success', + message: , + }) + ) + + refetch() + }) + .catch(console.error) + } + } + + const handleDelete = + ({ uid, name }: CoreWorkflowMeta) => + (e: React.SyntheticEvent) => { + e.stopPropagation() + + dispatch( + setConfirm({ + title: `${i18n('archives.single', intl)} ${name}`, + description: , + handle: handleAction('archive', uid!), + }) + ) + } + + const handleReRun = (uid: uuid) => async (e: React.SyntheticEvent) => { + e.stopPropagation() + + const { name, kube_object } = await getWorkflowsUid(uid) + + dispatch( + setConfirm({ + title: `Re-run ${name}`, + description: 'This will re-create a new workflow with the same configuration.', + handle: () => { + createWorkflows({ + data: { + apiVersion: 'chaos-mesh.org/v1alpha1', + kind: 'Workflow', + metadata: { + ...kube_object!.metadata, + name: `${name}-${uuidv4()}`, + }, + spec: kube_object!.spec, + } as any, + }) + .then(() => { + dispatch( + setAlert({ + type: 'success', + message: , + }) + ) + + refetch() + }) + .catch(console.error) + }, + }) + ) + } + + const jumpToSingleWorkflow = ({ row }: GridRowParams) => navigate(`/workflows/${row.uid}`) + + const columns: GridColDef[] = [ + { + field: 'status', + headerName: 'Status', + width: 150, + renderCell: ({ value }: GridRenderCellParams) => , + }, + { + field: 'name', + headerName: 'Name', + renderCell: ({ value }: GridRenderCellParams) => {_.truncate(value)}, + }, + { field: 'time', headerName: 'Time' }, + { + field: 'actions', + type: 'actions', + headerName: 'Operations', + align: 'left', + width: 150, + getActions: ({ row }: GridRowParams) => [ + } label="Archive" onClick={handleDelete(row)} />, + ...(row.status === 'finished' + ? [} label="Re-run" onClick={handleReRun(row.uid)} />] + : []), + ], + }, + ] + + return ( + <> + +
    + {workflows && workflows.length > 0 ? ( + + + + + + + + + ) : ( + + + + + + + )} +
    +
    + + {loading && } + + ) +} + +export default Workflows diff --git a/ui/app/src/react-app-env.d.ts b/ui/app/src/react-app-env.d.ts new file mode 100644 index 0000000000..1f4e0ee8e0 --- /dev/null +++ b/ui/app/src/react-app-env.d.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +/// diff --git a/ui/app/src/reactQueryClient.ts b/ui/app/src/reactQueryClient.ts new file mode 100644 index 0000000000..5a8d64efda --- /dev/null +++ b/ui/app/src/reactQueryClient.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2023 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { QueryClient } from '@tanstack/react-query' + +const queryClient = new QueryClient() + +export default queryClient diff --git a/ui/app/src/reducers/index.ts b/ui/app/src/reducers/index.ts new file mode 100644 index 0000000000..2dc5864d7c --- /dev/null +++ b/ui/app/src/reducers/index.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { combineReducers } from 'redux' + +import experiments from 'slices/experiments' +import globalStatus from 'slices/globalStatus' +import settings from 'slices/settings' +import workflows from 'slices/workflows' + +export default combineReducers({ + settings, + globalStatus, + experiments, + workflows, +}) diff --git a/ui/app/src/router.tsx b/ui/app/src/router.tsx new file mode 100644 index 0000000000..fbe681a6f1 --- /dev/null +++ b/ui/app/src/router.tsx @@ -0,0 +1,109 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import Archives from 'pages/Archives' +import Archive from 'pages/Archives/Single' +import Dashboard from 'pages/Dashboard' +import Events from 'pages/Events' +import Experiments from 'pages/Experiments' +import NewExperiment from 'pages/Experiments/New' +import Experiment from 'pages/Experiments/Single' +import Schedules from 'pages/Schedules' +import NewSchedule from 'pages/Schedules/New' +import Schedule from 'pages/Schedules/Single' +import Settings from 'pages/Settings' +import Workflows from 'pages/Workflows' +import Workflow from 'pages/Workflows/Single' +import { Navigate, createHashRouter } from 'react-router-dom' + +import NewWorkflow from 'components/NewWorkflow' +import NewWorkflowNext from 'components/NewWorkflowNext' +import TopContainer from 'components/TopContainer' + +const router = createHashRouter([ + { + path: '/', + Component: TopContainer, + children: [ + { + index: true, + element: , + }, + { + path: 'dashboard', + Component: Dashboard, + }, + { + path: 'workflows/new', + Component: NewWorkflow, + }, + { + path: 'workflows/new/next', + Component: NewWorkflowNext, + }, + { + path: 'workflows', + Component: Workflows, + }, + { + path: 'workflows/:uuid', + Component: Workflow, + }, + { + path: 'schedules/new', + Component: NewSchedule, + }, + { + path: 'schedules', + Component: Schedules, + }, + { + path: 'schedules/:uuid', + Component: Schedule, + }, + { + path: 'experiments/new', + Component: NewExperiment, + }, + { + path: 'experiments', + Component: Experiments, + }, + { + path: 'experiments/:uuid', + Component: Experiment, + }, + { + path: 'events', + Component: Events, + }, + { + path: 'archives', + Component: Archives, + }, + { + path: 'archives/:uuid', + Component: Archive, + }, + { + path: 'settings', + Component: Settings, + }, + ], + }, +]) + +export default router diff --git a/ui/src/setupProxy.js b/ui/app/src/setupProxy.js similarity index 100% rename from ui/src/setupProxy.js rename to ui/app/src/setupProxy.js diff --git a/ui/app/src/setupTests.ts b/ui/app/src/setupTests.ts new file mode 100644 index 0000000000..6dd8f7dc68 --- /dev/null +++ b/ui/app/src/setupTests.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom' + +import { server } from './__mocks__/server.js' + +// Establish API mocking before all tests. +beforeAll(() => server.listen()) +// Reset any request handlers that we may add during the tests, +// so they don't affect other tests. +afterEach(() => server.resetHandlers()) +// Clean up after the tests are finished. +afterAll(() => server.close()) diff --git a/ui/app/src/slices/experiments.ts b/ui/app/src/slices/experiments.ts new file mode 100644 index 0000000000..de6a1e692f --- /dev/null +++ b/ui/app/src/slices/experiments.ts @@ -0,0 +1,94 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { PayloadAction, createSlice } from '@reduxjs/toolkit' + +import { Kind } from 'components/NewExperimentNext/data/types' + +export type Env = 'k8s' | 'physic' + +const initialState: { + fromExternal: boolean + step1: boolean + step2: boolean + env: Env + kindAction: [Kind | '', string] + spec: any + basic: any +} = { + fromExternal: false, + step1: false, + step2: false, + env: 'k8s', + kindAction: ['', ''], + spec: {}, + basic: {}, +} + +const experimentsSlice = createSlice({ + name: 'experiments', + initialState, + reducers: { + setStep1(state, action: PayloadAction) { + state.step1 = action.payload + }, + setStep2(state, action: PayloadAction) { + state.step2 = action.payload + }, + setEnv(state, action: PayloadAction) { + state.env = action.payload + }, + setKindAction(state, action) { + state.kindAction = action.payload + state.spec = {} + }, + setSpec(state, action) { + state.spec = action.payload + }, + setBasic(state, action) { + state.basic = action.payload + }, + setExternalExperiment(state, action: PayloadAction) { + const { kindAction, spec, basic } = action.payload + + state.fromExternal = true + state.kindAction = kindAction + state.spec = spec + state.basic = basic + }, + resetNewExperiment(state) { + state.fromExternal = false + state.step1 = false + state.step2 = false + state.kindAction = ['', ''] + state.spec = {} + state.basic = {} + }, + }, +}) + +export const { + setStep1, + setStep2, + setEnv, + setKindAction, + setSpec, + setBasic, + setExternalExperiment, + resetNewExperiment, +} = experimentsSlice.actions + +export default experimentsSlice.reducer diff --git a/ui/app/src/slices/globalStatus.ts b/ui/app/src/slices/globalStatus.ts new file mode 100644 index 0000000000..75d8aede58 --- /dev/null +++ b/ui/app/src/slices/globalStatus.ts @@ -0,0 +1,126 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { PayloadAction, createSlice } from '@reduxjs/toolkit' +import React from 'react' + +import { TokenFormValues } from 'components/Token' + +import LS from 'lib/localStorage' + +export interface Alert { + type: 'success' | 'warning' | 'error' + message: React.ReactNode +} + +export interface Confirm { + title: string + description?: React.ReactNode + handle?: () => void + [key: string]: any +} + +const initialState: { + alert: Alert + alertOpen: boolean + confirm: Confirm + confirmOpen: boolean // control global confirm dialog + authOpen: boolean + namespace: string + tokens: TokenFormValues[] + tokenName: string +} = { + alert: { + type: 'success', + message: '', + }, + alertOpen: false, + confirm: { + title: '', + description: '', + }, + authOpen: false, + confirmOpen: false, + namespace: 'All', + tokens: [], + tokenName: '', +} + +const globalStatusSlice = createSlice({ + name: 'globalStatus', + initialState, + reducers: { + setAlert(state, action: PayloadAction) { + state.alert = action.payload + state.alertOpen = true + }, + setAlertOpen(state, action: PayloadAction) { + state.alertOpen = action.payload + }, + setConfirm(state, action: PayloadAction) { + state.confirm = action.payload + state.confirmOpen = true + }, + setConfirmOpen(state, action: PayloadAction) { + state.confirmOpen = action.payload + }, + setAuthOpen(state, action: PayloadAction) { + state.authOpen = action.payload + }, + setNameSpace(state, action: PayloadAction) { + const ns = action.payload + + state.namespace = ns + + LS.set('global-namespace', ns) + }, + setTokens(state, action: PayloadAction) { + const tokens = action.payload + + state.tokens = tokens + + LS.set('token', JSON.stringify(tokens)) + }, + setTokenName(state, action: PayloadAction) { + const name = action.payload + + state.tokenName = name + + LS.set('token-name', name) + }, + removeToken(state) { + state.tokenName = '' + state.tokens = [] + + LS.remove('token') + LS.remove('token-name') + }, + }, +}) + +export const { + setAlert, + setAlertOpen, + setConfirm, + setConfirmOpen, + setAuthOpen, + setNameSpace, + setTokens, + setTokenName, + removeToken, +} = globalStatusSlice.actions + +export default globalStatusSlice.reducer diff --git a/ui/app/src/slices/settings.ts b/ui/app/src/slices/settings.ts new file mode 100644 index 0000000000..e107becfc1 --- /dev/null +++ b/ui/app/src/slices/settings.ts @@ -0,0 +1,78 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { createSlice } from '@reduxjs/toolkit' + +import LS from 'lib/localStorage' + +export type Theme = 'light' | 'dark' + +const initialState = { + theme: (LS.get('theme') || 'light') as Theme, + lang: LS.get('lang') || 'en', + debugMode: LS.get('debug-mode') === 'true', + enableKubeSystemNS: LS.get('enable-kube-system-ns') === 'true', + useNewPhysicalMachine: LS.get('use-new-physical-machine') === 'true', + useNextWorkflowInterface: (LS.get('use-next-workflow-interface') || 'true') === 'true', +} + +const settingsSlice = createSlice({ + name: 'settings', + initialState, + reducers: { + setTheme(state, action) { + state.theme = action.payload + + LS.set('theme', action.payload) + }, + setLang(state, action) { + state.lang = action.payload + + LS.set('lang', action.payload) + }, + setDebugMode(state, action) { + state.debugMode = action.payload + + LS.set('debug-mode', action.payload) + }, + setEnableKubeSystemNS(state, action) { + state.enableKubeSystemNS = action.payload + + LS.set('enable-kube-system-ns', action.payload) + }, + setUseNewPhysicalMachine(state, action) { + state.useNewPhysicalMachine = action.payload + + LS.set('use-new-physical-machine', action.payload) + }, + setUseNextWorkflowInterface(state, action) { + state.useNextWorkflowInterface = action.payload + + LS.set('use-next-workflow-interface', action.payload) + }, + }, +}) + +export const { + setTheme, + setLang, + setDebugMode, + setEnableKubeSystemNS, + setUseNewPhysicalMachine, + setUseNextWorkflowInterface, +} = settingsSlice.actions + +export default settingsSlice.reducer diff --git a/ui/app/src/slices/workflows.ts b/ui/app/src/slices/workflows.ts new file mode 100644 index 0000000000..bf387975fb --- /dev/null +++ b/ui/app/src/slices/workflows.ts @@ -0,0 +1,140 @@ +/* + * Copyright 2021 Chaos Mesh Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { PayloadAction, createSlice } from '@reduxjs/toolkit' + +import LS from 'lib/localStorage' + +export type TemplateExperiment = any + +export interface Branch { + target: string + expression: string +} + +export interface TemplateCustom { + container: { + name: string + image: string + command: string[] + } + conditionalBranches: Branch[] +} + +export enum TemplateType { + Single = 'single', + Serial = 'serial', + Parallel = 'parallel', + Suspend = 'suspend', + Custom = 'custom', +} + +export interface Template { + index?: number + type: TemplateType + name: string + deadline?: string + experiment?: TemplateExperiment + children?: Template[] + custom?: TemplateCustom +} + +// TODO: remove above code +export type NodeExperiment = any + +export interface WorkflowNode { + id: uuid + experiment?: NodeExperiment +} + +export interface RecentUse { + kind: string + act?: string +} + +const initialState: { + nodes: Record + recentUse: RecentUse[] + templates: Template[] +} = { + nodes: {}, + recentUse: [], + templates: [], +} + +const workflowSlice = createSlice({ + name: 'workflows', + initialState, + reducers: { + importNodes(state, action: PayloadAction>) { + state.nodes = action.payload + }, + updateWorkflowNode(state, action) { + const payload = action.payload + + state.nodes[payload.name] = payload + }, + removeWorkflowNode(state, action: PayloadAction) { + delete state.nodes[action.payload] + }, + loadRecentlyUsedExperiments(state) { + state.recentUse = LS.getObj('new-workflow-recently-used-experiments') + }, + setRecentlyUsedExperiments(state, action: PayloadAction) { + const exp = action.payload + + state.recentUse = [...state.recentUse, exp] + + LS.setObj('new-workflow-recently-used-experiments', state.recentUse) + }, + resetWorkflow(state) { + state.nodes = {} + // TODO: remove below code + state.templates = [] + }, + // TODO: remove below code + setTemplate(state, action: PayloadAction